Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: development

  • 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 Big Picture

    The Big Picture

    Decisions, Not Options

    WordPress’s core philosophies are what has allowed it to be extendable, supportable, extensible, and surpass 25% market share.

    One of WordPress’ hallmarks is a massive plugin repository and the ability to extend WP to do pretty much anything. Instead of making the core software huge and bloated, filled with aspects the majority don’t use, WordPress decided to follow a path of ‘decisions, not options.’ With that, the onus is on the developers to deeply learn and understand the implications of any and all changes and additions to the core software. We’re encouraged to separate our personal feelings from what is best for the project and the users.

    We need to think about the big picture.

    I Fight for the Users

    I often say this when I’m in core meetings about ideas for changes that will impact users. Generally these are visual changes, like moving a menu or adding in a more obvious button. When we, as developers, make a decision, we need to have the big picture in mind. Do most users need to decide what quality of image compression to use for WordPress? No. Not because they don’t care, but because the information to explain it is overwhelming to many.

    Recently WordPress increased the default image compression (you’ll see it in WP 4.5). In the proposal, an incredible amount of research went in to figuring out what settings would be best for the majority of users.

    Will the minority, the photography site runners, be possibly upset? Yes. But when we look at the big picture (ironic, I know) we remember that most people will only notice that their sites are loading images faster.

    It’s Okay To Be A Minority

    Most of us started using WordPress and were the majority. We were the target audience and the people it aimed at. Over time, the ways we use WordPress become more and more specific, and suddenly we have at least one way where we are unique and special. We no longer ‘just blog’ on WordPress. We sell our wares, we write novels, we build communities.

    We are, suddenly, a minority in how we use WordPress. This makes it harder and harder to keep the big picture in mind. We are, as humans, inclined to see ourselves first and put our own needs first. Our websites need these things, therefor they are the most important aspect of the upcoming changes in WordPress.

    This isn’t true, of course. But we lose sight of the big picture very easily when the changes impact us, and it tends to make us concentrate on the wrong things.

    I Prioritize the Users

    I speak up for the users in developer meetings when they’re not there.

    I think of them first.

    When I make a change, when I design a change, it’s for the users first. Even when it inconveniences me, even when I feel it’s not the perfect solution for my plans, I consider that what I’m making only is what it is because of the users.

    The big picture is that users make the software what it is. Putting them first in as many things as possible makes it so that they can trust me when I make a decision. When I say “No, this would be better for you as a user but not for your safety.” I know I can say it from a place where I’ve earned the respect and trust of the users.

    You cannot get to that place of trust without putting the users first in all possible things.

    The big picture is bigger than just you, who wrote the software, and you, who used the software. The big picture is all of us.

  • 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.

  • 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.

  • Consenting to Collection

    Consenting to Collection

    Collecting information on users is something every program wants to do. Doing it is easier said than done. (more…)

  • Disclosure

    Disclosure

    One of the myriad reasons I push back on WordPress plugins is because someone didn’t disclose enough information about ‘phoning home.’ Phoning Home is simple concept that comes down to this “Don’t send data from the plugin users back to yourself (or anyone else), unless you’re a service. And if you are a service, make this clear in the readme.”

    Simple, right? It’s totally easy to understand that we want you to tell people “Hey, if you use this plugin, it will report back to my servers…” Much of the time, this is obvious. A Facebook connection plugin, logically, contacts Facebook. Embedding YouTube playlists contacts YouTube. Those sorts of things we don’t worry about, though if you have your plugin say “This will pull data from YouTube” then it’s better. Sometimes this is less obvious, like if you use geoplugin.net to determine locations. Your plugin probably has nothing to do with that domain, but you still have to tell people about it so they know.

    But why do they need to know?

    First of all, this is the basic email I’ll send you if I see you’re not explaining the phone-home in your plugin:

    Plugins that send data to other servers, call js from other servers, and/or require passwords and APIs to function are required to have a full and complete Readme so we can make sure you’re providing the users with all the information they need before they install your plugin. Our goal with this is to make sure everyone knows what they’re installing and what they need to do before they install it. No surprises.

    This is especially important if your plugin is making calls back to your own servers. For the most part, we do not permit offloading of images or code, however in the case where you are providing a service (like Disqus or Akismet or Twitter), we permit it. The catch is you have to actually explain this to the layman in your read me, so they know where data is going.

    Clearly there are some basic reasons, like we should know where our data is going for our own safety. There are also some surprising reasons to people who don’t think about these things, like legal ones. You’re calling out to other servers? What if my company legally can’t do business with them? Then we have the tin-foil hat reasons, like I don’t want to do business with Google so I don’t want to have Google JS in my plugin.

    All that sounds pretty basic. And some of it is super obvious. If you’re making an app to communicate with Facebook, then it’s logically going to send data to Facebook. None of that surprises anyone, nor should it. With a service, one simply has to be up front about what the product does, what services it connects to, and why.

    “This plugin pushes your comments from your Facebook page to your blog, matching users by email addresses with their Facebook accounts (if found).”

    I just made that up. But it’s upfront, it’s honest, it’s direct, and it’s clear what’s being sent and where and why.

    There’s another aspect to this, however, something that is far trickier and more complex. What happens when your existing tool adds a service?

    The obvious answer is that you need to disclose this change to our users. As long as the users know what they’re getting into, then you are golden. The complex answer, the one I can’t really tell you a one perfect answer for, is how you might do this.

    Why is this hard? It’s hard because there is no one right way to tell users about the change. There is no one perfect way to make sure users read the information. There is no one way to get all the data to all the people who need to know about the information.

    And there sure as hell isn’t one way to make sure no one will complain about any of that.

    When you make a change to the paradigm of what your tool does, taking a stand alone tool and adding in a service, you have to consider that a percentage of your users will rebel. This is simply because all those wonderful things you do about disclosing the service for new users have to be transitioned in a meaningful and logical way to existing users. And there is just no way to do that perfectly.

    This doesn’t mean you shouldn’t try. This means you have to be creative and innovation and a little ‘in your face’ about the change. You have to give users an option, before the service kicks in, to say if they want their data shared.