趁着周末,将网站的php版本升级到了8.1,但是由于wordpress插件都比较陈旧,没有及时更新。所以出现了不少的错误。通过查阅网络资料,结合实际情况,列出遇到的如下三种情况。
1、Fatal error: Uncaught Error: Call to undefined function create_function()
由于在wordpress中,一些插件、主题使用了create_function()函数。这个函数在 PHP 7.2 版本中就已经被废弃并且在 PHP 8.0 中被移除。你可以使用匿名函数来代替 create_function()
。例如,如果你原来的代码是这样的:
$myFunction = create_function('$arg1, $arg2', 'return $arg1 + $arg2;');
$result = $myFunction(1, 2);
可以将其修改为:
$myFunction = function ($arg1, $arg2) { return $arg1 + $arg2; };
$result = $myFunction(1, 2);
再比如原来代码如果是:
add_action('widgets_init', create_function('', 'return register_widget("imsail_comment");'));
可以将其修改为:
add_action('widgets_init', function() {
return register_widget("imsail_comment");
});
2、Warning: Only the first byte will be assigned to the string offset in /wp-includes/class.wp-scripts.php on line 492 或者 Fatal error: Uncaught TypeError: WP_Scripts::localize(): Argument #3 ($l10n) must be of type array, string given, called in /wp-includes/functions.wp-scripts.php on line 221 and defined in /wp-includes/class-wp-scripts.php:483
这个警告指向的是wp-includes/class.wp-scripts.php文件,这是WordPress的一个核心文件。可能一开始会以为是WordPress核心文件的错误,但WordPress在5.6版本就已经宣布全面支持PHP 8了,所以这应该是主题或插件的问题。
要想解决这个问题,我们需要把报错的相关代码拿出来看:
$l10n[ $key ] = html_entity_decode( (string) $value, ENT_QUOTES, 'UTF-8' );
上述代码,大家肯定和笔者一样看的莫名奇妙,感觉不到什么问题。但是如果结合它所在的function
:
public function localize( $handle, $object_name, $l10n )
大家是不是猜到了,很可能是在使用wp_localize_script
这个function
时出现了问题,而问题的关键就在于参数$l10n
。
我们不妨从官网资料中看一下$l10n
到底是个什么东西:
$l10n (array) (Required) The data itself. The data can be either a single or multi-dimensional array.
原来,问题在于参数$l10n
在函数wp_localize_script
中接受到的应该是一个数组,如果没有接受到数组,只是接受到了字符串等非数组的值时,由于PHP 8的新特性,会报出一个警告。
因此,在使用函数wp_localize_script
时,一定要确保第三个参数是一个数组类型。
wp_localize_script( string $handle, string $object_name, array $l10n )
那么,这个报错该怎么解决呢?
首先查找自己的主题或插件的代码中,对wp_localize_script()
函数的调用是否正确。可以通过全局搜索“localize“ 这个单词进行检索。比如我找到的下面这个代码:
function ews_scripts(){
wp_enqueue_script('jquery');
wp_enqueue_script( 'ews', EWS_URL.'/assets/ews.js', array(), EWS_VERSION ,true);
wp_localize_script( 'ews', 'ews_ajax_url', EWS_ADMIN_URL . "admin-ajax.php");
}
很明显,最后一句在调用WP_Scripts::localize()
方法时,第三个参数:EWS_ADMIN_URL . "admin-ajax.php",是一个字符串,并非是数组类型。这就导致了Argument #3 ($l10n) must be of type array这个错误提示。
解决这问题其实相对简单,只需要将传入的第三个字符串类型的元素转化成数组类型的即可。
...
$new_array = array(EWS_ADMIN_URL . "admin-ajax.php");
wp_localize_script( 'ews', 'ews_ajax_url', $new_array);
...
另外,还有一种解决办法,是直接修改wp的核心文件class.wp-scripts.php中的localize方法:
$l10n[ $key ] = html_entity_decode( (string) $value, ENT_QUOTES, 'UTF-8' );
修改为:
$str = $l10n[$key];
$str_replace= html_entity_decode( (string) $value, ENT_QUOTES, 'UTF-8' );
substr_replace($str, $str_replace, 0, strlen($str_replace));
但是这个方法只能算是临时方案,wp一旦升级,文件就会被覆盖。所以,还是采用第一种”治本“之策为好。
3、Deprecated: Required parameter $xxx follows optional parameter $yyy in… 或者 Optional parameter $aaa declared before required parameter $bbb is implicitly treated as a required parameter
这类报错在升级PHP 8后也很常见,多是来自一些主题或者插件。虽然这类错误早就存在多年,但一直未受到太多重视,最终在PHP 8的时候变成了Deprecated报错。这个错误的原因是:将可选参数 $aaa 放在必需参数 $bbb 之前会被视为必需参数。
在编程中,参数可以分为强制参数和可选参数。强制参数是在函数或方法的定义中指定的必须要传入的参数,一般不会设置默认值,通常,这些参数在函数或方法的定义中需要设置在前面;而可选参数是在函数或方法的定义中指定的不是必须要传入的参数,一般来说,可选参数通常出现在函数或方法的定义中的最后,并且具有默认值,这意味着如果不传入参数,函数或方法将使用默认值作为参数。
以下是出现错误的代码:
function xxxxx( $avatar, $id_or_email, $size=30, $default, $alt )
根据上述分析,错误的点就在$size=30
这个参数。由于PHP规定,在可选参数中,若有默认值的参数不在最后一个,将会直接忽视它的默认值。所以这样写根本没必要,直接把默认值删除即可:
function xxxxx( $avatar, $id_or_email, $size, $default, $alt )
也许有人会担心是不是会导致一些问题,这大可不必。因为这个问题在PHP 8之前就存在,只是没有报错而已。这次PHP 8特地报了个Deprecated来解决这种不严谨的使用。所以,赶紧找找你的代码里还存在哪些历史遗留问题吧~
4、Deprecated: 函数 get_page_by_title 自版本 6.2.0 起已弃用!请使用WP_Query 替代。
这个报错是因为你的代码中使用了被弃用的函数 get_page_by_title()
,WordPress 从6.2.0版本开始弃用了这个函数。
为了解决这个问题,你需要使用 WP_Query
函数来替代 get_page_by_title()
。下面是一个例子:
$page_title = 'My Page Title';
$args = array(
'post_type' => 'page',
'post_title' => $page_title,
'post_status' => 'publish',
'posts_per_page' => 1
);
$query = new WP_Query($args);
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
// 在这里处理你需要的逻辑
}
} else {
// 如果没有找到对应的页面,则进行相应处理
}
wp_reset_postdata();
上面的代码会查询一个标题为 'My Page Title'
的页面,如果找到了,就会执行你需要的逻辑。如果没有找到,你可以在 else
分支中进行相应处理。最后,使用 wp_reset_postdata()
来重置查询的数据。
关于WP_Query的具体用法可以参考wp官方网站的开发文档 https://developer.wordpress.org/reference/classes/wp_query/
此外,升级php8.1后,除了wordpress程序,在其他的代码里也存在不少的报错信息。借助ChatGPT的力量,我也整理了一些错误及修复方法,有兴趣的小伙伴可以点此查看《服务器php版本升级到8.1后的报错修复》这篇文章。
参考资料:
PHP 8.0 部分错误的解决办法(https://www.idleleo.com/01/4929)
ChatGPT(https://chat.openai.com/)