php升级8.1后wordpress主题/插件常见报错及处理方案

猿代码 · 2023-04-17 · 224 人浏览

趁着周末,将网站的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/)

升级 wp wordpress php
京ICP备2023019113号-1 ◎ Theme by Jasmine