Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: plugins

  • Making Plugins Filterable

    Making Plugins Filterable

    I’m really bad at thsi since, generally, I don’t know why people would want to with the plugins I make. Which means I don’t do it. Which means I didn’t know how.

    I have a plugin that records the IP address of users as they register and outputs it on the ‘show users’ page. It’s simple and it works.

    Someone asked me if I could make it link to a place where he could see where the IP was from. Now my intent with the plugin was to list the IPs so I could spot serial sock puppets. But this use-case, I agreed, was valid. I just didn’t want to tie my plugin into one service or another. So I made it filterable.

    As it happens, it was incredibly simple. This is filed under “Stuff I should have known years ago…”

    Make The Output Filterable

    Originally I had the code outputting $theip and, in order to make it filterable, I wrapped that with this:

    if ( has_filter('ripm_show_ip') ) {
        $theip = apply_filters('ripm_show_ip', $theip);
    }
    

    The whole function looks like this:

    	public function columns($value, $column_name, $user_id) {
            if ( $column_name == 'signup_ip' ) {
                $ip = get_user_meta($user_id, 'signup_ip', true);
                if ($ip != ""){
                    $theip = $ip;
    				if ( has_filter('ripm_show_ip') ) {
    					$theip = apply_filters('ripm_show_ip', $theip);
    				}
                    return $theip;
                } else {
                    $theip = '<em>'.__('None Recorded', 'register-ip-multisite').'</em>';
                    return $theip;
                }
            }
    	    return $value;
    	}
    

    You’ll notice the has_filter() check is only on one possible output? That’s because I’m translating the output on the other one, which says “None Recorded” I could filter that, so people could change it to anything they want, but right now I think that’s a bit odd.

    Filter The Output

    To test this, I made a file /mu-plugins/register-ip-multisite.php and put the following inside:

    function filter_ripm_show_ip($theip) {
        $theip = '<a href="https://duckduckgo.com/?q='.$theip.'" target="new">'.$theip.'</a>';
        return $theip;
    }
    add_filter('ripm_show_ip', 'filter_ripm_show_ip');
    

    That made it a link. Simple.

    Does It Work?

    Of course!

    Example of users screen with the IP showing as a link

    I did not apply the filter to the output on the edit-users page, but if that turns out to be needed, I can.

  • The Trouble With Libraries

    The Trouble With Libraries

    I’ve had the same argument over and over, to the point that people follow me here and complain that I suck. You’re welcome. I’m going to spell out the issues, as I personally see them with frameworks as plugins. If you want to talk about this in so far as it applies to the WordPress plugin repository, please read this post and keep the discussion there.

    The Problems

    Problem 1 – Users have no idea what the ‘library’ plugin is for.

    Most users understand “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?”

    Problem 2 – We don’t have true ‘dependancies’ in WordPress

    I think everyone can accept that’s a problem. We literally do not have a perfect way to require things. Look at Themes. If you try to delete a parent theme, you get warned there are children around. We don’t have that for plugins. We probably should.

    Problem 3 – Users are responsible for something they don’t understand.

    By having a library as a plugin, the onus of version compatibility and updates is now on the person least likely to understand it when it breaks: the user. They have to update the library, and your plugins, every time there’s a new version.

    Problem 4 – Frameworks and libraries can no longer break backwards compatibility.

    This is hugely restrictive, by the way. With a framework-as-plugin you can’t break things because you (the framework developer) are responsible for all the plugins that use your framework. If you break how things work from V1 to V2, and one of the myriad plugins a user has doesn’t work on V2, and the user updates your framework, you broke things. True, this was always the case, but at least the plugin contained the library and could use it’s own version.

    Problem 5 – Plugins will still break.

    I have to say ‘still’ because we have one version of the problem today, and we’ll have another tomorrow. Right now, if four plugins include the same library, and they’re all different versions, we don’t have a clear and perfect way to know which version of the library the user will get. Tomorrow, if a framework is a separate plugin, there’s absolutely no assurance than every plugin that requires that library has been tested with the version the user has install.

    The Options

    Today we really have two.

    Option 1 – Frameworks are plugins and users have to install them.

    This means all new plugins that include said framework have to remove it and change it to a require. All existing plugins should be contacted and told to change their code. Some users will complain about installing ‘extra’ plugins and some developers will lose users (it’s already happened).

    All developers have to put in this requirement themselves, possibly using a library like TGM (until we have dependancies). Also all developers have to ensure they, now and forever, keep up with the frameworks and ensure compatibility as well as proper alerts if a user removes the framework by accident. Their code has to break elegantly if the user doesn’t upgrade the library. Your plugin takes advantage of the latest feature in a framework? Awesome. Make sure your plugin checks “If this feature exists, use it” and fails gracefully if not.

    Option 2 – Frameworks that are not ‘functional’ frameworks, but really libraries are treated as all libraries are with all projects, and included separately.

    Developers have to code the calls to the library, making sure that the ‘right’ version is included no matter what someone else includes. Developers also have to update their plugins when a library updates. though if they properly handle the code calls, they don’t HAVE to. They could use namespaces and cleverly call use MYPLUGINAWSSDK as /aws/AWS/foo/bar instead, so their version is what’s used. They’ll probably want to code in a failsafe “If a version higher than mine is used, show a warning.”

    The Solution

    Looking at the options we have today, we have to ask “Which is better?”

    Neither. They both suck for developers. They both suck for the users. They both frustrate everyone. I have heard arguments from the same number of developers for each option. Some developers want to include the ‘core’ or a framework in their plugin because it’s ‘better’ than requiring another plugin. Other developers want the other plugin so they don’t have to be responsible to update the library.

    There is, clearly, an argument to be made in both cases. There isn’t a win here. Personally, I think once a framework or library exists as a plugin in the .org repository, you should remove it from your plugins and require it. Of course, good luck figuring out how to do that in a sane way without breaking people. The best I came up with was have a period of time where you keep the library while using TGM or something to require the other plugin. Make an alert or notice to tell users to install the requirement. Keep that for a whole major version. Then, on the next major version release, drop the library.

    With all that in mind, we have to ask this instead “Which option annoys users slightly less?”

    That’s – libraries as libraries, not plugins. The one where the users don’t have to know (or care) about it anything except “I have plugin X.”

  • What’s In a Plugin Name

    What’s In a Plugin Name

    Not terribly long ago, we stopped letting people use someone else’s trademark or company/plugin name as the first term in their submitted plugin.

    Example:

    “Girl Scout Cookie Tracker by Mika” would no longer be accepted.

    However “Mika’s Girl Scout Cookie Tracker” would be just fine.

    The point we try to make here is that your name, your product name, should be first.

    Of course, that second name is pretty poor, and I’d be more inclined to name it “Cookie Order Hunter” with the description of “Hunting down Girl Scouts to buy your next hit of Thin Mints has never been easier!” Yes, I know you can buy them online, not the issue here.

    This new name is sort of neat. It’s got a kick to it and it has a distinct name. Suddenly I have a sort of branding all my own and this is good! I am now unique and I will stand apart from the other similar plugins.

    Of course there are times when you don’t want to do this. I wrote a plugin called “EDD – Prevent EU Checkout” and I submitted it as “EDD Prevent EU Checkout” because it was a “Prevent EU Checkout” plugin only for Easy Digital Downloads. If I was doing my normal thing, where I pick a fun name, then I would have used the dev name: “EDD – Sucks to be EU.”

    Here, though, I started the plugin with EDD – a search term often used – and ended with a description of what the plugin was. The fact that I keep the name as I do just means I haven’t finished the new version. I will soon be rebranding it to “Prevent EU Checkout with Easy Digital Downloads” because that’s a better SEO friendly name.

    But here I’ve pointed out two things. The display name and the submission name are two different things for a reason. The display name is what people see, and the submission name is what sets your URL in the repository. Had I used “Prevent EU Checkout with Easy Digital Downloads” then my URL would be https://wordpress.org/plugins/prevent-eu-checkout-with-easy-digital-downloads and that’s not a friendly URL to anyone.

    Submit a plugin with the ‘name’ you want for your URL.

    Let’s take an example just for fun. Commoji – A plugin that lets you reply to comments with emoji reactions. No it’s not real. Yet. I would submit this as ‘commoji’ (all lowercase) and in the description I would put only the short description, leaving the readme to be read on it’s own. Remember: The readme is vital, so every pertinent piece of information that a user should have must be in that readme.

    Within my plugin code, and that readme, the plugin’s display name would be “Commoji – Reply to comments with Emoji” (and if I’m feeling puckish, I’d add ? at the end).

    Now I have my cake and Edith too! A short plugin slug, a descriptive plugin name, and a unique name that people will remember. I’m not stomping on Emoji’s trademark, such as it is, and I’m demonstrating my own individuality.

  • Chickens, Eggs, and MVP

    Chickens, Eggs, and MVP

    There’s a lot of weight to shoulder for the WordPress REST API project. It has a lot of hurdles to overcome and a lot of doubters to win over.

    I’ve been silent about it, thoughtful about it, and questioning about it. I personally want the REST API if, for no other reason, than once it’s in-core, we can set the XMLRPC on fire. Which means…

    My MVP – Parity with XMLRPC

    That’s right. If the REST API can do everything that XMLRPC can do today, I think that part of its code needs to be in Core today. Get it in. Get people using it. I don’t think the measurements of how many plugins are using the REST API are a valid argument, since you get these numbers (roughly):

    • 115 plugins use XMLRPC
    • 25 plugins use V1 of the REST API
    • 21 plugins use V2 of the REST API

    Now, this is not the right measurement because looking at both XMLRPC and the REST API, we are not clocking the number of plugins but the number of sites – non WordPress sites even – that are calling these features. And that is a number that cannot be measured. There’s no way on the planet to really know for sure how many people use those features because, for the most part, they’re not doing it within WordPress. All the plugin scans will tell you is people who are extending it, for the most part. WooCommerce, Advanced Custom Fields, those are plugins adding their own endpoints and hooks.

    And those, yes, are important. But more so is the real-world.

    Can we detect how many WordPress sites are using the JSON API? Not really. Sure we could probably violate trust and get a list of every site that’s asked for an upload or install of the plugin, that wouldn’t tell us who has it active and who is using it.

    We’re Not Ready (Until We Leave Beta)

    We’re not wrong to be cautious about this. There’s a freedom a plugin has that a core feature does not. Once the REST API is in core, it’s done. I don’t mean development or innovation stops, I mean we can no longer make breaking changes.

    While we believe the API is now stable enough for public testing, we may continue to break the API in the future as we improve it further. Only use the API in development, and do not use version 2 in production environments.

    That’s what the documentation for Beta 1 says. And when I look at the changelog for 2.0 Beta 12.0 (released February 9, 2016) I count six changes labeled ‘breaking change.’ That’s bad. I hesitate at saying it’s deplorable, as I understand why it’s happening. They’re iterating fast and hard and trying to get to a place where they’re ready.

    That said, this is a real world problem, as Eric Mann expressed in a series of Tweets:

    My client installed the REST API before it included post meta. We had to build a bunch of custom work to support meta.
    Then the REST API updated to include meta and broke our integration. I spent a chunk of hours refactoring to compensate so we could update.
    Now, apparently, the REST API is pulling that meta support out and putting it in a separate plugin …
    Yet people still criticize me for saying I’m wary of placing too much dependency on the stability of the API …

    Eric’s point is a good and valid one, and it actually supports both ends of the argument.

    The REST API is too much right now. It’s too much of all the things, and pulling meta out and letting it iterate quickly is a good choice. That said, the rest of the API needs to consider the same things. What’s done? What’s ready and locked and will not be ‘breaking’ changes? That should be ‘stable release ’ and that goes into core.

    From that moment on what’s in core cannot not receive any breaking changes. Lock down: These are done and will not be broken. Give the developers your promise in blood that this is what it is.

    WordPress is backwards compatible for a million miles and frankly the REST API has not been. So make it. Put it in stone. But the REST API plugin itself is really too big to continue developing as it has been, and that’s to it’s detriment. It’s simply not sustainable the way it has been because it’s trying to serve two masters.

    On the one hand, it wants to grow rapidly. On the other, it wants to be secure and safe and solid and ready for code.

    But right now we’re stuck in Beta, and that hurts the perception. Also we’re still breaking things, and that hurts adoption. No one wants to start using a beta product that changes things in a way that breaks their sites. No one wants to use this for clients yet.

    I Propose a “Release Candidate”

    Go back to my first point.

    Parity with XMLRPC. That’s all the REST API core plugin should be right now. Pull out everything else and slap the designation “Release Candidate” on there. You do not break things in Release Candidates. This candidate is your candidate for core inclusion. When it’s good, that goes into core and we close the existing plugin. Of course we do one final update to notify people ‘Hey, this is included in core now! Woohoo!’ It’s called ‘disabling’ the plugin, and anyone who has a feature plugin thats been moved into core, if you want it disabled, contact the plugins team. We will be happy to retire you plugin.

    What about everything else? They get punted out into their own mini plugins. Like meta, they can be iterated and they can break all they want until they hit Release Candidate.

    You see, that Release Candidate is your promise that you believe you are ready to go. Everything works the way you want it to, everything is ready for real-world testing. No more breaking changes.

    In Hindsight

    Looking back, I think the REST API is a perfect example of why the Featured Plugin system is both perfect and problematic. We are trying to simultaneously treat development like a plugin (fast, light, and iterative) and like core (adaptive, backwards compatible, and reliable). The whole reasons we started breaking out things like MP6 into Feature Plugins has come home to roost and shown that the idea is solid, but the methodology needs to be more set in stone as to what they should and should not do.

    For a Featured Plugin, Beta is the time for breaking. RC is the time for testing in the real world. We need to be more firm about what we will include in our Featured Plugins and what we will not. We need to be harder on adding new features. We need to say ‘No’ a little more, and let things be developed outside of the plugin.

    We need a plan that includes the retirement of the plugin when it’s job is done.

  • Mailbag: The Trouble of Rollbacks

    Mailbag: The Trouble of Rollbacks

    Anonymous asks:

    Why doesn’t WordPress let me rollback a plugin?

    Answer: Because the education of developers as to how to properly tag and number releases hasn’t hit critical mass.

    Other answer: Because no one’s paid me enough yet to sit and manage every single WordPress plugin release to ensure the developers are properly using tags.

    Other answer: No one’s written the code to enforce proper tagging for plugins.

    Look. Let’s step back. Why does rolling back WordPress work? I’m going to assume you disabled auto-updates for a moment. They work becuase WordPress understands semantic versioning.

    • 4.4 is a major release.
    • 4.4.1 is a minor release (bug and security fixes)

    Now go look at your plugins. Look at their versions. Let me show you what I, a plugin reviewer, sees:

    • 20151205-295323 is a major release
    • 3.2.3.1 is a minor release
    • 4.2.1 is a major release
    • 14.4 is a critical bug fix
    • 738741 is a minor release

    It goes on and on.

    But even if we fix that, we have to trust that people will remember to actually use the SVN tags folder. They don’t. Trust me, about half the time I contact a plugin developer about a problem, I have to ask them to please use SVN properly.

    The trunk folder is for the ‘latest’ version of your plugin. This may be a beta, and it may be the same as your stable release. Either way, trunk should be a working version.

    The tags folders are for your releases. Finished up version 1.3.4? Great! Update the plugin readme and the main file to have the new stable version and run svn cp trunk tags/1.3.4 to copy it over. Done. But no, they don’t do that.

    This is the ‘fault’ of open source and freedom, of course. We let plugin developers do what they want, a lot more than themes, and with that freedom comes risks and responsibilities. Different people rise to those responsibilities differently. Most of us stumble along, make mistakes, figure out what best practice works for us, and move on.

    Should WordPress enforce proper behavior? I gotta tell you, I don’t think it would be sustainable. Not without a much smaller repository and not without some sort of signed contract with developers to agree to the guidelines. And I don’t think developers would like it.

    I don’t think we’re (yet) at the point where auto-updating plugins is wise. Themes, yes, but I don’t think plugins are quite there yet. Maybe we’ll get there, but there are so many hurdles before us it’ll be a while yet.

  • Packaging and Shipping Resource Folders

    Packaging and Shipping Resource Folders

    No, I don’t mean resources to get help.

    Have you ever opened a plugin or theme and seen a folder that says bower_components or node_modules? Yeah, I hate those. I don’t hate Bower or Node, I use them quite a lot. I hate how people use them in their plugins.

    What Are Those Folders?

    In order to make life easier, Bower is a package manager that lets you install libraries that your plugin needs. Making a plugin that needs AWS SDK?

    bower install aws-sdk-js

    Boom. And you can easily upgrade it too with bower update – which I love. This is a great idea.

    $ bower install aws-sdk --save
    bower aws-sdk#*                 cached git://github.com/aws/aws-sdk-js.git#2.2.28
    bower aws-sdk#*               validate 2.2.28 against git://github.com/aws/aws-sdk-js.git#*
    bower aws-sdk#~2.2.28          install aws-sdk#2.2.28
    
    aws-sdk#2.2.28 bower_components/aws-sdk
    

    But notice that last line? bower_components/aws-sdk is where it saved my files. And if I go in there, the JS file I need is bower_components/aws-sdk/dist/aws-sdk.min.js and that is surrounded by other files:

    Deep down the bower rabbit hole

    Now as a developer you have a couple choices here. You can leave the file where it is and just call it from there or you can move it. If you move it, you want to make a simple way of updating it. After all, the whole point of using Bower here is to make life easier. Personally I use Grunt for these things. I talked about it last year but my basic idea is to use Bower to download the latest and greatest versions, and then Grunt takes care of (a) updating the Bower packages and (b) copying the files to where I need them.

    Okay, but what if I have something a little more complex?

    What Resources Do I Need?

    This seemingly innocuous question is surprisingly deep. It’s not just ‘what package/library am I trying to manage’, but how do I manage it and with what? What if, instead of the javascript, I wanted to use the PHP AWS SDK instead? Well, the AWS SDK for PHP is not available in Bower! Instead it uses Composer.

    Here’s where things get weird. Composer is a package manger. Grunt is a package manager. Node and Bower are too. This means I have to stop and think hard. Which one do I need? Why do I need it? What am I going to be managing?

    It’s time to ask this:

    What Are My Packages For?

    Within Node there are two kinds of packages:

    • “dependencies”: these packages are required by your application in production
    • “devDependencies”: these packages are only needed for development and testing

    Take a moment to think what you need to dev and what you need to run. Your test code doesn’t need to be in your release, does it? No, of course not. It would make perfect sense to have in your Git or personal repository, but the WordPress SVN repository is not actually for your own code management. It’s a release management tool. That’s another post for another time. Just keep in mind that you should really only be pushing your code to SVN when it’s a version ready for use (be that beta testing or releases).

    Back to what things are for. When talking about the AWS SDK javascript, I’m talking about front end packages. So that’s a dependancy. But Bower? It’s a devDependency. The users don’t need to know (or care) that I’m using Grunt and Bower to package things up. That means they shouldn’t be installed in my plugin!

    In the case of my AWS SDK a ‘devDependency’ is Composer. I only need it to build my packages.

    My dependencies are as follows:

        "require": {
    	    "aws/aws-sdk-php": "2.*",
    	    "doctrine/orm": "*",
    	    "monolog/monolog": "*"
    	}
    

    Adding that to my composer.json file is a simple thing and now I can just run composer update to get everything I need!

    Where Should My Packages Live?

    This is generally pre-destined. If you use Node they go in node_modules and Bower likes bower_components and Composer uses vendor and so on and so forth. You can, of course, customize these. I often make a folder called ‘assets’ or ‘assets-dev’ so I can easily ignore it in my version control. Frankly I don’t need them and neither do my users and it’ll help save space.

    There’s a cool thing about composer. If you use composer init then it asks, at the end “Would you like the vendor directory added to your .gitignore [yes]?” This is great, because if you looked at the folder vendor you would see a lot of folders and files you don’t really want. I actually only want one folder vendor/aws/aws-sdk-php/src/Aws/ and I want that folder to be located in aws/Aws please and thank you. Composer adds this into .gitignore for you.

    You’ll still have to add that into your SVN ignore file, which is a little more annoying. To ignore all composer.* files it’s this:

    svn propset svn:ignore "composer.*" .

    And if you want to ignore multiple files or folders use the following command to bring up the text editor:

    svn propedit svn:ignore . 

    For SVN I would ignore composer.json, composer.lock, and the vendor folder.

    How Do I Move Folders?

    Remember I want to move things to another folder? I use Composer’s scripts to do this. I admit this is ugly code. I have this in my composer.json:

    	"scripts": {
            "post-update-cmd": [
    	        "rm -rf aws/Aws",
    	        "cp -r vendor/aws/aws-sdk-php/src/Aws aws/",
    	        "rm -rf aws/Doctrine",
    	        "cp -r vendor/doctrine/common/lib/Doctrine aws/",
    	        "rm -rf aws/Guzzle",
    	        "cp -r vendor/guzzle/guzzle/src/Guzzle aws/",
    	        "rm -rf aws/Monolog",
    	        "cp -r vendor/monolog/monolog/src/Monolog aws/",
    	        "rm -rf aws/Psr",
    	        "cp -r vendor/psr/log/Psr aws/",
    	        "rm -rf aws/Symphony",
    	        "mkdir -p aws/Symphony/Component/EventDispatcher",
    	        "cp -r vendor/symfony/event-dispatcher/* aws/Symphony/Component/EventDispatcher/"
            ]
        }
    

    This runs whenever I run composer update in this folder and it copies everything where I need it to be. I did tell you it was ugly, right? But it does work.

    The Result?

    The result is my vendor code is never uploaded to WordPress.org’s SVN, my users never see the stuff they don’t care about, and I have a faster way to update my plugins when I need to make sure all the packages are right.