Half-Elf on Tech

Thoughts From a Professional Lesbian

Category: How To

  • Multisite And Theme Activation Checks

    Multisite And Theme Activation Checks

    Earlier this week I talked about how you can’t actually network activate all plugins. As it happens, I have a plugin for a specific theme, and it doesn’t like being Network Activated.

    The plugin is Genesis Simple Hooks and, logically, it only works if you have a Genesis theme installed and active.

    How It Works

    When the plugin is activated it properly runs the following activation hook:

    register_activation_hook( __FILE__, 'simplehooks_activation' );
    /**
     * This function runs on plugin activation. It checks to make sure Genesis
     * or a Genesis child theme is active. If not, it deactivates itself.
     *
     * @since 0.1.0
     */
    function simplehooks_activation() {
    
    	if ( ! defined( 'PARENT_THEME_VERSION' ) || ! version_compare( PARENT_THEME_VERSION, '2.1.0', '>=' ) )
    		simplehooks_deactivate( '2.1.0', '3.9.2' );
    
    }
    

    First this looks to see if there’s no parent theme or if the parent theme version is less than 2.1.0, and if either of those are the case (that is if there’s no parent theme, and the version is less than…) it calls simplehooks_deactivate.

    /**
     * Deactivate Simple Hooks.
     *
     * This function deactivates Simple Hooks.
     *
     * @since 1.8.0.2
     */
    function simplehooks_deactivate( $genesis_version = '2.1.0', $wp_version = '3.9.2' ) {
    
    	deactivate_plugins( plugin_basename( __FILE__ ) );
    	wp_die( sprintf( __( 'Sorry, you cannot run Simple Hooks without WordPress %s and <a href="%s">Genesis %s</a>, or greater.', 'genesis-simple-hooks' ), $wp_version, 'http://my.studiopress.com/?download_id=91046d629e74d525b3f2978e404e7ffa', $genesis_version ) );
    
    }
    

    And you know what? That sucks. It never checks for Genesis as the parent theme name, based on the assumption that only Genesis themes use the define of PARENT_THEME_VERSION which probably made sense a few years ago, but doesn’t anymore. And more importantly for this explanation, you can’t network activate it because unless you’re lucky enough to be running a Genesis child theme on the main site of your network, it won’t activate.

    Worse, it will throw errors on sites that aren’t.

    How I’d Fix It

    First I made a list of the action/function calls that require a Genesis Child Theme to be active in order to run properly: simplehooks_load_textdomain, simplehooks_init, simplehooks_execute_hooks

    Then I moved them all to their own section and wrapped them in a check:

    if ( simplehooks_can_run() ) {
    	add_action( 'plugins_loaded', 'simplehooks_load_textdomain' );
    	add_action( 'genesis_init', 'simplehooks_init', 20 );
    	add_action( 'genesis_init', 'simplehooks_execute_hooks', 20 );
    }
    

    What’s simplehooks_can_run? That’s a new function I’ve created to check for the requirements:

    /**
     * Can Simple Hooks Run
     *
     * This function checks if the requirements for Simple Hooks are met.
     *
     * @since 2.3.0
     */
    function simplehooks_can_run() {
    	
    	global $wp_version;
    	$my_theme = wp_get_theme();
    	$genesis_theme = wp_get_theme( 'genesis' );
    
    	if ( ( version_compare( $genesis_theme->get( 'Version' ), '2.1.0', '>=' ) && !is_null( $genesis_theme->get( 'Version' ) ) && !empty( $genesis_theme->get( 'Version' ) ) ) && ( $my_theme->get( 'Name' ) == 'Genesis' ||  $my_theme->get( 'Template' ) == 'genesis' ) ) {
    		return true;
    	}
    		
    	return false;
    	
    }
    

    What this checks is if the parent theme is 2.1.0 or higher and, if it is, if the theme or it’s parent is named Genesis. By having it use return I don’t have to check if it’s true or false, the if-check is smart enough for me not to do it explicitly.

    Finally I changed the if check in simplehooks_activation to look like this:

    	if ( !is_multisite() && !simplehooks_can_run() )
    

    What this isn’t doing is checking for WordPress 3.9.x anymore, as it’s 2016 and that was 2014 and I’m not worried about it. If I was, I’d toss && version_compare( $wp_version, '3.9.2', '>=' ) to the if-check in simplehooks_can_use to CYA.

    This also isn’t giving you an error on Multisite. That means if you network activate the plugin and, on Multisite, go to a site that does not have Genesis running, you don’t get an error. This is by design. There’s no point in telling a site-admin “Hey there’s this Genesis thing you can’t have because you’re not using it! NEENER!”

    I’m actually using this here on this site. If you’re interested at testing it out, grab it from my Github repo.

    Pull requests welcome.

  • Google Advertising Experiments

    Google Advertising Experiments

    In the time since I’ve gone back to Google Adsense, I’ve had issues with some of their ads. Mostly religion and politics. Big shocker, right? Every once in a while, Google suggest I allow those ads:

    Consider allowing ads from sensitive categories to increase auction pressure and improve performance.

    I usually discard the suggestion, but this time they tried something new to me.

    … you can allow these ads now, or run an experiment to help you decide.

    Experiment?

    There are only two types of experiments right now. One is ad units, where you can adjust templates and ad sizes. The other is what I’m doing, allowing and blocking ads. I clicked on the experiment button, and it set up an A/B test for me, tracking the clicks of each version of my site, to see if anyone actually clicks on those ads.

    Screenshot of the experiment page, showing nothing since it just started

    Initially there was an option to automatically pick the best one, but I don’t know if I want to. I do know that I want to actually see if anyone who reads my sites wants to see political ads.

    The reason I’d blocked them is they were showing right-wing crazy people on my sites, and I’m not that person. They were showing ads I would deem offensive (and you have to work hard to offend me) so instead of reading every single ad, I decided to block all of them, assuming I wasn’t hurting my income too much.

    After this experiment, I’ll circle back and make a more informed decision. I wish there were more things I could experiment on, like specific ads in specific locations, but this ability to just see if the ads are clicked at all is a nice start for a free product.

  • Debugging Unexpected Output

    Debugging Unexpected Output

    It’s going to happen one day. You’re going to get that weird error when you activate your plugin to test it and you will have no idea what it means.

    What error?

    The plugin generated 306 characters of unexpected output during activation...

    Unexpected output.

    The problem is WordPress doesn’t tell you what did it, where, or why, not even if you have debug turned on. You do have debug turned on, right? Well I was stumped on this one. I checked all my PHP calls to make sure I didn’t have whitespace, I looked for any files that were accidentally saved UTF-8, and I checked and double checked my diffs between the good and bad versions.

    What I ended up doing was writing a function that saved the error and output it.

    /* For debugging only */
    if (defined('WP_DEBUG') && true === WP_DEBUG) { 
        function myplugin_activated_plugin_error() {
            update_option( 'myplugin_error',  ob_get_contents() );
        }
        function myplugin_deactivated_plugin_error() {
            delete_option( 'myplugin_error' );
        }
        add_action( 'activated_plugin', 'myplugin_activated_plugin_error' );
        add_action( 'deactivated_plugin', 'myplugin_deactivated_plugin_error' );
        
    	function myplugin_message_plugin_error() {
    	    ?>
    	    <div class="notice notice-error">
    	        <p><?php echo get_option( 'myplugin_error' ); ?></p>
    	    </div>
    	    <?php
    		}
    	if( get_option( 'myplugin_error' ) ) {
    		add_action( 'admin_notices', 'myplugin_message_plugin_error' );	
    	}
    }
    

    That results in a pretty kind of output:

    A pretty version of my errors!

    I like to use the pretty display so I can easily read what, exactly I messed up and how.

  • EasyApache 4

    EasyApache 4

    While we use Ubuntu and Debian things at work, I have a CentOS server that is (as of today) on CentOS 7. Which means not only is it weird and uses yum, but it has cPanel and WHM installed.

    Over the last year or so, cPanel has been working on EasyApache 4 (EA 4). EasyApache is their … easy way to manage Apache and upgrade things. It’s an interface to help make things like your LAMP stack easier to comprehend, and it’s actually pretty nice. EA 3 has been around for a while, and it has serious limitations. Like you have to re-run EasyApache to upgrade PHP (always annoying), and you can’t have multiple versions of PHP. That means when you upgrade PHP to 5.6, everyone is upgraded to 5.6, and damned be the conflicts.

    This … was a problem.

    I have some older code that can use 5.6 but I’ve not been able to fully test it on 7. And I want 7. You don’t even know.

    The actual upgrade process is remarkably painless. I had two errors, one of which was my own doing (don’t try to use opcache if you don’t have opcache installed…) and one was math related. The majority of my settings ported over painlessly.

    AH00316: WARNING: MaxRequestWorkers of 40 is not an integer multiple of ThreadsPerChild of 25, decreasing to nearest multiple 25, for a maximum of 1 servers.

    Obviously the fix there was to change MaxRequestWorkers to 50.

    The interface itself is much nicer. It’s a modern design that is easy to look at with whitespace and tabbing that is natural. The only thing I didn’t like was I couldn’t tell it ‘Install PHP 7 and pick the same options as PHP 5.6 please.’ I ended up copying down what I’d selected for PHP 5.6 and then manually reproducing.

    The provisioning process took a little getting used to, after years of EA 3, but once I had used it a couple times, it felt natural. This can be said of all things. Embrace change, right? It’s also faster, which is very welcome. The longest part is the review process, where it checks for conflicts. This used to happen ‘inline’ with the old deploy, so moving it out just changes the when. I found I preferred it, since I didn’t think “And I’m done!” I knew I couldn’t go forward.

    Initially it installed suphp. I didn’t notice that’s what the default was and found all sorts of errors because of permissions. Errors like this:

    SoftException in Application.cpp:255: File "/home/public_html/index.php" is writeable by group
    SoftException in Application.cpp:613: Directory "/home/public_html/gallery" is writeable by group
    

    I actually knew the fix for this was to run the following in my public_html folder:

    find . -type f -name '*.php' -exec chmod 644 {} \;
    find . -type d -exec chmod 755 {} \;

    And yes, that solved everything. I was logged in as Ms. Groves root anyway, so I bounced through my users and ran it.

    But… did I want to stay on suphp? Turns out EA 4 only supports FastCGI with the FastCGI Process Manager (PHP-FPM), and while I’ve been using that for a while (instead of the dread mod_php). The problem there is that suPHP or CGI PHP handlers don’t support opcache. That meant I either had to suck it up and do the manual install for FastCGI or I could wait for v58 of WHM, which will have a UI.

    I opted to wait and stay on suPHP right now. The domains on my site are pretty fast, thanks to the SSD and a well optimized server. Load time did increase, I won’t lie, but it was pretty negligible. I don’t think it’ll really hurt things at this moment. I did some quick tests on GTmetrix and found my load time for sites on PHP 7 actually decreased.

    And that’s why I wanted PHP 7. It’s just faster.

  • Blocking Referrer Spam Server Wide Sucks

    Blocking Referrer Spam Server Wide Sucks

    A while back I talked about Referrer Spam in Google Adsense and I mentioned how you could block referrer spam with some .htaccess calls. That’s cool, but when you have 12 sites on a server, making this one more thing to manage per site is a pain in the ass. Well okay, what can we do constructively? And sadly the answer is “Not much.”

    First of all, forget the idea of using a robots.txt file. If they were real seo crawlers, they would honor this. They don’t and that’s how I know they’re evil.

    Secondly, this will only work if you have server wide access. That should be obvious, but server wide settings need server wide access, and that’s just how it is. I say that it sucks because it can be a little complicated and messy to understand where you put things.

    If you have your own server, like I do, then you can make a custom VirtualHost template

    Since I’m using Apache 2.4, I made local templates:

    $ cd /var/cpanel/templates/apache2_4/
    $ cp ssl_vhost.default ssl_vhost.local
    $ cp vhost.default vhost.local
    

    If you’re using 2.2 then the files are in /var/cpanel/templates/apache2_2/ instead. In each file, I added this to the top of the VirtualHost settings.

      RewriteEngine On
      RewriteOptions Inherit
    

    What that does is it tells Apache that it should inherit Rewrite rules from the main server. That means each virtual host (i.e. each website) will abide by any rules in the local settings.

    Where you put this in that file can be weird. I ended up looking for this section, and putting it right below:

    [% IF !vhost.hascgi -%]
      Options -ExecCGI -Includes
      RemoveHandler cgi-script .cgi .pl .plx .ppl .perl
    [% END -%]
    

    Put that in both files. Because you use HTTPS, right? Then you need to bounce httpdconf:

    /scripts/rebuildhttpdconf

    Since I’m using WHM, the next step is to go in to the Apache Configuration section and open the Include Editor. Then you want to add your blocking directive in ‘Pre-Virtual Host Include’ for All versions. If you don’t use it, you’ll want to edit /usr/local/apache/conf/includes/pre_virtualhost_global.conf and bounce Apache after.

    As you can see, I have some content in there already.

    My pre_virtualhost_global.conf file

    I added this below:

    <IfModule mod_rewrite.c>
      RewriteEngine on
      RewriteCond %{HTTP_REFERER} spammerseocompany\.com [NC,OR]
      RewriteCond %{HTTP_REFERER} keywords-monitoring-your-success\.com [NC]
      RewriteRule .* - [F,L]
    </IfModule>
    

    Does it work? Yes. It blocks ‘spammerseocompany’ from all my domains on my server. I put in the other URL since that’s the one they have that’s currently spamming the heck out of my stuff. There are a lot of other options with Apache 2.4, like sending them a 403 and so on. You should read up on using mod_rewrite to control access and pick the method you find most sustainable. For example, you could single like it:

      RewriteCond %{HTTP_REFERER} (spammerseocompany|keywords-monitoring-your-success)\.com [NC]
    

    I find that a bit clunky.

    If you’re using nginx, you’ll want this I believe:

    if ($http_referer ~* "keywords-monitoring-your-success\.com|spammerseocompany\.com") {
        return 403;
    }
    

    A big note of caution here. If your list gets too long, you’ll end up slowing your server down. A lot. So keep it as simple as you can. I find that CSF does a dandy job of blocking the most of my trouble makers, and I only need this for the unnamed spammerseocompany because they don’t abide by the common rules of robots.

    If, one day, they do, I will stop blocking them and allow their robots. As it stands, they’re idiots and need to go away.

  • How To Pick Your Webhost

    How To Pick Your Webhost

    This is not a real conversation, except it totally is.

    User: I want hosting.
    Me: What kind of site do you want to host?
    User: A WordPress site!
    Me: What kind of content do you plan on writing?
    User: Oh you know, blog stuff.
    Me: Okay… A food blog, a photo blog, a tech blog…?
    User: ​Why are you asking me all this!?!?!

    I’ve had so many conversations like this, I’m of the opinion that recommending hosting is a mugs game that simply cannot be ‘won’ so I generally don’t play.

    Then why am I presuming I can tell you how to pick a webhost? Because I’m telling you how to pick a webhost, not who the best webhost is.

    Preface

    Someone will hate every single webhost on the planet. I use Liquidweb and DreamHost. People hate both of those. There’s the bevy of EIG companies whom people will detest and lambast and accuse of shady actions to be listed somewhere. There are the millions of small companies. There are good and bad companies, and there are reasons to use them. Whenever someone asks what host to use, I remind them that someone will hate their choice. That’s okay, just don’t take it personally and I recommend you ignore people who simply jump on bandwagons to tell you “X SUCKS!” They’re not being helpful.

    Needs vs Wants

    I repeat this a lot in myriad situations. Your needs are what your website needs, which should be obvious. If you’re running WordPress you need a webserver than runs a modern version of PHP and a MySQL (or MariaDB) database. That’s it. But that isn’t all of what you need for a website, and to understand your needs you need to be very clear about your own abilities, your capabilities, and the time you’re willing to commit to your project. Running a website is very time consuming and stressful. You can’t just set it and forget it.

    Who Are You?

    We should all know who we are, what our skills are, and what we enjoy doing. I’m like playing with servers and code. My wife prefers practical experimentation (she makes cheese and mead). My father is a mathematician. We’re all writers of a sort, but of the three of us I’m the one who runs the website and puts of articles on the regular. This is not because the others can’t, but because they know who they are. My father sends me his articles to post, my wife posts her own, and I both write my own for me but for my company, and I maintain the servers (and email). If you’re not me, and don’t have a me, you need a me. That may be your host, and it may not.

    How Do You Communicate Best?

    Do you get anxiety with phone calls? Look for a company with live chat and email support. Do you hate live chat? Are you dyslexic? Look for phone support. You know how you like to communicate with strangers, so pick a host that has what you need. I personally prefer ticket based systems, unless my server is actually on fire. That hasn’t happened much.

    How Do You Add People?

    Let’s say you decide to hire someone to work on your website. Do they need access to the server? Do they need access to your billing? How do you do that without giving them your passwords? Find out how the host handles this. Can you simply add a technical contact or will there be more complicated steps?

    What Is Your Site About?

    Why does this matter? Well, think of it this way. “I want to make a community site where people from my city can come and post news, events, crimes, etc.” Did you just think about BuddyPress? You will likely need a bigger server than Shared. “I want a photoblog!” Okay you will need to seriously look at diskspace, which means SSDs may be a little tricky for you since most limit space. Check if the host allows easy upgrades. “I’m going to run a multisite network for my school!” You need a private server. Knowing what your site is about will help you predict upcoming hurdles.

    Do You Know Any Metrics?

    Most people, especially people with a brand new site, are going to say “No!” here and that’s okay. But if you do know things like how much traffic you get or how often you post or how much disk space you use, talk to the host about it. Pre-sales questions like “What’s the best hosting plan for a site that gets 2000 visits a day, and then 12k on one day a week?” are the bread and butter of a host. If they can’t answer it, move on.

    Does The Host Make You Feel Good?

    If you get a bad feeling from the host at any step along the way, you feel like they’re dismissive or maybe not a good fit, walk away. Look, you need to be comfortable with your host, and if the advertising practices of a host upset you, don’t use them. It’s that simple. Even if they’re the best for your needs, if they make you uncomfortable, you will be miserable. And remember, for every single host there will be people who hate them. That’s okay too. If it works for you, and you feel good about doing business with them, then that is really all that matters.