PHP 8.4 Features for WordPress Plugin Development

PHP 8.4 (released November 2024) introduced property hooks — getter/setter logic directly on class properties — asymmetric visibility for readonly-like properties, array_find() and related array functions, and the #[\Deprecated] attribute. These changes significantly affect how modern WordPress plugin architecture is written.

Problem: A WordPress plugin codebase is upgrading from PHP 8.2 to PHP 8.3 and it is unclear which deprecations need to be addressed, which new features are safe to adopt, and which patterns will generate warnings on strict hosting environments.

Solution: PHP 8.4 (for forward planning) deprecates implicit nullable parameters (function f(Type $x = null)) — replace with explicit Type|null unions. Use new features: property hooks for computed getters/setters, asymmetric visibility (public private(set)), and the #[\Override] attribute. Run vendor/bin/phpstan analyse --php-version=80400 to catch deprecations before they become errors.

The examples below demonstrate property hooks for lazy-loaded WordPress settings, asymmetric visibility for immutable-by-default objects, and the new array_find() function applied to post meta arrays.

api_key
            $key = get_option( 'myplugin_api_key', '' );
            if ( empty( $key ) ) {
                throw new \RuntimeException( 'API key not configured.' );
            }
            return $key;
        }
        set( string $value ) {
            // Hook runs when $this->api_key = 'new_value'
            if ( strlen( $value ) < 32 ) {
                throw new \InvalidArgumentException( 'API key must be at least 32 chars.' );
            }
            update_option( 'myplugin_api_key', sanitize_text_field( $value ) );
        }
    }

    // Virtual property — computed, never stored as a field
    public string $masked_key {
        get => substr( $this->api_key, 0, 4 ) . str_repeat( '*', 28 );
    }
}

$settings = new PluginSettings();
$settings->api_key = 'sk_live_abcdefghijklmnopqrstuvwxyz123456';
echo $settings->masked_key; // sk_l****************************

Asymmetric visibility and new array functions:

status = 'publish';  // allowed — inside the class
        wp_update_post( [ 'ID' => $this->id, 'post_status' => 'publish' ] );
    }
}

$post = new WP_Post_Wrapper( 42, 'draft', 'my-post' );
echo $post->status;       // 'draft' — OK, public read
// $post->status = 'publish';  // Fatal: private(set) — not allowed outside class
$post->publish();          // Updates DB and internal status

// PHP 8.4: array_find() — returns the first value matching a predicate
// (like Array.prototype.find() in JavaScript)
$posts = get_posts( [ 'numberposts' => 50 ] );

$featured = array_find( $posts, fn( WP_Post $p ) =>
    get_post_meta( $p->ID, '_is_featured', true ) === '1'
);
// Returns the WP_Post object or null if not found

// array_find_key() — returns the array key of the first match
$featured_key = array_find_key( $posts, fn( WP_Post $p ) => $p->post_author == 3 );

// array_any() — returns true if ANY element matches
$has_published = array_any( $posts, fn( WP_Post $p ) => $p->post_status === 'publish' );

// array_all() — returns true if ALL elements match
$all_published = array_all( $posts, fn( WP_Post $p ) => $p->post_status === 'publish' );

// PHP 8.4: #[Deprecated] attribute — triggers E_DEPRECATED with a message
class MyPlugin {
    #[\Deprecated( 'Use new_method() instead', since: '2.0' )]
    public function old_method(): void {
        $this->new_method();
    }

    public function new_method(): void {
        // modern implementation
    }
}

NOTE: PHP 8.4 also adds a native HTML5 parser via Dom\HTMLDocument::createFromString() that correctly handles modern HTML5 — use it instead of DOMDocument::loadHTML(), which silently mangles non-XHTML content. Run vendor/bin/phpstan analyse --php-version=80400 before upgrading to catch compatibility issues in your plugin.

Leave Comment

Your email address will not be published. Required fields are marked *