Repository Guideline Reminder: Do Not Remote Load Content

In a very irregular feature, we’re posting about various plugin guidelines and what they really mean to you.

This week, we want to remind you about a long-standing guideline in the repository, which is covered in item #7 – Don’t phone home without consent.

No “phoning home” without user’s informed consent. This seemingly simple rule actually covers several different aspects:

The guideline goes on to break down what we mean in four main points:

  1. No unauthorized collection of user data
  2. All images and scripts shown should be part of the plugin
  3. No 3rd party ad tracking
  4. No ad-spam

That second item (which I emphasized) is what we want to remind you of today.

Your images, your scripts, your CSS, etc, should all be included locally. Besides not tracking users, keeping everything locally will make your plugins faster. It obviates the problem of external load. It means when your server is down for maintenance, you didn’t just slow down everyone’s wp-admin. It means you’ll never DDoS yourself on accident.

Unless you’re a service, your plugin has no business phoning home to your own servers to load data. If you are a service, you must have this clear in your readme as to what the service entails, preferably with a link to your ToS and and explanation as to what is tracked. This is for your protection. By remote loading files, you have the ability to track users. Data tracking is a huge deal, and while we understand you want to do it for metrics, it someone was taking your data without permission or consent and selling it or using it to promote their code, you’d be pretty ticked off.

You can (and should) re-read all the guidelines on – we rarely change them though we may reword things for clarity.

If you have suggestions as to how we can be more clear about #7, please leave a comment and let us know.

Keep in mind, we’re not going to spell out everything to the letter, as in our experience that leads to people playing nit-picky fake-lawyers about everything, and still violating the ultimate rule of the guidelines which is ‘Don’t be a spammer.’ For example, we’re not going to make a rule for not stealing other people’s plugins. You already know stealing is bad, right? 😈

#guidelines, #reminder, #repository

[Somewhat Resolved] Assets/Readmes not showing properly on Plugin Pages

1624 UTC – Tue 19 April

This is MOSTLY resolved, but basically we’re going to be facing sync issues for a while until someone sorts out why they’re getting so behind. The best thing to do here is to WAIT and not push anything. The more you push, the longer the queue gets and slower it gets :/

1541 UTC – Wed 13 April

We are aware of an issue where your assets (banners etc) and readme information isn’t loading properly, and we are looking into it.

Please DO NOT push your code multiple times! It’s like ringing a doorbell over and over. It doesn’t actually make things work better 😉

As a general reminder, though, please try to keep your readme to under 10k. You can shuffle your changelog off to a separate file (chaneglog.txt) to keep things smaller. After all, no one really reads the 1.x version of your changelog from 6 years ago.

In addition, if your plugin is very large, it’s okay to remove old versions from SVN. That will ensure processing and syncing is faster 🙂

We will update this post with any information as we determine exactly what’s wrong.

Update 1: One of the servers is running behind again. So please just be patient. Go for a run. Dance. Sing. It’ll catch up 🙂

Update 2: Still running slow. There are moments where this will work fine, and then it will drag. Sorry.

Please do not submit frameworks

Note: We are aware that some frameworks are current in the repository. We are asking you not submit any NEW at this time.

This isn’t a new ‘rule.’ It’s not a secret one either. It’s not listed in the guidelines specifically because any attempt to lay down each and every reason a plugin shouldn’t be in the repository just ends in people rule-lawyering. Should we have to tell people “Don’t ask users to write to your plugin files”? No. That should be self-evident. A plugin gets replaced when it’s upgraded, so writing to plugin files means the changes get destroyed. And in many ways, that’s our problem here.

The issue is as follows: Having a framework as a plugin is a poor experience for the user. Not the developer. The user. The user understands “I have an add-on for WooCommerce, I probably need Woo.” They do not always understand “I have plugin Slider Joe. Why do I need Advanced Custom Fields?” In addition, by having a library as a plugin, the onus of version compatibility is now on the person least likely to understand it: the user.

The plugin repository is not, currently, a library or framework repository. It’s not meant like the NPM package manager, or even Composer as a way to define what a plugin ‘needs’ in the same ways for a developer to build a project. The plugin repository is, plain and simple, meant for plugins that users will find useful. Plugins that add functionality to WordPress in a directly inter-actable way.

We don’t allow people to add javascript or fonts on their own to the repository and, I suspect, most of you would nod and say “Well of course not. A font and javascript should be included in the plugin or theme!” We feel the same way about most full blown library and framework plugins too. The user doesn’t need to know or care about the libraries. They shouldn’t be expected to be responsible for it.

At this time, we are not accepting frameworks as we don’t feel frameworks, boilerplates, and libraries are appropriate for the Plugins Directory. We require that plugins be useful in and of themselves (even if only being a portal to an external service). And while there are many benefits to frameworks and libraries, without plugin dependency support in core or the directory, it becomes another level of hassle for users.

The parade of likely support issues:

  • Not recognizing the framework plugin, and thus deleting it (causing the plugin(s) to break)
  • Not recognizing the framework plugin and thinking they’ve been hacked
  • Debugging drama, when we tell them to disable all their plugins and they find its a library problem
  • Updating the framework plugin separately from the dependent plugins, possibly leading to breakage
  • Updating a dependent plugin without updating the framework, possibly leading to breakage
  • Plugins not keeping up with library changes to the point that they break
  • Different plugins requiring different versions of the framework

And bearing in mind that the framework and plugin developers are different people, that’s another level of coordination/compatibility issues. A developer is (in theory) clever enough to write their plugin in a way that it includes the version of the library they need in a way that will not break everyone else. Of course, you developers know that’s a goal and not an absolute.

Frameworks and libraries should be packaged with each plugin (hopefully in a way that doesn’t conflict with other plugins using the framework or libraries). At least until core supports plugin dependencies.

Making this messier is the fact that once a library is in the repository, you shouldn’t put it in your plugin anymore. Why not? Well what happens if they install a library as a plugin, while having the library inside a plugin already? Which one takes precedent? What happens when they’re out of sync and so on? See the goal up above that isn’t an absolute. It gets even messier.

A library is a library, and should be in the plugin, not separate.

Maybe one day we’ll have proper plugin dependencies, but we simply are not there yet.

#directory, #reminder, #repository

Reminder: Many Javascript Libraries Are Included in Core

WordPress includes jQuery with core. Most everyone knows this. But did you also know WordPress includes a great deal of other libraries for your use.

You should take the time to check the documentation on wp_enqueue_script().

But that list actually isn’t complete! For a complete list of registered files inspect `$GLOBALS[‘wp_scripts’]` in the admin UI. Registered scripts might change per requested page. You can also check out the massive amounts of files in wp-includes to see even more.

My point, though, is that 90% of the time, you don’t need ‘your own’ version of something. We have it.

Even datepicker folks (jquery-ui-datepicker).

Check if core works. If you call it right, most of the time it will.

#libraries, #reminder

Plugin Review “Inconsistencies”

A few people have complained that they feel the review process is inconsistent. I’d like to take a moment to explain exactly why that happens. The tl;dr is, of course, humans make mistakes. But if you really want to understand what’s going on, read on!

There is no automated review process

This is the big thing. Every single plugin is opened and read by a human being. We download the plugin, read it, and try to catch the myriad things that are wrong, insecure, not permitted, etc. And we’re humans. We do our best to scan/grep for things we know are easy to find (like I love checking for wp-(con|load|blog) to see if that’s being called). But a lot of times things are buried or hard to catch.

This means mistakes are made. We don’t claim to be perfect. We claim to try our best to give you the best review we possibly can for your sake, as well as your users.

Some replies are canned, the process is not

I’m sure a lot of you have gotten an email starting with this:

There are issues with your plugin code. Please read this ENTIRE email, address all listed issues, and reply to this email with your corrected code attached. It is required for you to read and reply to these emails, and failure to do so will result in your plugin being rejected.

Yes, that’s a canned auto-reply. In order to get through reviews faster, we have replies for the common issues. Right now I have 60 in A-Text. That means there are at least 60 problems with plugins I see every single day.

This makes us able to keep up with reviews. It’s impersonal, we know, but we try to cite examples from your plugin to help you understand what needs your attention.

We don’t test your plugin on all environments

Sometimes we do. But really that’s your job, not ours. We do if we notice things that are weird and we think may be problematic. Some days we test on VVV with PHP 5.6, sometimes it’s HHVM, and sometimes its PHP 5.2. Why? It depends on what we have available just then.

This means sometimes we catch that you coded something for PHP 5.3 and up and sometimes we don’t.

Every new version is checked top to bottom

Think about that for a second, please. If you submit a plugin and we pend it for changes, and you send us the new version, we read the whole thing all over again. Every. Single. Time. We check to make sure you did your changes first, yes, but then we go back and re-read everything to make sure we didn’t miss anything, or you didn’t accidentally add in something new.

This is why, sometimes, you get an email that starts with “We missed this before…” or “This is also not permitted because…” We’re giving you the best review we can.

No, we don’t list everything wrong

It’s not what you’re thinking. Every time we do a review, we list everything we see that’s wrong. We do not list out, for example, every instance of a non-sanitized/validated POST call. We do not list out every single usage of script tags instead of enqueues. We will give you an example, especially if you miss some on your first edit, but we expect you to know how to search your own code.

This helps you learn how to better vet and review your own code. Also it saves us a little time.

There are multiple people doing reviews

Some of us are better at some thing than others. When we find a plugin we don’t feel confident in reviewing on our own, we raise a flag and ask our cohorts to spot-check our work.

This also lets us hand off troublemakers. Let’s be honest here, folks, we don’t all get along with everyone. When it’s clear we’re at an impasse with someone, we ask each other for help.

Our goal is protecting users first, then you

The people we care about the most are the users who can’t code or who don’t understand the severity of things like offloading CSS. You may think it’s trivial and makes your plugin smaller. Someone in another country could find them sued for not disclosing it. Or your plugin may not work because Google is blocked where they are.

We care about protecting the users from XSS and SQL injections. We care about protecting their information. We care about keeping them safe. But we care about you too! We’re so techy about you documenting ‘This plugin calls service XYZ’ because, yes, the users have a right to know where their data is going, but also because you deserve not to have a slew of angry 1-star reviews that you didn’t tell them.

This is a tricky road to walk. Some people may get exceptions. Some people may teach us more about code! Some people may be told ‘no’ flat out.

Guidelines evolve over time (so do security best practices)

We’re constantly looking over the guidelines and evaluating them for clarity, consistency, supportability, and real-world applicability. Have you read our Detailed Plugin Guidelines lately? You should. Similarly, our security checks have gotten better over time. We used to allow you to call wp-config.php directly. We don’t anymore. The more a specific vulnerability is targeted, the harder we are on your code to ensure you are not the weakest link.

This is for your protection! We’re doing our best to make sure you don’t get dog-shamed for being the reason sites go down.

Remember: We are mortal

I said this to start off this post and I’ll say it again. We, your review team, are human beings.

We make mistakes. We miss things. We read code incorrectly. We don’t test everything as fully as we should. We screw up. We never miss things out of maliciousness or an intent to blacklist you from the repository. We believe you submit your plugins in good faith, and we respect you enough to treat you as adults and point out what you missed or explain how you can do things better.

This means you should give us the same benefit of doubt we give you.


[RESOLVED] Jan 11 – Issues committing to SVN

0100 UTC

This problem should be fixed now. Let us know if you have any continuing issues. -Otto

2339 UTC

We’ve ruled out a couple things. The access table seems okay. But right now we don’t have an ETA 🙁 I’m sorry.

2141 UTC

Just an update to let you know we’re still looking into it. You don’t need to tell us your plugin names. Pretty much everyone who was approved this weekend and on has this issue.

1631 UTC

We’re aware of this and looking into it. Please keep an eye on this post. We will update as soon as we have any information.

‘Policy’ on PHP Versions

The official stance of is that WordPress is supported on PHP 5.2.4 or greater.

The official stance of the Plugin Team regarding what version of PHP your plugins can use is .. not that.

We don’t have an official stance. We’ve never needed one. We do (often) test complex plugins on multiple versions of PHP (and sometimes HHVM) to make sure there’s proper degradation and support, but at the same time, we do not have an official requirement that you must support version X or Y.

This is not an official requirement post.

This is a reminder post.

Use whatever version of PHP works best with the code you’re writing. If you’re using, for example, Amazon S3’s library, you must use PHP 5.3 and up because otherwise the libraries won’t work. From that standpoint, your plugin should require PHP 5.3 and up. That’s a decision prompted by circumstances outside of WordPress.

For everyone who just wants to know what to do if your plugin must be on PHP 5.3 or 5.4, the answer is this:

Make sure your plugin checks for any and all requirements on activation and, if they’re not found, it should gracefully fail and alert the user as to why.

This includes things like required software (if your plugin is an add-on to WooCommerce, yes, check that WooCommerce is installed and active), but also PHP versions and (if needed) SQL versions. That’s your responsibility. We’re not going to force you to do it at this time, but understand that your plugin’s reviews and ratings will be directly impacted by how you handle those things.

Fail gracefully. Degrade gently. Error politely. Consider your users. Remember: WordPress can be used on anything.

This can be complicated or not, depending on your requirements. The main thing to think of here is that if you don’t support PHP 5.2, then your main plugin still needs to work in PHP 5.2.

Practical Examples

Let’s say you use a function that only works in PHP 5.3 and up. A simple function_exists check will do the job:

if ( !function_exists( 'some_function' ) ) {
    add_action( 'admin_notices', create_function( '', "echo '<div class=\"error\"><p>".__('Plugin Name requires PHP 5.3 to function properly. Please upgrade PHP or deactivate Plugin Name.', 'plugin-name') ."</p></div>';" ) );

Note the use of create_function here, because anonymous functions (aka closures) don’t work in PHP 5.2.

The use of return prevents the rest of the plugin from executing here, preventing that function call later from causing a syntax error.

Sometimes though, you need more complicated checks. Let’s say your plugin uses PHP namespaces. Those are not supported in PHP 5.2, and will cause a syntax error just from having them in the file, before any of your code runs.

So, your main plugin file needs to not have namespaces and basically only be a shiv to load the rest of the plugin from another file if the requirements are met:

if ( version_compare( PHP_VERSION, '5.3', '<' ) ) {
    add_action( 'admin_notices', create_function( '', "echo '<div class=\"error\"><p>".__('Plugin Name requires PHP 5.3 to function properly. Please upgrade PHP or deactivate Plugin Name.', 'plugin-name') ."</p></div>';" ) );
} else {
    include 'rest-of-plugin.php';

Here, the plugin does not load the files that can cause errors unless the requirements are met.

Maybe you need to check against the WordPress version. Plugins load in the global context, so the $wp_version variable is available to you to check:

if ( version_compare( $wp_version, '4.0', '<' ) ) {
    add_action( 'admin_notices', create_function( '', "echo '<div class=\"error\"><p>".__('Plugin Name requires WordPress 4.0 to function properly. Please upgrade WordPress or deactivate Plugin Name.', 'plugin-name') ."</p></div>';" ) );

Although, if you’re requiring a specific WordPress version, then you’re more likely to be requiring a specific function instead, in which you should check for that specific function as in the first example.

If you want to be complicated about it, you can indeed do so. Here’s code for a plugin which will deactivate itself if the PHP version requirement is not met:

if ( version_compare( PHP_VERSION, '5.4', '<' ) ) {
    add_action( 'admin_notices', create_function( '', "
        echo '<div class=\"error\"><p>".__('Plugin Name requires PHP 5.4 to function properly. Please upgrade PHP. The Plugin has been auto-deactivated.', 'plugin-name') ."</p></div>'; 
        if ( isset( $_GET['activate'] ) ) 
            unset( $_GET['activate'] );
        " ) );
    add_action( 'admin_init', 'pluginname_deactivate_self' );
    function pluginname_deactivate_self() {
        deactivate_plugins( plugin_basename( __FILE__ ) );
} else {
    include 'rest-of-plugin.php';

The reason for the unset of $_GET[‘activate’] here is so that the normal plugin activation process will not show the normal activation message, showing the plugin’s message only.

These are not the only ways to perform a check like this, however they should be enough to get you started. Remember: Make things obvious to your users what the problem is, so they can understand the situation and take action.


Ratings Rebuilt

Did your ratings suddenly change dramatically? Hopefully not, but if they did, it’s because the ratings for all plugins were recently reset and rebuilt earlier this week. All ratings now correspond exactly with existing, non-deleted, reviews.

As Otto put it:

Back when we launched the review system 2.5 years ago, we tied ratings to reviews. However, up until that point, we had existing ratings in the system. At the time, some argued that the ratings should be wiped and everybody start fresh. I argued for the opposite, that we should leave the existing ratings in place until such time as we had enough reviews in the system to build up a good body of ratings.

That time has finally come. What you see now is the ratings that correspond to your reviews. The data comes directly from the reviews themselves, and is accurate. Any ratings previously left over from the pre-review world are no longer available.

Additionally, the ratings now will accurately reflect the actions of the moderation team. If a review is deleted for whatever reason, then the associated rating for it will not be reflected in the results.

Please keep in mind, this means that all of the people who thought making sockpuppets to spam the reviews with 5-stars on their own plugins (or 1-stars on their competitors) have had the biggest swings. It should go without saying that you should never leave multiple reviews on your own product (we’re pretty sure you like it 😉 ) and you should never attempt to hide behind proxies and fake accounts to leave reviews. Be honest. It works out better.

#directory, #repository, #reviews

GPL and the Repository

All plugins hosted in the repository must be compatible with GPLv2 or later. That means all code that is on our servers, from images to CSS to JS to the PHP code, has to meet that requirement. This is an extra requirement than just the standard one of derivative code, but we strongly feel that proprietary content has no need to be in our repository. If your code needs to be split licensed, or you have to included proprietary code for any reason, we can’t host you on .org, but that has no bearing on how neat and cool your code might be.

For a list of various licenses, and their compatibility with GPLv2 please read this: – We know not all of you are lawyers, and thankfully that list makes it easy to check what licenses do and don’t mesh. If something doesn’t have a license, ask the author please, and don’t assume.

The following code bases are popular (which is to say we see submissions with them pretty regularly), but at the time of this post, are not licensed GPL-compatible. None of this means you can’t or shouldn’t use this code on your sites or plugins, just that we can’t host it here if you do.

If there are plugins you find using these (or any non-GPL-Compatible) code bases in their plugin, please email plugins AT and we’ll get in touch with the developer. If you’re the author of one of those code bases, please consider re-releasing your code under a GPLv2 Compatible license! We’d love to be able to host your work here.

#gpl, #licensing