Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: mu-plugins

  • Per-Site MU Plugins

    Per-Site MU Plugins

    A great many moons ago, I handled my per-site MU plugins in a very straight forward way. I made a halfelf-functions.php file and checked for the blog ID with if ( $blog_id == 2 ) {...} and off I went.

    Now? I do this:

    global $blog_id;
    $helf_site_url = parse_url( get_site_url( $blog_id ) );
    $helf_file = plugin_dir_path( __FILE__ ) .'functions/'. $helf_site_url['host'] .'.php';
    if ( file_exists( $helf_file ) ) {
        include_once( $helf_file );
    }
    

    I have a folder called ‘functions’ and in there I have a file for every site that needs it’s own functions. This also let me clean up some rather old code I wasn’t using anymore, but it also let me add in code to include local CSS. Since I version control my mu-plugins folder, this allowed me to move my custom CSS from Jetpack to a normal CSS file.

    Why did I need to do that? Jetpack CSS doesn’t allow the fill param for CSS. Their current justification is that it’s advanced enough that people should be editing the theme. And mine is “But … why?” SVGs are becoming more and more popular, after all, and a number of plugins are allowing them. That means to style your SVGs, you’ll want to use CSS. And you can’t with Jetpack, which means you’re back to the old hell of editing your theme’s CSS. And that was something I wanted to avoid.

    You’d think I could do this:

    $helf_file_css = plugin_dir_path( __FILE__ ) .'functions/css/'. $helf_site_url['host'] .'.css';
    function helf_scripts() {
    	if ( file_exists( $helf_file_css ) ) {
    		wp_enqueue_style( $helf_site_url['host'], $helf_file_css );
    	}
    }
    add_action( 'wp_enqueue_scripts', 'helf_scripts' );
    

    But that actually didn’t work. No matter what I did, the result of $helf_site_url['host'] was empty. I know, right? What’s up with that.

    What’s up is me not thinking about how functions ‘know’ what they know.

    function helf_scripts() {
    	global $blog_id;
    	$url = parse_url( get_site_url( $blog_id ) );
    	$css_path = plugin_dir_path( __FILE__ ) .'functions/css/'. $url['host'] .'.css';
    	$css_url = plugins_url( 'functions/css/'. $url['host'] .'.css', __FILE__ );
    
    	if ( file_exists( $css_path ) ) {
    		wp_enqueue_style( $url['host'] , $css_url );
    	}
    }
    add_action( 'wp_enqueue_scripts', 'helf_scripts' );
    

    Inside the function, you see, it can’t see non-globals. So it wouldn’t work. If you’re not using Multisite, you don’t need to use $blog_id, but I don’t know why you’d want to use this if you weren’t using Multisite. The other silly moment was remembering that plugin_dir_path() would give me /home/user/public_html/wp-content/mu-plugins which would make the URL a relative URL, and not at all what I wanted. But using plugins_url() would give me an absolute path.

    Perfect.

  • Sidebar Login Widget

    Sidebar Login Widget

    This comes up a lot.

    The basic concept is you want to allow users to log in and out via a sidebar, and never see the admin-end of WP. There’s an awesome plugin called Sidebar Login that already does this, but I decided to play around and make a dead simple widget. There’s no ajax going on here, and very little code since it all calls the built in functions and filters.

    It lets you make a few choices, as to what verbiage you want to use, and if you want to show login/registration info or not. The registration link won’t work if you have registration turned off, natch.

    All the code is here at Hack: Sidebar Login Widget

    Really those hacks are more ‘mu-plugins’ that I don’t want to support, but still wrote, but you get the idea.

    I’ve taken to writing up the code, when I can, for people in the forums a little more, since it helps me as a developer get better with WordPress. I’m still new at wrangling widgets, so this was a new, and interesting, experience for me. That brought up questions for me, as to where people like the plugin ‘settings’ to be.

    [polldaddy poll=6676462]

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

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

  • Display Videos Shortcode

    Display Videos Shortcode

    This is a one-off, but it’s interesting to me so I’m sharing. I have a site with very pretty archives. It came with a video Custom Post-Type, but no archives for that type. Now I could have edited the theme, or overwritten the CPT, but I decided instead to embrace what I had and add on. What if I made a shortcode for [recent-videos] that showed me the recent videos?

    This code was specifically designed for the custom post-type ‘Videos’ in the News Theme by Theme Hybrid.

    add_shortcode('recent-videos', 'recent_videos_shortcode');
    function recent_videos_shortcode($atts) {
    
            extract( shortcode_atts( array(
                    'posts_per_page' => '10',
            ), $atts ) );
    
            $args = array(
                    'post_type' => 'video',
                    'posts_per_page' => $posts_per_page,
            );
    
            $vidlist = new WP_Query($args);
            if ( $vidlist->have_posts() ):
                    $return .= '<div class="display-vidlist archive" style="margin: 0 0 0 -20px!important;">';
                    while ( $vidlist->have_posts() ): $vidlist->the_post(); global $post;
    
                            $image = '<a class="image" href="'. get_permalink() .'">'. get_the_post_thumbnail($post->ID, thumbnail, array('class' => 'news-thumbnail')).'</a> ';
                            $title = '<h2 class="entry-title"><a class="title" href="'. get_permalink() .'">'. get_the_title() .'</a></h2>';
                            $date = '<div class="byline"><abbr class="published" title="'. get_the_date('l, F jS, Y, g:i a') .'">'. get_the_date('F j, Y') .'</abbr></span></div>';
                            $excerpt = '<div class="entry-summary"><p>' . get_the_excerpt() . '</p></div>';
                            $output = '<div id="post-'. get_the_ID() .'" class="hentry videos publish author-'. get_the_author_meta( 'user_login' ) .' has-excerpt">' . $image . $title . $date . $excerpt . '</div>';
                            $return .= apply_filters( 'display_posts_shortcode_output', $output, $atts );
    
                    endwhile;
    
                    $return .= '</div>';
            endif; wp_reset_query();
    
            if (!empty($return)) return $return;
    }
    

    The heavy lifting was formatting it to look right, and I’m not happy about my hack in class="display-vidlist archive" style="margin: 0 0 0 -20px!important;" but I also wasn’t 100% sure I wanted to separate the css just yet.

    Most people will need to change 'post_type' => 'video', to their CPT, and remove the style hack.

    I can already see where I’d extend this if I wanted to allow more arguments. The only one I put in was for the number of posts: [recent-videos posts_per_page=10] — You could easily add in one to allow ANY post type:

    function recent_videos_shortcode($atts) {
    
            extract( shortcode_atts( array(
                    'posts_per_page' => '10',
                    'post_type' => 'post',
            ), $atts ) );
    
            $args = array(
                    'post_type' => $post_type,
                    'posts_per_page' => $posts_per_page,
            );
    

    Then call [recent-videos post_type="video"] — Of course, if you do that, you should probably fork this into ‘Recent Posts Shortcode’ and rebrand recent-video to something else.

    Which you totally can do (this, as with all my code, is licensed GPL2).

  • WordPress: Change HTML Editor Font

    WordPress: Change HTML Editor Font

    Starting with 3.2, the WordPress HTML editor has become MonoSpaced. Yay! Problem is that it looks best on a non-Windows PC, so someone of my friends who happen to be Windows users have the grumpy.

    I made an htmleditor.php file and tossed it into my mu-plugins folder. You can use the folder in single and multisite WordPress, and it makes any php files in there act similar to your functions.php. I find it preferable since you don’t have to port to a new theme, should you change it. Read What is the MU-PLUGINS folder? if you need more help.

    <?php
    /*
    Plugin Name: HTML Editor
    Plugin URI:  https://halfelf.org/hacks/wordpress-html-editor-font/
    Description: I don't like the HTML editor Font on Windows
    Version: 1.0
    Author: MA Epstein
    Author URI: https://ipstenu.org/
    */
    
    function html_editor_admin() {
            ?>
            <style type="text/css">#content #editor, #editorcontainer #content, #editorcontainer textarea#content, #editorcontainer textarea, div#postdivrich.postarea #editorcontainer textarea#content { font: normal 13px/1.5 verdana !important; }</style>
    <?php }
    
    add_action('admin_head', 'html_editor_admin');
    ?>
    

    You can obviously change font: normal 12px/1.5 Monaco, monospace !important; to whatever you like.

    Enjoy!