PHP 8.0 was released on November 26, 2020, introducing the largest set of language improvements since PHP 7.0. For WordPress developers, it brought features that reduce boilerplate, improve code clarity, and eliminate whole categories of bugs: named arguments remove the need to remember parameter order, the match expression replaces verbose switch blocks and returns a value, union types let you declare that a parameter or return accepts multiple types, the nullsafe operator ?-> eliminates nested null checks, and constructor property promotion cuts class boilerplate in half. WordPress itself became compatible with PHP 8.0 starting with WordPress 5.6 (December 2020). This article shows practical before/after rewrites of common WordPress plugin patterns, demonstrating where each PHP 8.0 feature provides the most value in day-to-day WordPress development.
Problem: Common WordPress plugin code written in PHP 7.x is verbose — nested null checks, positional arguments to functions with many parameters, repeated switch blocks that don't return values cleanly. PHP 8.0 features solve each of these.
Solution: Adopt PHP 8.0 features where they improve clarity: named arguments for WordPress functions with many optional parameters, match for status-to-label mappings, ?-> for optional object chains, and constructor promotion for dependency-injected plugin classes.
<?php
// ── Named arguments — no more counting parameter positions ─────────────
// PHP 7.x
register_post_type( 'movie', [ 'public' => true, 'label' => 'Movies' ] );
array_slice( $array, 0, 5, true );
// PHP 8.0 — parameters by name, order doesn't matter
register_post_type( post_type: 'movie', args: [ 'public' => true, 'label' => 'Movies' ] );
array_slice( array: $array, offset: 0, length: 5, preserve_keys: true );
// ── match expression — replaces switch, returns a value ────────────────
// PHP 7.x
function get_post_status_label( string $status ): string {
switch ( $status ) {
case 'publish': return __( 'Published', 'textdomain' );
case 'draft': return __( 'Draft', 'textdomain' );
case 'pending': return __( 'Pending Review', 'textdomain' );
default: return __( 'Unknown', 'textdomain' );
}
}
// PHP 8.0 — strict (===) comparison, no fall-through, returns value
function get_post_status_label( string $status ): string {
return match ( $status ) {
'publish' => __( 'Published', 'textdomain' ),
'draft' => __( 'Draft', 'textdomain' ),
'pending' => __( 'Pending Review', 'textdomain' ),
default => __( 'Unknown', 'textdomain' ),
};
}
// ── Nullsafe operator — eliminates nested null checks ─────────────────
// PHP 7.x
$user = get_userdata( get_current_user_id() );
$email = $user ? $user->user_email : null;
// PHP 8.0
$email = get_userdata( get_current_user_id() )?->user_email;
// ── Union types — accept multiple types in one declaration ─────────────
// PHP 8.0
function update_meta( int $post_id, string $key, int|float|string $value ): bool {
return (bool) update_post_meta( $post_id, $key, $value );
}
// ── Constructor property promotion ────────────────────────────────────
// PHP 7.x
class Post_Repository {
private wpdb $wpdb;
private string $table;
public function __construct( wpdb $wpdb, string $table ) {
$this->wpdb = $wpdb;
$this->table = $table;
}
}
// PHP 8.0 — same result in one line per property
class Post_Repository {
public function __construct(
private wpdb $wpdb,
private string $table
) {}
}
NOTE: PHP 8.0 also introduced breaking changes that affect some older WordPress plugins: the @ error-suppression operator no longer silences fatal errors, implicit conversions between incompatible types now throw TypeError, and many built-in functions became stricter about argument types. Before deploying to PHP 8.0 on a production WordPress site, run the PHP Compatibility Checker plugin to scan installed plugins for known incompatibilities. WordPress core has been compatible since WP 5.6, but third-party plugins and themes require individual verification.