Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: wordpress

  • Mailbag: Multisite Subdomains Live Where?

    Mailbag: Multisite Subdomains Live Where?

    Heather is confused, and I don’t blame her:

    I am want to use subdomains in my multisite. 1. Install WordPress in the subfolder and set it up to run from root before you create your subsites. 2. You should not use www in your URL ….. Where exactly do need to change this? Settings/ General ( that’s how i saw it in your book) or in my file manager, having to change it in many different files…. ( saw and read this from other internet sources).

    Let’s take this by the numbers.

    1. Install WordPress in the subfolder and set it up to run from root before you create your subsites.

    If (and that’s a big if) you want to install WordPress at example.com/wordpress but have the URL look like example.com then you must do this before you activate Multisite. Can it be done after? Yes. But you will go insane.

    1. You should not use www in your URL

    If you’re using subdomains, just don’t. The issue where WordPress breaks if you use the www here is not to do with WordPress so much as the variant hosts out there and how they handle the www/non-www redirects. Save yourself a headache. Don’t use www. You don’t use www. Yes, I know Google does. They don’t care so long as you’re consistent.

    In both cases, on your single site install of Wordpress, you go to the General panel. The value for Site Address (URL) is what you want people to see when they visit your site. The one for WordPress Address (URL) is where WordPress is installed.

    Make sure they both match in terms of schema and www. Then change the Site Address from http://example.com/folder to http://example.com and save it.

    The official directions are on the codex – Giving WordPress it’s own Directory. There’s a bit more when it comes to moving a couple files, but really that’s it. Once it’s done and working, go ahead and activate Multisite.

    By the way, I always get the WordPress Address and Site Address confused. It’s not just you.

  • Heartbeat API

    Heartbeat API

    For the longest time I didn’t really get the heartbeat API. I get the very basics of it, but it took me a while to understand what it was really doing.

    We’re used to interacting with our websites in a very one-directional way. I click a link, I go to a page. Heartbeat API is a bi-directional communication, which can best be translated as ‘shit happens without you having to click.’ The browser and the server are happily chatting to each other all the time, without me having to do anything.

    If you’ve ever used Google Docs or MS Word or Apple Pages and noticed you don’t have to press ‘save’ all the time, that’s the idea of a Heartbeat API. It does the background things for you. That thing you should do (save often). In WordPress, the most obvious thing that Heartbeat does is it saves your posts as revisions.

    That doesn’t stop neurotics like me from pressing ‘save’ all the time.

    Of course, this can get a little expensive, checking all the time, so the Heartbeat API is smart. It only checks every 15 seconds by default (you can change this), and it only checks when you’re on a page doing something. If you just leave a page open, it slows down and, after an hour, turns off.

    But besides saving, the Heartbeat API can share information between the systems. For example, it can ping out to Jetpack and check if it’s up and everything’s working, or if you have to reconnect your LinkedIn settings. And since it’s javascript based, it doesn’t reload the page.

    You can use it to alert logged in users to new content. Imagine a post that suddenly had an overlay of ‘This post has been updated…’ Doing that requires two parts:

    1. Hook into the send call and add your data
    2. Hook into the receive call and show the data

    Pippin has a great heartbeat API example but he also warns people:

    I’ve managed to bring down server servers by using the Heartbeat API on the frontend.

    If you trigger things to be called too often, you can totally crash a server.

    The Heartbeat API is a step towards making our sites really responsive and modular. Instead of statically checking via PHP if someone’s logged in and changing display based on that, Heartbeat can dynamically change on the fly. This would allow caching systems like Varnish or static-file caches like WP Super Cache, to save the cache and speed up your site while still being dynamic. It lessens the weight on wp_ajax_ and makes things work with caches, rather than bypass them.

    And that will make our sites beat faster for everyone.

  • Mailbag: Would You Review…

    Mailbag: Would You Review…

    From ‘anon’ in Orange County:

    Why did you review plugins at WCOC but you said no when I asked you to review mine?

    That’s not actually exactly what he said. I’ve cleaned up the English.

    At WordCamp Orange Country, I was given the rare opportunity to put value judgements on plugins. I never get to do this. I review plugins on WordPress.org every day (pretty much). I test them and evaluate them and send back comments. I look for bugs and security and guideline issues.

    What I never get to do is tell people how I feel about their plugins. So when WCOC asked me to judge the Plugin-a-palooza contest ala American Idol, I replied “Oh I’m Simon Cowell. I’m in.” And when Ryan Seacrest — I mean Chris Lema asked me why I agreed to do it, I said it was because I never got to be myself when I reviewed plugins. I never got to just review and tell people how I felt.

    They should have known. Right?

    The plugin that won was not the one I liked the best. The one I liked the best was small, it was simple (if a little complex with the code). It did one thing and it did it very well. It wasn’t perfect by any means, but it worked. That plugin came in second.

    The plugin that won, I wanted to like. In fact, I said that. I said “I really wanted to like this plugin.” And everyone went ‘oooooh’ (or possibly ‘boooo’). Chris jumped to my defense and pointed out I had warned them. So I detailed out why I didn’t like the plugin, from the UX perspective, and from the functionality. Some of why I didn’t like it weren’t it’s fault at all. It was trying to fix an imperfect system in a sensible way.

    And I was asked, in the session, if it mattered to me if the flaws in the plugin were the fault of core, the APIs, or the plugin.

    No.

    Look. When you make a plugin, you’ve made it knowing the world around you and knowing what’s already broken (or non-optimal). So when you’ve made decisions on how you handle things, I firmly feel that you should be graceful and reliable and fail intelligently. And I don’t think they did. I think they solved the main problem, but in doing so created a host of others.

    When someone asks me to review their code (theme or plugin) it’s like being asked if the pants make their butt look big. They want to hear “This is great.” I believe coding is as much art as math (and yes, I see the beauty in math), so it’s also a very critical and personal thing to be told that I don’t like this thing you’ve created. It hurts!

    But for the folks in plugin-a-palooza, they knew what they were getting into. Maybe they didn’t know it was with me, but they knew. They knew they’d be judged on merits and flaws. Most people who email me asking for those reviews don’t know that. They think maybe they’ll get a security review or a comment about how things could be better.

    What they’re going to get is how I feel about their work. Did the art speak to me? Did I get confused when I used it? Did I enjoy it? Do I think it did what it set out to do? Do I think it fixes the issues it claims to address?

    Most people really aren’t ready for the real answers. And as much as it’s nice to be able to be me for a while, I’m still always chained by the reality that my reviews come from someone who’s involved in the WordPress community. Just imagine my ‘testimonials.’

    So in the interests of not starting fights, not giving myself headaches, and not making everyone grumpy, I will decline to review your code today.

  • CloudFlare Code Muncher

    CloudFlare Code Muncher

    CloudFlare’s email protection butchered my code examples.

    Just putting that out there.

    What Happened?

    I went, perhaps ironically, to a post about changing your git repo URLs after activating CloudFlare, and was confused. See, I knew the code was something like me@mydomain.com:/path/to/repo but when I visited the page, it was all gibberish like this:

    /* <![CDATA[ */!function(){try{var t="currentScript"in document?document.currentScript:function(){for(var t=document.getElementsByTagName("script"),e=t.length;e--;)if(t[e].getAttribute("cf-hash"))return t[e]}();if(t&&t.previousSibling){var e,r,n,i,c=t.previousSibling,a=c.getAttribute("data-cfemail");if(a){for(e="",r=parseInt(a.substr(0,2),16),n=2;a.length-n;n+=2)i=parseInt(a.substr(n,2),16)^r,e+=String.fromCharCode(i);e=document.createTextNode(e),c.parentNode.replaceChild(e,c)}}}catch(u){}}();/* ]]> */
    

    I quickly edited the post and saw the content there was just fine. The only content that was getting munged was code output. It was very confusing so I googled and found a surprising answer.

    What Was Wrong?

    Turns out it was “Email Address Obfuscation” — a feature in CloudFlare that munges your email address to protect it from being scraped. In and of itself, that is ultra cool.

    I could wrap everything like this:

    <!--email_off-->
    
    <!--/email_off-->
    

    Or I could filter all the shortcodes… Or I could turn off “Email Address Obfuscation”

    I went with turning off the setting because it was faster, and it’s not like people cant deduce my email address. But if I was going to set it up, the fastest would actually be to filter all shortcodes, and that proved problematic.

    Why All?

    One of the problems is that I use Syntax Highlighter Evolved to handle my code chunks, and one of the things that plugin does is let me use a shortcode based on the programing language. That means the most efficient way would be to say “If this is a shortcode, wrap it in the email-off tags to tell it to shut up.”

    Can You Code It?

    This is theoretical and not fully tested. Use at your own risk.

    With embeds, you can do things like this:

    add_filter('embed_oembed_html', 'halfelf_embed_oembed_html', 99, 4);
    function halfelf_embed_oembed_html($html, $url, $attr, $post_id) {
      return '<!--email_off-->' . $html . '<!--/email_off-->';
    }
    

    But sadly there isn’t a wrap around like that for shortcodes, which means we have to do some serious filtering. There’s a global array called $shortcode_tags that lists all shortcodes (as you register them, so shall they be added), so I’m going to take that and replace their callback functions with my own. Then in my callback, I’ll keep their callback but at the same time I’ll wrap around it:

    function cloudflare_email_off_for_shortcodes() {
        global $shortcode_tags;
    
        $shortcode_tags[ $tag ] = 'cloudflare_email_off_html';
    }
    add_action( 'init', 'cloudflare_email_off_for_shortcodes', 99 );
    
    function cloudflare_email_off_html( $attr, $content = null, $tag ) {
        global $shortcode_tags;
    
        return '<!--email_off-->' . call_user_func( $shortcode_tags[ $tag ], $attr, $content, $tag ) . '<!--/email_off-->';
    }
    

    But that struck me as a little expensive when I considered how rarely I put email addresses in things in the first place.

  • Design for Multisite or DIE

    Design for Multisite or DIE

    I don’t mean you need to design all your code to have special Multisite features. I mean that if you’re not writing code to work on multisite, you’re probably doing a lot of things non-optimally and not fully WordPressy. When you write your code with Multisite in mind, you’re actually writing it with the basic tenants of WordPress itself. It forces you to think about how WordPress is used, how it might be used, and how you can be flexible and extendable.

    Let’s throw out the idea of network options and activation for a moment and consider the ways we can write our code to make it work for Multisite and the world. The truth is that if you’re coding ‘for Multisite’ in many ways your coding for WordPress in the best way possible.

    Calling Files

    There’s a time and a place for ABSPATH but it’s as a last resort. There’s a time and a place for get_bloginfo('url') but it’s not to call .'/wp-admin/admin.php either. Did you know admin_url() will get the url to the admin area using the right protocol (http or https) for you? And it works for Multisite. Instead of hardcoding your paths or assuming everyone has WordPress installed in the root of their website (they don’t), use the functions and template calls WordPress has created.

    Oh and stop supporting the old WordPress 2.x ways of determining folders. It’s 2015. We’re good.

    Saving Files

    Saving data to the disk means everyone can read it. Duh, right? Well, where do you save uploaded files? You use wp_upload_dir of course. That works on Multisite just fine. Instead, if you hardcode in /wp-content/uploads/myplugin/ then you’re saving things for everyone. If you’re not using the WordPress options to grab the upload directory, then your code won’t work on Multisite and everyone will be sad.

    This extends to where you save your cache files. Did you know there’s a plugin that saves the cache to the plugin folder itself? Besides the fact that the cache didn’t have a way to flush and grew to 700megs over the year the person used it, that cache was for all the sites in the network. All. Saving the cache to a unique location (I suggest /wp-content/pluginname-cache/siteID) prevents cross contamination of cache.

    Saving Options

    If you write a plugin that, to save its data, it creates a new DB table and saves it there, that can be okay. But if your plugin on update then drops that table and recreates it… That was not pulled at random, by the way, I was reviewing a plugin that did that. Instead he should have been using the function update_option() to create (and update) the options. And yes, it knows.

    But that’s an extreme, I admit. What isn’t an extreme is people creating their own tables. It happens a lot. And when they do, they often forget that we have $wpdb->prefix which means they force create wp_mypluginname instead of $wpdb->prefix . "mypluginname" … guess which one’s smart enough to know it’s on Multisite?

    (If you want to make a network table use $wpdb->base_prefix and use update site option for network wide options, yes, we know the naming conventions are weird.)

    Theme Customizer

    Not everyone can edit theme files. Not everyone can make child themes. On a Multisite, the only person who can do that is the Super Admin. Site Admins have no access to edit files or upload themes. Worse, if you make a change to a theme, everyone who uses that theme gets the change. What happens when a site wants a special header and your theme doesn’t allow those to be edited via the customizer? The customizer is there for a reason. Use it. At the very least make things hookable to allow plugins to do simple things like change footers. Please. Please. That’s one of the things that themes get wrong constantly.

    What Else?

    What do you think would be improved if people ‘coded for Multisite’?

  • Mailbag: Network Shared Media

    Mailbag: Network Shared Media

    Doug asks:

    On the WP Forums (at https://wordpress.org/support/topic/multisite-with-one-media-library) you posted this comment:

    Ipstenu (Mika Epstein) Half-Elf Support Rogue, Volunteer Forum Mod & Plugin Referee Posted 1 year ago # http://wordpress.org/plugins/network-shared-media/ Keep in mind, this is generally something that kills your site’s performance.

    Unfortunately, the thread is closed so I can’t ask you to elaborate through the forum. So can you elaborate via email reply on exactly where or how the “performance is killed” as a result of installing & activating the `Network Shared Media` plug-in? Thank you, -Doug

    The problem is that WordPress Multisite was built to be multiple separate sites. You used one install of WordPress, one install of all your themes and plugins, and one ‘user base,’ but outside of that, the sites are all separate. Which plugin is active is different, which theme is used is different, and most importantly your data is segregated.

    Your data includes your media.

    The concept of ‘sharing media’ is a great one. If you have a network, you would want to have a way to share all common media in a way that every site can call it and insert it. But the way most plugins (including the one mentioned above) go about it is by doing sql queries:

    $blogs = $wpdb->get_results( $wpdb->prepare("SELECT blog_id, domain, path FROM $wpdb->blogs WHERE site_id = %d AND public = '1' AND archived = '0' AND spam = '0' AND deleted = '0' ORDER BY registered DESC", $wpdb->siteid), ARRAY_A );
    

    The code, in and of itself, isn’t bad, but that’s just to get a list of sites on the network. Then you have to check if each user has access to upload files to the site. Then you have to use switch_to_blog to go to each site and load the images.

    What happens if you have a lot of sites and a lot of images?

    Your site is slow.

    We’ve made a lot of improvements on that end, but extensive DB queries when you have to cross paths like that can be ‘expensive’ on a computational level. Not to mention those large DB queries can cause headaches if you use database caching. All that data has to be generated and cached on every load. That too will slow your server down.

    Now this won’t always make your site slow, but if you use it and you end up with a slow site, I’m not surprised.

    The next logical question, of course, is do I have suggestions or alternatives? I don’t. I actually do suggest people use that plugin if they need shared media. Or I suggest they don’t use Multisite.