We plan to launch a new service for customers soon where the goal is to improve the reliability of their sites. A part of that involves monitoring PHP for warning, errors, and exceptions, with the idea of picking up third party plugin errors before they become issues. To do that we wrote a plugin today that is in testing. The first error message it came up with was:
Error Number: 2
Error String: Trying to access array offset on value of type bool
Error File: /var/www/html/wp-content/plugins/elementor-pro/modules/dynamic-tags/tags/post-featured-image.php
Error Line: 39
Error Context:
This is a warning, so it doesn’t have any functional effect on Elementor. But still, we took a look. Elementor is great but this issue has been around for more than 6 months. We found the following code:
public function get_value( array $options = [] ) {
$thumbnail_id = get_post_thumbnail_id();
if ( $thumbnail_id ) {
$image_data = [
'id' => $thumbnail_id,
'url' => wp_get_attachment_image_src( $thumbnail_id, 'full' )[0],
];
} else {
$image_data = $this->get_settings( 'fallback' );
}
return $image_data;
}
Therein sits the code issue. Whilst the code takes care of the possibility of the wordpress function get_post_thumbnail_id returning false, it doesn’t do the same for wp_get_attachment_image_src . Further, it seems that in practice wp_get_attachment_image_src may return an empty array, which wouldn’t have an offset of 0.
Oddly, you can pass some options into this function, but they don’t have any effect. Our presumption is that’s a structural requirement where similar functions in other classes may take options. So we left that untouched.
Our solution is:
public function get_value( array $options = [] ) {
$thumbnail_id = get_post_thumbnail_id();
if ( $thumbnail_id ) {
$image_src = wp_get_attachment_image_src( $thumbnail_id, 'full' );
if ( !is_array($image_src) || $image_src === false) {
$fallback = $this->get_settings( 'fallback' );
$thumbnail_id = $fallback['id'];
$image_src = [ $fallback['url'] ];
}
$image_data = [
'id' => $thumbnail_id,
'url' => $image_src[0],
];
} else {
$image_data = $this->get_settings( 'fallback' );
}
return $image_data;
}
The observant will, of course, notice that this is a fair bit longer than the original and, indeed, longer than a solution to this could be. This extra length is due to a conscious choice to limit the number of calls to other functions by ensuring we only call them if necessary. At “The Byte Wizards” we put code speed and reliability over and above most other aspects, a little bit of extra length here seems like a good trade-off to us.
Whilst the free version of Elementor is on github, Elementor Pro doesn’t appear to be in a public github repository and there doesn’t appear to be a way to suggest bug fixes. The problem then is that, even though we’ve fixed the Elementor Pro code for our website, it’ll get overwritten by any update that Elementor releases.
We’d rather the originals got patched, but it did start us thinking. Perhaps a part of our service will be to apply patches on upgrades.