Co-Authors Plus Contributions: My Role in v4.1.0 Security and PCP Compliance

·

·

Co-Authors Plus contributions showing WordPress plugin code with security improvements

Introduction

Have you ever used a WordPress plugin and thought a feature could be better? That is the feeling that led me to make several Co-Authors Plus contributions to the v4.1.0 release. This popular plugin with over 20,000 active installations got security hardening, PCP compliance fixes, and block editor improvements in this update.

Co-Authors Plus lets you assign multiple authors and guest authors to your WordPress posts. It is maintained by Automattic and used by blogs and news sites worldwide. The v4.1.0 release was a maintenance-focused update that addressed critical Plugin Check (PCP) violations and added several quality-of-life fixes. I submitted over 10 pull requests that were merged into this release.

If you are new to WordPress development, check out my guide on how to get started with WordPress theme and plugin development.

Why Plugin Check (PCP) Compliance Matters for WordPress Plugins

The WordPress Plugin Check (PCP) tool helps plugin developers meet the required standards for the WordPress.org plugin directory. It runs static checks using PHP_CodeSniffer and dynamic checks by activating your plugin in a test environment. Since PCP became a stable release, more developers have adopted it as part of their workflow.

Without PCP compliance, plugins risk rejection from the WordPress directory. They can also expose users to security vulnerabilities and incompatibility with newer WordPress versions. My Co-Authors Plus contributions focused on fixing these issues before they caused problems for users.

The PCP tool was introduced to help the community maintain higher code quality. You can read the official announcement on Make WordPress Plugins.

The Merged Pull Requests Behind v4.1.0

The v4.1.0 release included several pull requests that I created to fix PCP violations and improve the plugin’s overall health. Here is a breakdown of each PR and what it changed.

PR #1260: Fixing a Fatal Error with get_current_screen()

The most critical fix in this release was guarding calls to get_current_screen() to prevent fatal errors. When plugins like Revisionary Pro triggered save_post events during the plugins_loaded phase, get_current_screen() had not been loaded yet. This crashed WordPress with a PHP fatal error.

You can see the full discussion on PR #1260 on GitHub.

Here is the code change I made. Before the fix, is_block_editor() called get_current_screen() directly with no guard:

// Before: Unconditional call that caused fatal errors
public function is_block_editor( $post = null ): bool {
    $screen = get_current_screen();
    // ...
}

After the fix, the method checks if the function exists first:

// After: Guarded with function_exists() check
public function is_block_editor( $post = null ): bool {
    if ( ! function_exists( 'get_current_screen' ) ) {
        return false;
    }
    $screen = get_current_screen();
    // ...
}

The same pattern was applied to is_post_type_enabled(). I also added a null check on the $screen object because get_current_screen() can return null on certain AJAX requests even when the function exists. Without this null check, PHP 8+ throws a TypeError inside method_exists().

This issue was originally reported in issue #1094.

PR #1284: ABSPATH Direct-Access Guards

Direct file access is a common security concern in WordPress plugins. If someone navigates to a PHP file inside a plugin folder by typing its URL in the browser, the file should stop executing immediately. The standard WordPress guard is:

You can check out PR #1284 on GitHub for the full changes.

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

I added this guard to 7 PHP files that were missing it, including co-authors-plus.php, template-tags.php, upgrade.php, and several integration files. One file needed special attention. The php/integrations/yoast.php file uses PHP namespaces, and the namespace declaration must come before the ABSPATH guard:

namespace CoAuthorsPlus\Integrations;

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

I caught this during CI and fixed it before merge.

PR #1285: Escaped Deprecated Hook Messages with esc_html__()

When WordPress deprecates a hook, the plugin shows a notice to developers. Before this PR, those notices used __() without escaping, which is a PCP violation.

See PR #1285 on GitHub for more details.

// Before: Unescaped output
_deprecated_hook( 'coauthors_auto_revoke_author_roles', '4.0', __( 'Use coauthors_assign_author_roles instead.', 'co-authors-plus' ) );

// After: Properly escaped with esc_html__()
_deprecated_hook( 'coauthors_auto_revoke_author_roles', '4.0', esc_html__( 'Use coauthors_assign_author_roles instead.', 'co-authors-plus' ) );

Both deprecated hook messages in the plugin were plain text with no HTML, so esc_html__() was the correct escaping function.

PR #1286: Translator Comments for sprintf __() in Block Files

Internationalization in WordPress requires careful handling of placeholder strings. When you use sprintf() with __(), translators need context to understand what each %s placeholder represents.

Check out PR #1286 on GitHub and the WordPress i18n developer documentation for more context.

// Before: No translator comment
sprintf(
    __( 'Posts by %s', 'co-authors-plus' ),
    $author_name
);

// After: With translator comment
sprintf(
    /* translators: %s: Author display name */
    __( 'Posts by %s', 'co-authors-plus' ),
    $author_name
);

I added these comments to three block files: block-coauthor-image.php, block-coauthor-name.php, and block-coauthor-avatar.php.

PR #1287: Migrating get_terms() to Single-Array Format

WordPress deprecated the two-parameter format for get_terms() in version 4.5. The old way passed the taxonomy as the first argument and an array of arguments as the second:

You can view PR #1287 on GitHub for the full diff.

// Before: Deprecated two-parameter format
$terms = get_terms( 'author', array( 'hide_empty' => false ) );

// After: Modern single-array format
$terms = get_terms( array(
    'taxonomy'   => 'author',
    'hide_empty' => false,
) );

I updated 4 calls across 3 files: class-wp-cli.php, class-coauthors-plus.php, and template-tags.php.

PR #1288: Input Sanitization and wp_trigger_error() Replacement

This PR added multiple security layers. First, it validated $_POST['coauthors'][0] before access to prevent undefined array key warnings.

See PR #1288 on GitHub for the full changes.

// Before: Direct access without validation
$coauthors = $_POST['coauthors'];

// After: Validated before access
if ( isset( $_POST['coauthors'][0] ) ) {
    $coauthors = $_POST['coauthors'];
}

Second, it replaced trigger_error() calls with wp_trigger_error(), which integrates better with WordPress error handling:

// Before: Using PHP's native trigger_error
trigger_error( esc_html__( 'Something went wrong', 'co-authors-plus' ), E_USER_WARNING );

// After: Using WordPress's wp_trigger_error
wp_trigger_error( 'coauthors_plus_log', esc_html__( 'Something went wrong', 'co-authors-plus' ), E_USER_WARNING );

Since Co-Authors Plus requires WordPress 6.4 or higher, using wp_trigger_error() was safe.

PR #1289: Remaining PCP Compliance Fixes

The final PCP-focused PR addressed the remaining violations. This was the largest PR in the sweep.

Check out PR #1289 on GitHub for the complete list of changes.

Here is what it covered:

Superglobal sanitization with wp_unslash():

// Before: Accessing superglobal directly
$page = $_GET['page'];

// After: Using wp_unslash before sanitization
$page = wp_unslash( $_GET['page'] );

Script loading with in_footer flag:

// Before: No footer flag
wp_enqueue_script( 'co-authors-plus-js', $url, array( 'jquery' ), CAP_VERSION );

// After: Footer flag set for better performance
wp_enqueue_script( 'co-authors-plus-js', $url, array( 'jquery' ), CAP_VERSION, array( 'in_footer' => true ) );

I also bumped the “Tested up to” version in the readme to WordPress 7.0.

Additional Improvements in v4.1.0

Beyond PCP compliance, I also contributed several functional improvements to the v4.1.0 release.

PR #1283: Entity Store Normalization for Block Editor

The block editor relies on entity records to manage state. PR #1283 normalized entity store registrations, ensuring consistent data handling in the block editor interface. You can see the details on PR #1283 on GitHub.

PR #1303: Author Feed Flag Preservation

Author feeds are important for sites that syndicate content. PR #1303 preserved the author feed flag correctly, ensuring RSS and other feeds respect author assignments. Check out PR #1303 on GitHub.

PR #1304: coauthors_plus_is_author_query Filter

This new filter gives developers more control over author queries. It allows plugins and themes to modify how Co-Authors Plus determines whether a query is an author query. View PR #1304 on GitHub.

PR #1305: Block Editor Combobox Fix

The block editor combobox component had a usability issue. PR #1305 fixed the combobox behavior, making the author selection experience smoother for content editors. See PR #1305 on GitHub.

If you want to see more of my open source work, check out my article on 8 WordPress open source contributions to MC4WP.

How These Changes Impact the Plugin’s 20,000+ Users

Every PR in this release had a direct impact on users. The get_current_screen() fix prevented fatal errors that could take down a site during content publishing. The security improvements protected sites from path traversal attacks. The internationalization fixes ensured translators could do their work accurately.

WordPress plugin development is not always about adding new features. Sometimes the most valuable work is maintenance and compliance. These Co-Authors Plus contributions ensure the plugin stays reliable, secure, and compatible with future WordPress versions.

The PCP Compliance Journey

Getting a plugin to pass all PCP checks requires attention to detail. Each violation has a specific fix. ABSPATH guards need to be placed in every PHP file. All output must go through escaping functions. Superglobals like $_POST and $_SERVER need wp_unslash() before access.

The WordPress Coding Standards on GitHub are a great resource for understanding these rules.

During this release cycle, I ran the PCP tool after each commit to catch new violations early. This workflow saved time and prevented regressions. I recommend every plugin developer add PCP to their local development environment.

If you want to learn PHP for WordPress development, I have a guide that covers exactly what you need: Learn PHP for WordPress plugin development.

What I Learned from This Release Cycle

Working on Co-Authors Plus taught me several valuable lessons.

Always guard WordPress admin functions. Functions like get_current_screen() are not available everywhere. A simple function_exists() check can prevent a production crash.

PCP compliance is not just about passing checks. Each rule exists for a reason. Understanding the why behind each rule makes you a better developer.

Small fixes add up. A translator comment might seem minor. But for someone translating the plugin into Bengali, my native language, that comment makes all the difference.

Open source is about collaboration. The maintainers at Automattic, especially Gary Jones, were responsive and supportive. They helped me refine my PRs and catch issues I missed.

To level up your PHP skills, check out my guide on PHP OOP composition explained simply.

Conclusion

My Co-Authors Plus contributions to the v4.1.0 release covered over 10 pull requests. The work ranged from critical security fixes to block editor improvements. While these changes may not be visible to end users, they make the plugin more secure, stable, and compliant with WordPress standards.

If you are a plugin developer, I encourage you to run PCP on your own projects. The process of fixing violations teaches you a lot about WordPress best practices. And if you use Co-Authors Plus, know that the v4.1.0 release has your back.

Download the plugin from the WordPress plugin directory or check out the full changelog on GitHub.

Have you contributed to a WordPress plugin recently? Share your experience in the comments below.

Meet the author

Faisal Ahammad

I’m a former Support Engineer at Saturday Drive Inc. (AKA Ninja Forms) and a GTE for the #bn_BD language. As an active contributor to WordPress, I have contributed to over 60 themes, plugins, and the WordPress core. I also run a small YouTube channel where I share my knowledge.

Leave a Reply

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

More from the blog


Recommended Topics


Popular Tags

formidable forms free stuff gravity forms ninja forms oop open source php top cash back Topcashback wordpress