DEV Community

Cover image for Sending a plugin to the Wordpress Plugin Directory
Rowinson Gallego
Rowinson Gallego

Posted on • Updated on


Sending a plugin to the Wordpress Plugin Directory

I'm the creator of the Perfecty Push Notifications plugin. This is a Wordpress Plugin that has a built-in Push API notification integration. You can send push notifications for free, without any third-party dependencies and you retain the data in your server.

Perfecty Push WP

Publish time! 🤞

Once I decided it was the right time to publish it in the Wordpress Plugin Directory, I reviewed it again using the detailed plugin guidelines, bundled it and finally uploaded the .zip file to

This was the first step towards publishing the side project I've been recently working on, so I was excited and panicked at the same time. Would it work? What would they complain about the plugin? Would it never take off?

One day later I got an email with a considerable list of recommendations from them:

Alt Text

I will list what those issues were. You can take a quick look at the MR that addresses them here:

Calling files remotely

For the admin area, I'm drawing a simple stat chart using Chart.js.

Alt Text

I initially thought it was not necessary to include it as an enqueued javascript but as a simple direct inline import in the HTML.

Enter fullscreen mode Exit fullscreen mode

However, that's not what is suggested in the plugin guidelines, calling third-party systems, so I had to bundle the min.js file with the plugin and mention it in the README.txt:

  plugin_dir_url( __FILE__ ) . 'js/chart.bundle.min.js',
  array( 'jquery' ),
  false );
Enter fullscreen mode Exit fullscreen mode
This plugin uses the [Chart.js]( library for the admin stats charts.
Enter fullscreen mode Exit fullscreen mode

Data Must be Sanitized, Escaped, and Validated

This is related to this admin page:

Alt Text

I am relying on the well-known WP_List_Table API implementation and honestly didn't catch it, so it was a nice find from them:

perfecty-push-wp/admin/class-perfecty-push-admin-notifications-table.php:118: $ids = is_array( $_REQUEST['id'] ) ? $_REQUEST['id'] : array( $_REQUEST['id'] );
perfecty-push-wp/admin/class-perfecty-push-admin-notifications-table.php:28: 'view' => sprintf( '<a href="?page=%s&action=%s&id=%s">%s</a>', $_REQUEST['page'], 'view', $item['id'], 'View' ),
perfecty-push-wp/admin/class-perfecty-push-admin-notifications-table.php:29: 'delete' => sprintf( '<a href="#" data-page="%s" data-action="%s" data-id="%d" data-nonce="%s">%s</a>', $_REQUEST['page'], 'delete', $item['id'], $action_nonce, 'Delete' ),

perfecty-push-wp/admin/partials/perfecty-push-admin-notifications.php:13: <input type="hidden" name="page" value="<?php echo $_REQUEST['page']; "/>
perfecty-push-wp/admin/partials/perfecty-push-admin-users.php:12: <input type="hidden" name="page" value="<?php echo $_REQUEST['page']; "/>
Enter fullscreen mode Exit fullscreen mode

And it was very easy to fix:

$page = esc_html( sanitize_key( $_REQUEST['page'] ) );
Enter fullscreen mode Exit fullscreen mode

For the issue in the class-perfecty-push-admin-notifications-table.php:118 line, honestly I thought it was sufficient with the intval() filtering to each of the elements:

        $ids = array_map(
            function( $item ) { 
                return intval( $item ); 
Enter fullscreen mode Exit fullscreen mode

However, I decided to do the recommended sanitization:

        $ids = array_map(
            function( $item ) {
                $item = sanitize_key( $item );
                return intval( $item );
Enter fullscreen mode Exit fullscreen mode

Included Unneeded Folders

This was me not knowing how the final structure of the distributable .zip file should look like. I was including some unnecessary folders and files. With their suggestions and reading the guidelines again, I just created a new shell command that copies the required files and the optimized vendor folder:

bundle() {
  CMD=$(plugin_cmd 'rm -rf vendor && composer install --no-dev --optimize-autoloader')
  compose_exec "$CMD"
  cp index.php vendor/
  zip -v -r admin/ assets/ includes/ languages/ lib/ public/ vendor/ composer.json composer.lock index.php LICENSE.txt perfecty-push.php README.txt uninstall.php
Enter fullscreen mode Exit fullscreen mode

The final folder structure looks like:

Alt Text

Please use wp_enqueue commands

This is tied to the first issue with Chart.js. As I was including it directly, I was not using wp_enqueue. Now that I'm bundling it, it is already addressed.

And that was it! ✅


While reviewing their suggestions I noticed I didn't put the dummy index.php file in some of the folders having PHP files so I also did that.

Let's reply to the email

Once I fixed those issues I got back to them and send the link to the distributable .zip file generated from the shell:

Alt Text

I'm still waiting for their comments and I expect more input from them, so I'll keep you posted!

I've received feedback even before posting this and apparently now I need to address some outdated dependencies from Composer, which ultimately affects the planned minimum PHP version I was intended to support. For that I will create a new post with further details. Thanks for reading!


Cover: Photo by SpaceX on Unsplash

Top comments (0)

An Animated Guide to Node.js Event Loop

Node.js doesn’t stop from running other operations because of Libuv, a C++ library responsible for the event loop and asynchronously handling tasks such as network requests, DNS resolution, file system operations, data encryption, etc.

What happens under the hood when Node.js works on tasks such as database queries? We will explore it by following this piece of code step by step.