Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: wordpress

  • HTTPS and WordPress

    HTTPS and WordPress

    Really there’s a right way and a not-quite-as-right way to handle HTTPS on WordPress. It’s not that hard to do, and if your whole site is going to be HTTPS, then the easiest way is to change your home and site URLs to be https://example.com/ and put define( 'FORCE_SSL_ADMIN', true ); in your wp-config.php file. Then you should (if this is an existing site) search your database for the old HTTP url and change that to HTTPS.

    Seriously, that’s it. That tells WordPress to be HTTPS all the way and you’re done. Of course, that doesn’t actually work 100% for everyone, because there are some silly plugins and themes that do things like this:

    add_action('wp_enqueue_scripts', 'enqueue_google_maps');
    function enqueue_google_maps() {
      wp_enqueue_script('google-maps', 'http://maps.googleapis.com/maps/api/js?&sensor=false', array(), '3', true);
    }
    

    The problem there is they’ve defined the script as HTTP and if your site is HTTPS then you’re going to get mixed content messages. And the real issue here is that means your connection is only partially encrypted! That non-encrypted content is accessible to sniffers and can be modified by man-in-the-middle attackers. This, clearly, is not safe anymore. The right way to do your enqueues is with protocol relative URLs:

      wp_enqueue_script('google-maps', '//maps.googleapis.com/maps/api/js?&sensor=false', array(), '3', true);
    

    Alternately you can just use the HTTPS url, because that won’t break HTTP visits and it won’t make anything less secure.

    But. Since you really can’t go in and edit all your themes and plugins, the plugin WordPress HTTPS is the way to go. That can force everything around. I know it’s not updated in a long time, but it still works. I keep thinking I’ll fork and clean it up… Well in my free time. The point of that plugin is that it lets you force everything to HTTPS, and will rewrite things on the fly. It’s a good idea.

    Instead of using the plugin, I’ve seen a lot of people do this in their .htaccess:

    RewriteEngine On 
    RewriteCond %{SERVER_PORT} 80 
    RewriteRule ^(.*)$ https://example.com/$1 [R,L]
    

    In and of itself, this isn’t wrong. This forces everything HTTP to redirect to HTTPS. The problem is you’re still actually sending data from WordPress over HTTP first, and you’re right back to opening up to man-in-the-middle attacks because the data from WordPress goes from HTTP first and that’s, say it with me kids, insecure!

    Now that said. This should be okay for most things. The POST calls should be sent securely, and all you should see on the return end is everything after that 301 redirect, but we can’t be absolutely sure about this. My buddy Jan used mod_substitute to force HTTPS (back before he moved to nginx). His code looks like this:

    <Location />
     AddOutputFilterByType SUBSTITUTE text/html
     Substitute "s|href="http://example.com/|href="https://example.com/|"
     Substitute "s|href='http://example.com/|href='https://example.com/|"
     Substitute "s|src=\'http:|src=\'|"
     Substitute "s|src=\"http:|src=\"|"
    </Location>
    

    In doing this, he doesn’t need to worry about the HTTPS plugin I mentioned, because it forces everything with a src attribute to be protocol relative. He also doesn’t have to search/replace his content if he doesn’t want to, which makes switching back easier. If you wanted to do that. But as Jan pointed out to me, he switched to nginx because it’s easier and supports variable substitutions.

    Should you use .htaccess or nginx to force https instead of a plugin? That’s totally up to you. I use the plugin since I trust it to only mess with WordPress and not anything else I may have lying around. Also since my domains are often more than just WordPress, it’s a little easier for me to segregate their control. The flip side to this is that WordPress doesn’t redirect http traffic.

    By this I mean if you turn your whole site to HTTPS properly, you can still go to http://example.com/this-is-a-page/ and WordPress will load it as HTTP. This is and is not a bug. WordPress is (properly) trusting your server to tell it what it should be. Your server is saying “Be HTTP or HTTPS! Whatever!” Now there is a trac ticket to have FORCE_SSL really force SSL but that’ll be a while because there are a lot of complications in that change.

    So yes, for now, I would use .htaccess to add an extra later of SSL forcing, but with a bit of caution. If you’re proxying HTTPS (like you’re on a Varnish cache behind something like Pound or nginx) then you may need to use this code for your .htaccess redirect.

    RewriteCond %{HTTP:X-Forwarded-Proto} !https
    RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R,L]
    

    The reason for this is Apache can’t always see SSL if it’s not in charge of it (because it’s proxied or handled by a load balancer), and to teach it where it really lives. The trick there is the code I just showed you may not be right because every server’s a little different. There’s a great StackOverflow post on the problems of redirect loops while forcing https that you should read.

    Good luck, and safe HTTPSing!

  • Mailbag: Finding A Rogue WordPress Setting

    Mailbag: Finding A Rogue WordPress Setting

    After helping someone track down a weird WordPress setting, he asked the logical question:

    How did you even find that!?

    The issue was that a person was missing the menu option to edit their themes. I asked if they were also missing the menu option for editing plugins. As soon as he said yes, I knew it had to be the define to disable the plugin and theme editor:

    define( 'DISALLOW_FILE_EDIT', true );

    That literally says “No editing files!” So we looked first in the wp-config.php file for it and came up empty. Now as much as we yell at people for editing functions.php or at themes for creating a mess of settings that aren’t needed, I knew the fastest way to find it was this:

    $ grep -R 'DISALLOW_FILE_EDIT' ./wp-content/
    

    And as expected, that gave me a file: ./wp-content/plugins/ninjafirewall/lib/firewall.php

    Since we had wp-cli, I opened that file and looked for the term:

    // Disable the plugin and theme editor ?
    if (! empty($nfw_['nfw_options']['disallow_edit']) ) {
           define('DISALLOW_FILE_EDIT', true);
    }
    

    Then I ran this: wp option get nfw_options

    If you don’t have wp-cli, just pop into the database and look at the option value for nfw_options — either way you’ll see this:

    array (
      'logo' => 'https://www.example.com/wp-content/plugins/ninjafirewall/images/ninjafirewall_75.png',
      'enabled' => 1,
      [...]
      'disallow_edit' => 1,
      [...]
    )
    

    I’ve snipped out a lot of the data, but you can see that disallow_edit is set to 1.

    We had the user change that setting. Imagine that. It worked!

    The moral of the story? Don’t make settings changes without reading what they do!

  • Mailbag: Headers Already Sent

    Mailbag: Headers Already Sent

    Yasha from Russia asks for guidance!

    Hi I was searching on ways to resolve get header error in WP and saw your posts, which helped a chap with his website. I am a total beginner and having a nightmare with a divi template I am trying to upload. I have tried a ton of solutions on line and nothing worked. I would be grateful if you could provide me with some guidance. Unfortunately I am not in a position to pay you, but should our path cross I would be happy to offer you a few fine Belgian beers. Thank you in advance

    I don’t drink beer (I can’t stand fizzy drinks, I know, it’s tragic).

    I have to preface this with the honest truth. I hate Divi Templates. I’ve reached out to them under my company hat a couple times, never heard back, but I cannot stand their theme because of the first line in header.php for every single theme I’ve ever seen from them.

    <?php if ( ! isset( $_SESSION ) ) session_start(); ?>
    

    Pardon me while I rage flip a table.

    Why do I hate this? Sessions aren’t friends with caching. A session is used to store information for a user and have it accessible across all the pages of your website. Cool, right? The problem is a session is also saying “This user gets unique content and should have a unique experience.”

    Which kinda tells caching, and specifically Varnish caching, to take a long walk. WPEngine doesn’t allow you to use them because of that.

    But all that aside, how do you debug that Headers Already Sent?

    1. Turn on wp_debug
    2. Read the error
    3. Kill the plugin (or theme) causing it

    I hate to say it’s that simple, but it usually is.

    Warning: Cannot modify header information - headers already sent by (output started at /example.com/wp-content/themes/applesororanges/functions.php:60) in /example.com/wp-includes/pluggable.php on line 962
    

    That error means the problem is in the theme applesororanges and you check by swapping themes.

    When you get around to these, it’s a bit messier:

    Warning: Cannot modify header information - headers already sent by (output started at /example.com/wp-includes/functions.php:3560) in /example.com/wp-includes/pluggable.php on line 962
    

    The bit in ‘output started at…’ is a wp-includes folder! It’s unlikely core has bad code, so here you have to turn off all the plugins and switch to a default theme. There’s a reason that’s the way we debug, by the way. It’s hands down the fastest way to see if it’s you or not.

    If turning off all the plugins fixed it, great. Now turn them back on, one at a time, until you break it again.

    Remember! Sometimes it’s the combination of the plugins and theme that caused the problem, so be ready to pick a second best theme or plugin.

  • Mailbag: Delete A New Page In Multisite

    Mailbag: Delete A New Page In Multisite

    From Brige:

    If u can, could u tell me how I can get rid of a new page that created in a subfolder from multisite ? out of my admin reach now. What would be the fastest way ? Should I restore completely to get rid of all WP remnants in order not to fall into this multisite hooking error : “page not found”?

    To be honest, I’m guessing here.

    I’m going to assume that Brige means he wants to auto-delete the ‘Sample Page’ page that WordPress generates when you make a new site.

    WordPress creates a default post (id – Hello World) and a page (id – Sample Page) when a new WP site is created, be it Multisite or not.

    Probably the simplest way would be to hook into wpmu_new_blog() which runs for all new blogs and run this:

    wp_delete_post(2, true);

    That force deletes the post with the ID 2. And since that’s always the sample page, that should work.

  • Static Content Subdomain

    Static Content Subdomain

    I use a lot of different tools to run my websites, and over time I’ve learned what I want is to have my static content, the files that are uploaded and are images, stored separately from my apps. So while I have the basic folders on my domain (wordpress, wiki, gallery) I have a special subdomain called static.example.com for all those images and videos.

    There are a few reasons I do this. First, I like having my images separate. Second, it allows me to establish a cookie-free subdomain for images and that shuts up YSlow’s check.

    Create The Subdomain

    Do this however your host allows. Keep in mind that some don’t allow you to traverse domain folders. If your host creates your domain as /home/user/example.com and subdomains as /home/user/static.example.com you may have to fight a little more with things depending on your setup. If possible, I prefer to put the subdomain folder inside the main web root.

    If you’re using cPanel, by default you get your static subdomain installed at /home/user/public_html/static which is how I like it. This is perfectly accessible by all things but it’s also browsable at example.com/static/ and we don’t want that. Applying a little .htaccess magic will solve this.

    # CDN
    <If "%{HTTP_HOST} == 'example.com' ">
            RedirectMatch ^/static/(.*)$ http://static.example.com/$1
    </If>
    

    Now we’re ready to go!

    Move WordPress Uploads

    This used to be really easy. Go to Settings -> Media and change things. But we removed that to stop people from blowing themselves up. Now there are a couple ways about it. I jumped right over to editing the options by going to wp-admin/options.php and look for upload_path and upload_url_path.

    Setting image location options

    I change upload_path to /home/example/public_html/static/wordpress which is where I’ve moved all my images. Then upload_url_path becomes http://static.example.com/wordpress and I’m done except for fixing my old posts. It’s actually pretty neat that once I put those paths in, the Media Settings page lists them as editable.

    Fixing the old posts takes a little trick though, and you’ll have to search/replace your posts via the database:

    UPDATE wp_posts SET post_content = REPLACE(post_content,'http://example.com/wp-content/uploads/','http://static.example.com/wordpress/');
    

    Or in wp-cli:

    wp search-replace http://example.com/wordpress/wp-content/uploads http://example.com/wordpress
    

    The gotcha here is that since I use SSL for my administration, I had to set up a new certificate for the static domain. Not a big deal right now since I can set up a self-signed, or use StartSSL until Let’s Encrypt is off the ground. It is something to consider though.

    Move ZenPhoto Uploads

    I have to start by warning you that Zenphoto doesn’t like this. When you install it, it puts your images in an albums folder, in the Zenphoto gallery install. This isn’t so bad, but you actually can move it around. You have to look in your zenphoto.cfg.php file (found in zp-data). The default location for your albums is defined by this:

    $conf['album_folder'] = '/albums/';
    $conf['album_folder_class'] = 'std';
    

    Since I want it in the static location, I tell it my folder path based on ‘web root’ and that its ‘in_webpath’ (which tells ZenPhoto to look in the root and not relative), by changing that section to this:

    $conf['album_folder'] = '/static/gallery/albums/';
    $conf['album_folder_class'] = 'in_webpath';
    

    But that means my URLs for images become http://example.com/static/gallery/albums... and I wanted http://static.example.com/gallery/albums... instead. Thankfully the .htaccess rule I used at the beginning of all this covers me there. Looking into this, I understand this is the case because unlike MediaWiki or WordPress, ZenPhoto only has one ‘location’ setting. The other two have path and URL.

    MediaWiki

    This was … weird. Technically all you have to do is set up the folders and change the following values in LocalSettings.php:

    $wgUploadPath       = "/static/wiki";
    $wgUploadDirectory  = "/home/example/public_html/static/wiki/";
    

    The thing that’s weird is that the documentation says you can do this:

    $wgUploadPath       = "http://static.example.com/wiki";
    

    And when you do, the image URLs properly call from the domain name. They just won’t load. When you dig deeper, it turns out that it’s caused by the settings for responsive images. The way it puts in srcset doesn’t seem to like this. So for now I’ve disabled it and my setup is this:

    $wgUploadPath       = "http://static.example.com/wiki";
    $wgUploadDirectory  = "/home/example/public_html/static/wiki/";
    $wgResponsiveImages = false;
    

    End Result?

    All my uploaded content is on my ‘static’ subdomain, separate from everything else, which makes version control even easier. Also now if I ever decide to move things off to a CDN, I’m pretty well set up.

    The real reason I do this is that while some of my content is uploaded via the content management systems I use (WordPress, ZenPhoto, etc), the majority is not. ZenPhoto, for example, is faster to FTP up a gig of images than it is to use a PHP tool. Ditto videos. And because of them, it’s nice to have a separate location I can give access to without allowing someone full rights on all my tools.

  • Image Compression

    Image Compression

    If you’ve ever tested your site on Google PageSpeed Insights, GTMetix, Yahoo! YSlow, or any of those tools, you may have been told about the value found in compressing images.

    Google Pagespeed has some images for me to optimize

    There are some images you can fix, like the first one on that screenshot is for an image from Twitter I downloaded. There are some you can’t fix, like the last three are all telling me the default smilies for WordPress need some shrinking.

    Either way, the short and skinny of it is that if you make your images smaller then your webpage loads faster. I know, it’s shocking. Many long-term webheads know that you can compress images best on your own computer, using ‘Save For Web’ and other command line tools for compression. That’s great, but that doesn’t work for everyone. Sometimes I’m blogging from my phone or my iPad and I don’t have access to my tools. What then?

    Before You Upload

    I know I just said but what about when you can’t resize before you upload. There are things you can do for this. Photo Compress for iOS will let you make your images smaller. So can Simple Resize. There are a lot of similar apps for Android as well.

    For the desktop, I use Homebrew so I installed ImageMagik (which is also on my server for WP to use) and toss in a command line call for it. Sometimes I’ll use grunt (yes, Grunt, the same thing I use for Bower and coding) and ImageOptim to compress things en masse.

    Of course, if I only have one or two images, I just use Preview which does the same thing more or less. Photoshop, which is still stupid expensive, also lets you do this, but for the layman, I suggest Preview for the Mac. I haven’t the foggiest what you can use on Windows.

    If you’re not uploading images via WordPress (and very often I’m not), you pretty much have to do it old-school.

    While You Upload

    Okay great, but what about WordPress?

    The best way about it is to have WordPress magically compress images while you upload them. And actually it does this out of the box. My cohort in crime at DreamHost, Mike Schroder, was part of the brain trust behind making ImageMagick a part of core WordPress. This was a massive undertaking, but it allowed WordPress to compress images better, faster, and more reliably than GD. I hesitate to say it’s ‘safer’ since the image loss (that is that weird fuzzing you get some times) is less.

    If you want to make it even better, you need to use plugins. I used to tell people to use smush.it which was a Yahoo! run service. But then they deleted it and we were all very sad. WPMU Dev, who owns a SmushIt plugin, installed Smushing on their servers and you can now use WP Smush. I’m a bit of a fan of TinyPNG, which gives you 500 free compressions a month, and that’s enough for me. I like TinyPNG because there are no options. I install it, it runs when I upload images, and done. That doesn’t mean I don’t see value in things like ShortPixel, just that it’s not really what I want. Finally there’s Kraken IO which I love just for the name, but it makes people balk because it’s not free.

    If you don’t want to use an external service, and I totally get why you wouldn’t, there’s EWWW Image Optimizer.

    I personally use either EWWW or TinyPNG, depending on the site.

    Can a CDN Help?

    Maybe. I know a lot of people love offloading their images to CDNs. I currently don’t for no reason other than I’m a bit lazy and I hate trusting someone else to host my images. But that said, you actually can (rather easily) use a CDN if you have Jetpack installed. Their service, Photon, does exactly that. Now, I don’t use Photon because my users in Turkey and China like to visit my site, but there’s nothing at all wrong with those services.