Half-Elf on Tech

Thoughts From a Professional Lesbian

Category: How To

  • Command Line WP

    Command Line WP

    In my new job, there’s a lot of command line work to be done. DreamHost has a mess of scripts I’m getting my comfort with, but also they’ve got this cool thing implemented on a lot of their servers called wp-cli, and that’s what I’m going to talk about today.

    wp-cli is a command line interface to do a lot of sneaky snazzy WP things. While most people are running towards the GUI world of pretty UI and clicks, some of us really like command lines because they’re fast. I mean, I wrote my own command line upgrader just because I wanted to (and was having PHP permissions woes at the time). Command line is just something server people are always going to like, much like people who love driving a stick-shift, or who want to hand-make their own dough for pies. We like to have that extra level on control.

    Aside from being control freaks, however, we CLI jockeys are also insanely lazy. If we can get everything done without having to touch the mouse, or lift our hands from the keyboard, we’re happy. If we can automate things so that all the WordPress installs on a server are magically upgraded in one fell swoop, we’re ecstatic. We all dream of being that guy who walks into a room, presses three keys, and saves the day. (I’ve been that guy, but remember he comes at a cost. I’ve also been the guy who presses three keys and reboots the money trading servers in the middle of our busiest time. Read twice, press enter once.)

    Where wp-cli takes off is in the speed you can perform basic tasks. Typing wp or wp help will get you a list of commands. If you try to run any command outside the WP folders, you’ll get a nice error message. Using Multisite, you have a cool advantage of installing a plugin once and updating it for all your sites. But in cases where you need to have things separated, wp-cli fills the void by letting you script updates. Imagine just writing a simple shell script to upgrade your plugins on all sites?

    Some of you perked up. There are a lot of cases where you don’t want to run Multisite (separate users, special code, whatever), and updating multiple sites under those custom installs really can be a pill. wp core update can be easily scripted to run off a list of your installs, or to just trawl through your directories, look for WP, and update when it’s there.

    Installing

    If you want to install this just on your own account, the directions for installing are on the wp-cli page. But me, I wanted it on my server for all my accounts. Obviously my DreamHost server has it, but this site is still on LiquidWeb (for myriad reasons, one of which is the same as why I didn’t bank at the company where I worked, old habits).

    Their directions are, via git, to install in ~/git/wp-cli, which I don’t want. I decided to put it in /usr/share/wp-cli/ and to do this I just su’d into my root account. Otherwise I could do it all prefacing with sudo, but I’m dangerous like this.

    My first hurdle was the issues I’ve had on git before, simply put the damn thing times out. The fix was so stupidly simple, once I really read into how git works. All I had to do was tell it ‘Use https.’

    git config --global url."https://".insteadOf git://
    

    Suddenly my commands started working and I was able to run the install directions (modified a little):

    git clone --recursive git://github.com/wp-cli/wp-cli.git /usr/share/wp-cli/
    cd /usr/share/wp-cli/
    utils/dev-build
    

    This ran without a hitch. And any update for this, since I’m only ever using trunk, will be as easy as git pull now and then.

    Now on my server, when I try to run certain commands I git this:

    Fatal error: Out of memory (allocated 38797312) (tried to allocate 17 bytes) in /home/userID/public_html/wp-includes/widgets.php on line 635
    

    Two important things to note.

    1. This only happened on one of my accounts.
    2. 37 Megs is a real weird amount of memory.

    I happen to know I usually allocate 64M for my PHP processes, but even bumping this up to 128 didn’t change the fact that at 37M, everything crapped out. I happen to work with one of the leads on wp-cli, and Mike (aka GetSource) let me bounce ideas off him. He offered to help with any questions, but I learn best by doing, so once I sorted out the basics, and was still stumped, I appealed to his greater familiarity. By the time I logged off to clear my head and get dinner, we decided it had to be user permissions. After all, every account on the box used the same PHP instance. Every account had the same rights, etc. It had to be something funny about the profiles, which I’d buy since this server has some accounts that are 15 years old, and it’s the oldest one having the most issues.

    When I picked it back up a day later, I learned something surprising. At first I could get this to run every time on a site that has bbPress, but then I discovered any time I ran a big search (like wp theme status on my multisite, which worked for all other commands), it would also fail. So clearly there’s a memory shenanigan running around here. I tested with and without APC, switched back and forth between PHP handlers (fCGI, suPHP, DSO), and I tried bumping the memory all the way to 128M. Nothing would get me past the weird 37M. In desperation, I changed my php Memory limit to -1. This means no limit. And now it failed on 32M. As I started testing various possibilities, I came across a moment where I set-faulted (this would be from APC cli, don’t use it) and finally grabbed Alex Rabe’s WP Memory Usage, which tells me I was using “Memory : 8.3 of 128 MByte” on the plugins page, so I know WP knows it can have 128M. This lead me down a path of ‘What PHP is CLI using?’ After digging around and verifying it was the same, I started looking at how I’d locked down my server.

    This is where I started banging my head on my keyboard.

    Shell Fork Bomb Protection is a cool thing, in that it stops people from running rough-shod over your server. Of course they way it does this is by restricting the processes you can run via shell. And wp-cli is, say it with me, shell. Once I turned it off, everything worked. I’m not sure if this is something I’d want to do for every server, but since I can count, on one hand, the number of people with access to mine, and I know their passwords are secure, I’m okay with it.

  • Multisite Per Site Registration

    Multisite Per Site Registration

    This post is dedicated to TJ List, who donated to help me get to WCSF. He’s the last post of this ilk, so I’ll stop having these announcements, but I wanted to say thank you all, one more time. My new job starts the 27th, and you all helped!

    Edit: If you want a plugin, see Join My Multisite

    Sometimes people want a way to sign up for the network on specific sites, and not go back to the main site. And I often tell people ‘You need to make a custom page template with the code from the signup page in it.’

    But how? There’s going to be a lot of code in this post, so at the end I’ll give you a link to the whole file you can download and play with. We’re going to go through the steps, however, since we may not be using the same theme, and you’ll need to understand the process.

    Make your Page Template

    First you make a new page template. I always call mine page-template-signup.php because well named files/code don’t need as much inline documentation.

    Since I wanted to build this off of TwentyTwelve, I grabbed the full page template, and pulled that over:

    <?php
    /*
    Template Name: Signup
    */
    
    get_header(); ?>
    
            <div id="primary" class="site-content">
                    <div id="content" role="main">
    
                            My Content Here
    
                    </div><!-- #content -->
            </div><!-- #primary .site-content -->
    
    <?php get_footer(); ?>
    

    Obviously on a first pass, nothing much is going on here. The next step is to open up wp-signup.php and take a look. There’s a lot going on here, but we don’t need all of it.

    First let’s look at what we need to add to the header area. Most of this is just styling and a little tweakage to stop search engines from thinking people need to really find this page, so let’s add the following right above get_header();

    add_action( 'wp_head', 'wp_no_robots' );
    
    // Fix for page title
    $wp_query->is_404 = false;
    
    function wpmu_signup_stylesheet() {
    	?>
    	<style type="text/css">
    		.mu_register { width: 90%; margin:0 auto; }
    		.mu_register form { margin-top: 2em; }
    		.mu_register .error { font-weight:700; padding:10px; color:#333333; background:#FFEBE8; border:1px solid #CC0000; }
    		.mu_register input[type="submit"],
    			.mu_register #blog_title,
    			.mu_register #user_email,
    			.mu_register #blogname,
    			.mu_register #user_name { width:100%; font-size: 24px; margin:5px 0; }
    		.mu_register .prefix_address,
    			.mu_register .suffix_address {font-size: 18px;display:inline; }
    		.mu_register label { font-weight:700; font-size:15px; display:block; margin:10px 0; }
    		.mu_register label.checkbox { display:inline; }
    		.mu_register .mu_alert { font-weight:700; padding:10px; color:#333333; background:#ffffe0; border:1px solid #e6db55; }
    	</style>
    	<?php
    }
    
    add_action( 'wp_head', 'wpmu_signup_stylesheet' );
    &#91;/php&#93;
    
    Just below <code>get_header();</code> we're going to add <code>do_action( 'before_signup_form' );</code>
    
    Then in the 'My Content Here' section, you're going to copy everything from <code><div id="content" class="widecolumn"></code> down to <code><?php do_action( 'after_signup_form' ); ?></code> and put it in there. It's a lot of code, I know. I'm not including it here because of that. Again, check the attached file.
    
    Finally search your file for all instances of <code>wp-signup.php</code> and change them. To what? To whatever you're going to name your page in the next section. I knew I wanted to name my page signup, so I replaced it with that.
    
    <h2>Make Your Page</h2>
    
    <a href="https://halfelf.org/wp-content/uploads/sites/2/2012/08/page-template.jpg"><img src="https://halfelf.org/wp-content/uploads/sites/2/2012/08/page-template-300x222.jpg" alt="Picking Page Template" title="Picking Page Template" width="300" height="222" class="alignleft size-medium wp-image-2509" /></a>Next you make a page. This is easy. You go in to your site, you make a page (I called mine Signup) and you put in <em>no</em> content. Pick the page template called 'signup' and save. I always opt to turn off comments and pingbacks on this page for what I hope are obvious reasons. Don't bother putting in any content to the post. Because we didn't leave in the loop, it wouldn't display.
    
    If that's something you want, then you would leave the loop info in where I had 'My Content Here'
    [php]
    
                            <?php while ( have_posts() ) : the_post(); ?>
                                    <?php get_template_part( 'content', 'page' ); ?>
                                    <?php comments_template( '', true ); ?>
                            <?php endwhile; // end of the loop. ?>
    

    That’s an ‘as you like it’ sort of thing. If you need to leave messages, etc, it’s great.

    And that’s kind of it. Oh, you’ll want to mess with your CSS, but that’s all you need to get started! It even keeps you on the page.

    How it looks…

    Since there are multiple registration options, here’s how they look:

    With Registration Disabled

    User accounts may be registered

    Logged in users may register new sites

    Only Logged In Users Can Make Sites

    Both sites and user accounts can be registered

    Adding Users to Sites

    I know, I said we were done. There’s one more thing. What happens if you want that per site registration to automatically add people to the site they’re on? That is, if someone goes to halfelf.org/signup/ I want them to be added to halfelf.org as a user. The problem with this is when you register for a user account, you may have noticed there’s an ‘extra’ step to confirm. This is where you get that email that says ‘click here…’

    The ‘good’ thing is the URL you get looks like this https://halfelf.org/wp-activate.php?key=0ef92965187a50be and it will take you back to the right site to login! The ‘bad’ thing is it doesn’t actually add you to the site. It will add you any time you create a site, but if you just make a login ID, you get this:

    No Access Is Bad

    As you can see from that URL, it’s sending me back to wp-activate.php, which is something we can’t change in our signup template. If you know you want to add all users to all sites, then you want Multisite User Management, but that isn’t always the case. So what do we do? Option one is to grab a plugin that makes us approve all users, then we can add them as they’re requested. But you don’t want to do manual work, I’d guess.

    The trick is to add an action onto user registration, but only run it per site. So you’d want this in an mu-plugin, and since halfelf happens to be blog , I do this:

    <?php
    global $blog_id;
    if ( $blog_id == 2 ) {
    
      function helf_activate_user( $user_id, $password, $meta )
      {add_user_to_blog( '2', $user_id, get_site_option( 'default_user_role', 'subscriber' ) );}
      add_action( 'wpmu_activate_user', 'helf_activate_user', 10, 3 );
    }
    ?>
    

    That says ‘Hey, if I’m on blog ID 2, when people register, kick them to be a subscriber on this blog. I have mine in a plugin called halfelf-autoregistration.php and it works rather nicely. If someone registers on ipstenu.org, even if they try to login to halfelf, they can’t login because their registration process was on the other site.(I suppose if someone was clever, they could take https://halfelf.org/wp-activate.php?key=0ef92965187a50be and change it to https://ipstenu.org/wp-activate.php?key=0ef92965187a50be to register there, but there’s no change in ‘risk’ between being a network psudeo subscriber and a real subscriber. If I was adding in editors, I’d probably change my mind here and manually validate every new user. I’m trusting in the fact that most people aren’t that clever.)

    Do you have any tricks that help you do this?

    Oh and here’s the file to download. It’s in .txt for security reasons.

    Download Here

  • Capital H Dangit

    Capital H Dangit

    My new gig at DreamHost comes with a minor ‘d’oh!’ and that is it’s a capital H. Which I seem to be incapable of remembering. So I wrote a function. I stole capital_P_dangit() and swapped the WordPress for DreamHost. To save myself from embarrassment, here it is:

    // Capital H in DreamHost
    add_option( 'helf_capital_H_dangit', 'yes', '', 'yes');
    
    if ( get_option( 'helf_capital_H_dangit' ) == 'yes' ) {
        foreach ( array( 'the_content', 'the_title', 'comment_text' ) as $filter )
            add_filter( $filter, 'capital_H_dangit', 11 );
    }
    
    function capital_H_dangit( $text ) {
        // Simple replacement for titles
        if ( 'the_title' === current_filter() )
            return str_replace( 'Dreamhost', 'DreamHost', $text );
        // Still here? Use the more judicious replacement
        static $dblq = false;
          if ( false === $dblq )
            $dblq = _x('&#8220;', 'opening curly quote');
          return str_replace(
            array( ' Dreamhost', '&#8216;Dreamhost', $dblq . 'Dreamhost', '>Dreamhost', '(Dreamhost' ),
            array( ' DreamHost', '&#8216;DreamHost', $dblq . 'DreamHost', '>DreamHost', '(DreamHost' ),
          $text );
    }
    

    Now. Here’s where it gets fun. No ‘hacks’ posts will be affected by this code! Otherwise how would I show it to you here? Normally this is where you would just run remove_filter( 'the_content', 'capital_H_dangit', 11 ); in the functions file for your theme. Due to the way I’ve wrapped my various functions into mu-plugins, the down and dirty way was to wrap the above block of code with a check for if ( $blog_id != 2 ) { { ... }.

    Most of the time you won’t care about things like this. I just needed it so I could demonstrate code. I’ve done the normal filter remove here so I can also say ‘Wordpress’ in my code related posts. For proof this works, I assure you, 100%, that I typed in ‘Dreamhost’ over in my post about quitting my job and going to work for them.

    Sorry about that, Simon!

  • My Custom PostTypes Live in MU

    My Custom PostTypes Live in MU

    This post is dedicated to Boone Gorges (aka ‘WP Boone’ to me), who donated to help me get to WCSF. My brother is also named Boone, so even if WP Boone wasn’t so awesome, I’d like him.

    Brain - You must useCustom Post Types. I really dig them, as a great way to make ‘kind of’ pages, without making a million pages. They don’t ‘order’ as well as pages, and default to publish date, but really that could be adjusted. The point, and I have one, is that they’re often a great alternative to Multisite, and I use them a lot.

    There are lots of plugins that can make these for you, but I prefer to do it myself in a function file, becuase it gives me more flexibility for what is, let’s face it, a complicated sort of thing.

    In this example, I’m going to make a ‘drawing’ custom post-type, like the one I just added to my photoblog. First I made a file called photo-cpt.php and in it put a header:

    <?php
    /*
    Drawing Name: Photos CPTs
    Drawing URI: http://photos.ipstenu.org/
    Description: All Photos custom code.
    Version: 1.0
    */
    ?>
    

    Notice I am not telling you to put this in a functions file. I never put my CPT in my theme’s function, becuase I always make my CPTs able to work with any theme. By making it a stand-alone ‘plugin’ file, I can put it in mu-plugins and run it automatically. More on this in a minute.

    The code itself is split into two sections. I learned this method from Justin Tadlock, who has a nice, if very techy, primer on Custom Post Types in WordPress. I freely admit, once I figured this code out, I saved it off line and copy/paste it where I need, replacing the terms (Drawing/s) for what the new CPT is.

    <?php
    	add_action( 'init', 'create_photos_post_types' );
    
    	function create_photos_post_types() {
    
             /* Labels for the Drawing post type. */
            $drawings_labels = array(
                    'name' => __( 'Drawings', $domain ),
                    'singular_name' => __( 'Drawing', $domain ),
                    'add_new' => __( 'Add New', $domain ),
                    'add_new_item' => __( 'Add New Drawing', $domain ),
                    'edit' => __( 'Edit', $domain ),
                    'edit_item' => __( 'Edit Drawing', $domain ),
                    'new_item' => __( 'New Drawing', $domain ),
                    'view' => __( 'View Drawing', $domain ),
                    'view_item' => __( 'View Drawing', $domain ),
                    'search_items' => __( 'Search drawings', $domain ),
                    'not_found' => __( 'No drawings found', $domain ),
                    'not_found_in_trash' => __( 'No drawings found in Trash', $domain ),
            );
    
            /* Arguments for the Drawing post type. */
            $drawings_args = array(
                    'labels' => $drawings_labels,
                    'capability_type' => 'post',
                    'public' => true,
                    'has_archive' => true,
                    'can_export' => true,
                    'query_var' => true,
                    'rewrite' => array( 'slug' => 'drawings', 'with_front' => true ),
                    'taxonomies' => array( 'post_tag', 'category'),
                    'supports' => array( 'title', 'editor', 'excerpt', 'thumbnail', 'custom-fields', "photos-post-settings" ),
            );
    
            /* Register the Drawing post type. */
            register_post_type( apply_filters( 'photos_drawings_post_type', 'drawings' ), apply_filters( 'photos_drawings_post_type_args', $drawings_args ) );
    	}
    ?>
    

    Looking at this, it’s actually surprisingly straightforward what I’m adding and where. The weird code of $domain is a variable I’ve defined elsewhere, and lets me translate if I need to. I probably won’t but it’s a good practice to get into. By splitting out my labels into their own variable, I’m able to break them up and make it more readable. As Otto says, good code doesn’t need inline documentation becuase it’s readable. You can see the names, and the fields, I’m adding, and they magically become self-explanatory. Then in my drawing arguments, I again make a variable with the settings. Pull in the complex labels, then I can break out the next arguments into something readable.

    Trucks and Buses Must Use Low Gear You can read all the various options in the codex article for register_post_type(), which is the function I finally call at the end.

    If you wonder why I have the whole thing wrapped in an action, it’s becuase in other places I actually add multiple post types to a site. This lets me put them all in one action, call it once, and walk away. As long as each CPT has a label, arguments, and registration, they’ll all run.

    Below that action, I have one to add my CPT to my ‘right now’ section on the dashboard. I got this from James Laws over at WP Ninjas, and really it’s one of my favorite things.

    <?php
    // Adding to Right Now
    	add_action( 'right_now_content_table_end', 'photos_right_now' );
     
    	function photos_right_now() {
      
              // drawings
              $num_drawings = wp_count_posts( 'drawings' );
              $num_p = number_format_i18n( $num_drawings->publish );
              $text_p = _n( 'drawings', 'drawings', intval($num_drawings->publish) );
              if ( current_user_can( 'administrator' ) ) {
                $num_p = "<a href='edit.php?post_type=drawings'>$num_p</a>";
                $text_p = "<a href='edit.php?post_type=drawings'>$text_p</a>";
              }
              echo "\n\t".'<tr class="first">';
              echo "\n\t".'<td class="first b b-drawings">' . $num_p . '</td>';
              echo "\n\t".'<td class="t drawings">' . $text_p . '</td>';
              echo "\n\t".'</tr>';
    
    	}
    ?>
    

    Taking a step back, there’s this interesting line in my arguments:

    'taxonomies' => array( 'post_tag', 'category'),
    

    All this does is say ‘I want to use post tags and categories in my CPT.’ And in this case, it’s the same ones as I use for my normal posts. You can do a lot more with it if you wanted, but I believe in KISS.

    To loop back around, however, why do I put this in an mu-plugin? First and formost, it’s portable. No matter what theme I use, it comes with me. As I talk about this method in No Children Necessary, it really comes into play here more than anywhere else. On a single, traditional, WP install, I just toss it in and walk away. It’s code, I don’t want my end-users playing with it, so a non-editable file is perfect. For Multisite, I really just add if ( $blog_id == 2 ) { ... } around the whole thing. I could do it just on the actions, but this is easier for me. I can see right away ‘Oh! Site 2.’

    This is obviously not going to work for everyone, but sometimes just looking at the next option will give you a new idea.

  • Mountain Lion and SVN

    Mountain Lion and SVN

    Caveat: You need root access on your Mac to do this!

    Ages and ages ago, when I first was using MAMP and all that fun stuff, Apple didn’t include a version of SVN. I had installed, and promptly forgotten about, my 1.4.4 install sitting out there. Now, I know I upgraded it to 1.6.something at some point, but I only found out that was wiped out when I went to svn up some code on my site and it all died. My version of SVN was too old.

    svn --version was coming back as 1.4.4 and I knew that was wrong. I complained on Twitter, and Eric Hitter pointed out that Xcode has SVN (and Git) so I went and installed that. It didn’t work, I was still stuck on 1.4.4.

    After checking that, indeed, svn was located at /Applications/Xcode.app/Contents/Developer/usr/bin/svn, and that ran the right version, I deleted 1.4.4 manually by removing the following folders:

    /opt/subversion
    /usr/local/bin/svn*
    /Library/Receipts/Subversion*
    

    Then I made a fast alias ln -s /Applications/Xcode.app/Contents/Developer/usr/bin/svn svn over in /usr/local/bin/ to redirect my scripts, and finally I followed the directions from Panic to fix Coda, and changed the Subversion tool path setting in the Files pane of Coda’s Preferences to /Applications/Xcode.app/Contents/Developer/usr/bin/svn. I also changed git to /Applications/Xcode.app/Contents/Developer/usr/bin/git and made a fast link for that too, since I can.

    Have a happy weekend!

  • No Children Necessary

    No Children Necessary

    This post is dedicated to Michael Fields, who donated to help me get to WCSF. I envy him his Portland.

    All Children left unattended will be sold to the circus.Not all of my sites use child themes. In fact, most of them don’t. I work on about 20 WordPress sites and of them I have five child themes, one of which is an unedited child from the theme dev. Even when I have custom-post-types, I rarely need to mess with a child theme, unless it’s needing a special template or page design. That means that most of my child themes are a style sheet, a functions file, and one or two new pages. When I do have to make a child theme, I do my best to make it reusable as much as possible. I have the same child theme on two sites, but they look nothing alike.

    But generally, when someone tells me they need to edit a theme, I tell them how to make a child theme, which I fully endorse, but also to step back. Do you really need a child theme? See most people make a child theme to customize their site, and since that’s pretty much what they were invented for, it shouldn’t be a bad thing. But sometimes people are using a child theme for the wrong thing and they ignore all the built-in ways to customize a theme.

    The only reason you need to use a child theme is when you have to add a new template, or replace one that cannot be hooked into.

    That’s it.

    Before we get into this, I’m going to point out that if you are using a Theme Framework, this is not for you. A theme framework is something designed for you to build a child theme off of. This post is for people who use TwentyEleven and want to make it a little special, or even a lot special, because most of what you want to do is something in CSS anyway. Yes, I did just say most of what you’re doing with a child theme can be done with CSS. The rest of it can usually be done with widgets, and after that there are some plugins to help you out.

    Ready to customize your theme without a child theme? Here we go.

    Themes Have Options

    It’s 2012, and the majority of themes have options. Some have too many, but pretty much every theme has some options. The default theme has some basic options. People may call them simple, but these options are huge to make your site just a little different. A single column, no sidebar, TwentyEleven is automatically a different feel than the generic sidebar site. It puts the concentration on your content, which is king, and pulls it back to the importance of it. If you’re running a documentation or essay site, that’s what you want. Most themes also have header options, to pick your text, color, and image, as well as background images and colors. The new theme customizer lets you actually do almost all of that in one go, making it even easier.

    Remember. All cars have wheels, windows, and doors: it’s how they’re arranged and styled that attract most people.

    I know I said I wasn’t going to mention Theme Frameworks, but themes like Genesis, and even ones like Hybrid, often build their themes with powerful options that let you use them without having to make your own functions files. More on how you don’t need that later.

    It’s just CSS

    No Children AllowedMost of what people want to change is CSS. I said it before, I’ll say it again. If you want to change the color of your site, and it’s not included in the theme options, you want to end your CSS. But how, I hear you ask, without a child theme? WordPress.com Custom CSS (aka Safe CSS) will let you edit your site’s CSS without making a child theme. You can’t use all CSS, there are some moz-radius things that don’t seem to work, but other than that, you can totally change up your site.

    CSS is more than just colors. CSS can format your text, move your divs, and completely customize your layout, all with just a few lines. Change the one column from a skinny one to a fat one, indent your paragraphs, and add whitespace to your header without any text. Everything can be moved.

    Neglect not your menus

    Customize your menus. You can add images and styles to your menus, and you should to make them look like anything you want. Yes, this goes back to CSS, but you’d be amazing how many people just leave them alone. First, remember to customize your menu to look like anything except that list of pages. Change it up right away, and then add in design and style to stand out. The menu is supposed to catch your reader’s attention and direct them where you want to go. Don’t slack off.

    Widgets, Widgets, Widgets, Widgets, Widgets, Widgets, yeah!

    Do not ignore the power of your widgets. Your widgets control your sidebars in most sites, but also your footers. People think of them as just a way to toss in twitter and search. You can use the amazing, incredible Widget Logic to control when and where a widget shows, to make different pages show different information. An alternative, if you’re really good at php, is the impressive PHP Code Widget, which will let you put any PHP in widget and customize it on it’s own.

    The most powerful widget in your arsenal, however, is the text widget. Text drives your site in so many ways, a simple text widget can hold any information, from contact information to a haiku. You can put anything in a text widget, HTML, inline CSS, your special code. Text is insanely powerful and you shouldn’t forget it.

    Want to use shortcodes in your widgets? We can do that too with two lines of code:

    add_filter( 'widget_text', 'shortcode_unautop');
    add_filter( 'widget_text', 'do_shortcode', 11);
    

    Normally this would go in your functions.php in your theme, but hang on, we’ll get to where to put that in a minute.

    Conjunction Junction, Don’t Use Functions

    Here’s where a lot of people demand they have to use a child theme. They need to add in functions, like the overriding filters and actions in their parent theme. I very, very, rarely use a functions.php file in any child theme, because I hate having to replace them if I ever switch themes. Instead, I make use of mu-plugins.

    Generally I end up with three files:
    customposttypes.php
    functions.php
    themename.php

    Unattended children will be given espresso and a free kittenObviously, the first one is for my Custom Post Types. They all live there happily. The second is for anything and everything I’d put in that theme function file. It’s important for me to keep the general functions separate from the theme specific ones, however. In fact, while I originally said I made a ‘subchild’ theme for Genesis’ Balance theme, I’m now using the CSS (mentioned above, SafeCSS), and two MU plugins: ipstenu-functions.php and ipstenu-balance.php. That’s right, all my tweaks, everything I did, are there. I’ve done the same for this domain, and all other sites except for photos. Why? Photos has a CPT that needs a custom template.

    On subsites of a network, I wrap my mu-plugin with if ( $blog_id == 2 ) { ... } to ensure it only gets called on that subsite. For the theme, $theme_name = get_current_theme(); and if ( $theme_name == 'Origin' ) { ... } within. Be careful, the theme name is the name, not the slug, so ‘Balance Child Theme’ and not ‘balance’ is what you want. Even straight up theme related actions like add_action('genesis_before_footer', 'ipstenu_before_footer'); work without a hitch. That leaves me with (at most) three ‘plugins’ for each site, and usually not even one. If I wanted to be really lazy with Genesis, I could do most of it internal with a plugin to do it on the dashboard instead.

    You can do it all without children

    Really the point is that of all the children theme possibilities on this network, the only one that exists is the one that needed it’s own special template. I certainly wouldn’t do this for all sites, but once you pull all the theme specific data out of your functions file, there’s often very little left. When you can do this, you retain a little extra flexibility in that your changes are easy to swap out between themes.

    At the end of the day, it doesn’t make things easier or harder, just different.

    Put all your non-theme-specific changes into a mu-plugin. Put your CPTs into another. See what’s left. You may be surprised.