Half-Elf on Tech

Thoughts From a Professional Lesbian

Tag: coding

  • Customizing Author’s Comments on Genesis

    Customizing Author’s Comments on Genesis

    commentsI like Genesis, but I wanted to make some tweaks to how comments looked.

    1) Bigger Avatar Size
    2) ‘Mark’ post authors and site admins

    This was pretty easy, since they have a filter in for comments, so all I had to do what tell it to replace their avatar size with mine, and then to use my callback. It’s in my callback that I did an extra check. If the commenter is an admin, they’re labled ‘Site Admin’ and if they’re the post author, it’s ‘Post Author.’

    The end result looks like this (I’m commenting on a CSI episode where someone’s hiding in the walls):

    Example Comment

    The only hard part of the code was finding I can’t filter the comment callback, but I have to totally replace it with my own. Bummer, but not insurmountable. StudioPress has a nice document on comment filters which explained how I could override settings like avatar size and callback, which lead me to my next step, the filter:

    // Customize Comments for avatar size and MY callback
    add_filter('genesis_comment_list_args', 'mysite_comment_list_args');
        function mysite_comment_list_args($args) {
            $args['avatar_size'] = '90';
            $args['callback'] = 'mysite_comment_callback';
            return $args;
    }
    

    Once I have the filter, I have to create the mysite_comment_callback. This is something I basically copied from the source of my theme, taking the whole function for genesis_comment_callback and changing what I wanted.

    /** replace comment callback with my own **/
    function mysite_comment_callback( $comment, $args, $depth ) {
    
    	$GLOBALS['comment'] = $comment; 
    	global $post; 
    	?>
    
    	<li <?php comment_class(); ?> id="comment-<?php comment_ID(); ?>">
    
    		<?php do_action( 'genesis_before_comment' ); ?>
    
    		<div class="comment-header">
    			<div class="comment-author vcard">
    				<?php echo get_avatar( $comment, $size = $args&#91;'avatar_size'&#93; ); ?>
    				<?php echo ( user_can( $comment->user_id, 'administrator' ) ) ? '<span class="mysite-title">Site Admin</span>' : (
    						( $comment->user_id === $post->post_author ) ? '<span class="mysite-title">Post author</span>' : '' ) ; ?>
    				
    				<?php printf( '<cite><span class="fn">%1$s</span></cite> <span class="says">%2$s:</span>',
    						get_comment_author_link(), 
    						apply_filters( 'comment_author_says_text', __( 'says', 'genesis' ) ) ); ?>
    		 	</div><!-- end .comment-author -->
    
    			<div class="comment-meta commentmetadata">
    				<a href="<?php echo esc_url( get_comment_link( $comment->comment_ID ) ); ?>"><?php printf( __( '%1$s at %2$s', 'genesis' ), get_comment_date(), get_comment_time() ); ?></a>
    				<?php edit_comment_link( __( '(Edit)', 'genesis' ), '' ); ?>
    			</div><!-- end .comment-meta -->
    		</div>
    
    		<div class="comment-content">
    			<?php if ( $comment->comment_approved == '0' ) : ?>
    				<p class="alert"><?php echo apply_filters( 'genesis_comment_awaiting_moderation', __( 'Your comment is awaiting moderation.', 'genesis' ) ); ?></p>
    			<?php endif; ?>
    
    			<?php comment_text(); ?>
    		</div><!-- end .comment-content -->
    
    		<div class="reply">
    			<?php comment_reply_link( array_merge( $args, array( 'depth' => $depth, 'max_depth' => $args['max_depth'] ) ) ); ?>
    		</div>
    
    		<?php do_action( 'genesis_after_comment' );
    
    	/** No ending </li> tag because of comment threading */
    
    }
    

    Finally it was a simple CSS to make it look snazzy.

    .bypostauthor span.mysite-title {
    	padding: 2px 5px;
    	padding: 0.15rem 0.4rem;
    	font-size: 11px;
    	font-size: 0.785714286rem;
    	line-height: 1;
    	font-weight: normal;
    	color: #7c7c7c;
    	background-color: #FFFFCC;
    	background-repeat: repeat-x;
    	background-image: -moz-linear-gradient(top, #ffc, #fc3);
    	background-image: -ms-linear-gradient(top, #ffc, #fc3);
    	background-image: -webkit-linear-gradient(top, #ffc, #fc3);
    	background-image: -o-linear-gradient(top, #ffc, #fc3);
    	background-image: linear-gradient(top, #ffc, #fc3);
    	border: 1px solid #d2d2d2;
    	border-radius: 3px;
    	box-shadow: 0 1px 2px rgba(64, 64, 64, 0.1);
    	float: right;
    }
    

    I should point out that I have no experience with editing comments.

  • Genericons: Plugin’d

    Genericons: Plugin’d

    banner-772x250 The thing about all this is that I really like Font Awesome. The licensing drives me to drink. The WordPress Repository has an extra rule, saying everything there has to be GPLV2 or later, for reasons that aren’t the point. What is the point is that the moment Genericons came out, I knew that it should be a plugin, because a totally GPL-compatible version of a font like this was what people wanted.

    Since I also knew Rachel Baker had made a killer Font Awesome Plugin (and yes, that’s the one I use), I quickly stripmined its code and made Genericon’d.(At this point it’s pretty much a re-write, but I always credit where I started!)

    ZabooThe name is not Genericons because it’s not official, and they may want that name later. With that in mind, I thought “Well I totally Genericon’d them all!” because sometimes I talk like Zaboo from “The Guild.” I think of him as the Patron Avatar of this Plugin (though he’d probably ask why there wasn’t a Genericon for his staff, or Codex’s).

    So what are these ‘font icons’ things anyway and how do they work?

    Normally if you want to insert a Twitter image, let’s say, you would have to go find the image, download it, edit it to the right size, upload, embed. On the other hand, with a font you can do this: That will look like this: Isn’t that cool? All you have to do is include the font and the CSS in your site and you’re good to go. All those files are smaller than most images, load faster, and best of all, they scale better.

    [genericon icon=twitter size=4x] Same font, bigger size. Isn’t that cool? Since they’re pure CSS, you can do whatever you want, from changing colors and size to inserting into menus, like I did on another site. When you add in their relatively small file size and scalability, you gain and added level of awesome because your little icons always look amazing on retina displays too! After all, they’re just fonts.

    The alternative to something like this would be to use sprites, which is actually what WordPress uses today on your dashboard, and they look like this:
    WordPress's Menu

    If you go look at your WordPress dashboard, you’ll notice that hovering over these images makes them change between the dull grey and the cool colorized version. In order to do that, you have two images. Not so with Genericons! .genericon-twitter:hover {background-color:pink;color:purple;} would do the same thing (in pretty garish colors…). Just as an example of how it works, here’s a link with a Genericon in it: [genericon icon=twitter] @ipstenu. It’s actually kind of nice how it automatically adapts to the CSS I have in place for hovering over links.

    Basically the reasons to use icon fonts instead of images are that you can style them with CSS, they look good on all displays at any resolution, they easily adapt to fit your site when you change themes and colors, there’s only one HTTP call for the icons, and they’re open source.

    Here are some features in Genericon’d (as of version 1.2) that I think are kinda awesome:

    On the fly color changing.

    You can make a Twitter Blue icon: [genericon icon=twitter color=#4099FF] makes [genericon icon=twitter color=#4099FF]

    On the fly resize.

    You can make a Facebook icon bigger: [genericon icon=facebook size=4x] makes [genericon icon=facebook size=4x]

    And it all pretty much works the way I want it to. I did tweak the CSS a little to use em instead of px, which isn’t perfect. Genericons works best when your font is a derivative of 16, and for some reason, people still default to 12px. Protip: Ask someone with imperfect vision to look at your site. If they squint, your font is too small.

    Genericons, and any font-icon add-on, aren’t perfect for everyone or every site, but they’re here if you need ’em.

  • IE 8 and SVG Smilies

    IE 8 and SVG Smilies

    I don’t like the default smilies in WP. There, I said it. They’re old and busted, so I use the smilies_src to replace them with nicer ones. Recently it came to my attention how old and busted my cute PNGs looked on my iPad and any retina capable computer, so I fiddled around and decided SVG graphics were the way to go. They scale well, and they work on all modern browsers, yay!

    Oh, wait, IE 8 is not a modern browser and it’s pretty common out there… In fact my old job still uses it on a lot of PCs. And so does at least one user on this site (actually 5, and one more uses IE 6, for crying out loud!) so I came up with this:

    // Move Smilies
    add_filter('smilies_src','my_smilies_src', 1, 10);
    function my_smilies_src($img_src, $img, $siteurl) {
        $img = rtrim($img, "gif"); // Remove GIF
    
        if ( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 8' ) || strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 7' ) ) {
            $type='png';
        }
        else {
            $type='svg';
        }
        return 'http://domain.com/images/smilies/'.$img.$type.'';
    }
    

    That said, I wish we had more modern smilies available for WP. Finding a set that look okay (like the ones I have here) that are also retina capable are not easy. I could use user agents to go the other way, checking if the visitor was on a ‘new’ iPad or iPhone and show them retina that way, but to the best of my knowledge, there’s no way (yet) to do it so that a retina MacBook also gets the nicer view. With that in mind, I went just with SVG, which scale naturally and meet all of my needs.

    By the way, thank Otto for the smilies filter. You can use it for normal filtering too:

    add_filter('smilies_src','ipstenu_smilies_src', 1, 10);
    function ipstenu_smilies_src($img_src, $img, $siteurl){
        $img = rtrim($img, "gif");
        return $siteurl.'/images/smilies/'.$img.'png';
    }
    

    That’s what I use here.

  • Backwards Settings API

    Backwards Settings API

    backwardsThe biggest problem with documentation is that if you don’t think the same way the doc was written, the examples will frustrate you to the point where you want to cry. If you’re not techy at all, directions to move WordPress to a subfolder will piss you off. If you’re a basic webmaster, who can edit posts and maybe FTP, they’re scary but doable. It’s all a measure of leveling up and seeing things in a way you understand.

    Recently I was banging around with the Settings API in WordPress to fix some debug errors in a plugin. It took me about 5 hours to figure out what it was I was doing, and how to fix it. Actual fixing? About half an hour, including the time it took to make fresh coffee.

    What was my problem? I was looking at code from a different angle. If you start ‘right’ it’s really easy to follow tutorials, but when you start from an already functioning plugin and want to correct it, it’s a nightmare. Reverse engineering things isn’t easy. You’re used to looking at things in one way, and changing that is a headache. What I had was working, up until you turned on debug, which is why I got away with it for so long, and why I hated having to change it.

    But I did. I had a plugin admin page that let you enter two text strings, an access key and a secret key, which the rest of the code used to do it’s magic. Because of that, I couldn’t just be lazy and use a basic register_setting() call like this:

    register_setting( 'myplugin-retain-settings', 'myplugin-retain');
    

    That’s easy, you put it in, you call it with settings_fields('myplugin-retain-settings');, and you go to the races. But I have two strings, and if you call the settings fields twice, you’ll find all sorts of fun errors.

    To explain, let me show you what I did wrong, and what right is.

    Doing It Wrong

    <form method="post" action="options.php">
    <input type="hidden" name="action" value="update" />
    <?php wp_nonce_field('update-options'); ?>
    <input type="hidden" name="page_options" value="myplugin-accesskey,myplugin-secretkey" />
    
    <table class="form-table">
        <tbody>
            <tr valign="top"><th colspan="2"><h3><?php _e('MyPlugin Settings', myplugin); ?></h3></th></tr>
            <tr valign="top">
                <th scope="row"><label for="myplugin-accesskey"><?php _e('Access Key', myplugin); ?></label></th>
                <td><input type="text" name="myplugin-accesskey" value="<?php echo get_option('myplugin-accesskey'); ?>" class="regular-text"/></td>
            </tr>
    
            <tr valign="top">
                <th scope="row"><label for="myplugin-secretkey"><?php _e('Secret Key', myplugin); ?></label></th>
                <td><input type="text" name="myplugin-secretkey" value="<?php echo get_option('myplugin-secretkey'); ?>" class="regular-text"/></td>
            </tr>
    </tbody>
    </table>
    
    <p class="submit"><input class='button-primary' type='Submit' name='update' value='<?php _e("Update Options", dreamobjects); ?>' id='submitbutton' /></p>
    </form>
    

    Doing It Right

    <form method="post" action="options.php">
    	<?php
            settings_fields( 'myplugin-keypair-settings' );
            do_settings_sections( 'myplugin-keypair_page' );
            submit_button();
    	?>
    </form>
    

    Making Wrong Right

    As you can tell, there’s a huge difference between the two, and one is a lot easier to look at than the other.

    First you have to set up registering settings. Since I already had an admin action for my settings page, I wanted to just add to that:

    function add_settings_page() {
            load_plugin_textdomain(myplugin, MYPLUG::getPath() . 'i18n', 'i18n');
            add_menu_page(__('MyPlugin Settings'), __('MyPlugin'), 'manage_options', 'myplugin-menu', array('MYPLUG', 'settings_page'), plugins_url('myplugin/images/myplugin-color.png'));
    }
    

    I added this in(I’m using an array to isolate my plugin functions, so I don’t have to worry as much about namespace clases.):

            add_action('admin_init', array('MYPLUG', 'add_register_settings'));
    

    That was the easy part. The hard part is converting all my table information into settings. Making another new function, I want to add a setting section, just as you would for a one-off. But in this case I need to make a group. Since I named my settings field myplugin-keypair-settings, and my section myplugin-keypair_page, that’s the first important information I need. But backwards.

    First I have to add my section using add_settings_section():

    add_settings_section( 'myplugin-keypair_id', 'MyPlugin Settings', 'myplugkeypair_callback', 'myplugin-keypair_page' );
    

    Once you do that, you want to register the setting, just like normal:

    register_setting( 'myplugin-keypair-settings','myplugin-key');
    

    The complete function

    function add_register_settings() {
         // Keypair settings
            add_settings_section( 'myplugin-keypair_id', 'MyPlugin Settings', 'myplugkeypair_callback', 'myplugin-keypair_page' );
            
            register_setting( 'myplugin-keypair-settings','myplugin-key');
            add_settings_field( 'myplugin-key_id', 'Access Key', 'myplugkey_callback', 'myplugin-keypair_page', 'myplugin-keypair_id' );
            
            register_setting( 'myplugin-keypair-settings','myplugin-secretkey');
            add_settings_field( 'myplugin-secretkey_id', 'Secret Key', 'myplugsecretkey_callback', 'myplugin-keypair_page', 'myplugin-keypair_id' );
    
            function myplugkeypair_callback() { 
                echo '<p>'. _e("Once you've configured your keypair here, you'll be able to use the features of this plugin.", MyPlugins).'</p>';
            }
        	function myplugkey_callback() {
            	echo '<input type="text" name="myplugin-key" value="'. get_option('myplugin-key') .'" class="regular-text"/>';
        	}
        	function myplugsecretkey_callback() {
            	echo '<input type="text" name="myplugin-secretkey" value="'. get_option('myplugin-secretkey') .'" class="regular-text"/>';
        	}
    
    }
    

    imagesWhen I got around to the massive amounts of design I put into things, I ended up making a file called lib/settings.php where I stored everything related to the settings. For me, that’s easier to manage than one massive file with lots of different calls. Easier to debug and edit too, without panicing that I broke something.

    I don’t know if it was so much I think backwards, or the API was backwards, but whatever it was, I had a massive brain-block about all this for about a day. I really have to thank Kailey and Pippin for pointing me at examples that ‘clicked’ in a way that I suddenly could figure it all out.

  • Version Control

    Version Control

    ControlI’ve noticed a lot of people don’t really ‘get’ what version control is, or how it works. This is most evident when you watch the WP plugin repository.

    Around 400 commits are made daily to the repository, which doesn’t seem like a lot until you compare it to core trac commits. Now WordPress Core never commits until they’re sure the version in trunk is functional (since many of us use trunk on live sites), something most devs don’t have to worry about unless they use trunk as ‘live’… Let’s not talk about that.

    Instead of going into code today, I’m going to explain a little theory and talk about what version control is, why you want to use it, and how to use it.

    If you’ve ever saved a document, had MS Word crash, and come back to be asked what version of the document you want to restore, then you actually already have an idea of what version control is. You’ve possibly just never had to do it yourself. Version control is a very simple concept: saving versions of a file so you can go back to the older ones. Sounds easy right? Yes and no. Most people are accustomed to a different way of saving.

    Traditionally, we’re taught about saving as something you do regularly and often. After all, we’ve all lost that crucial document by forgetting to save. Apple has been changing this on us, having a much more robust auto-save process, and a better restore. It coaxes you into a place where you don’t think about saving anymore. There’s no save button on my iPad, and I actually use it to write a lot of the time. That freaks me out still, but so far it’s worked really well.

    In contrast, I have my coding. I sit and write, save a lot, test a lot, and when I’ve got a change that works, I commit my code. You see, version control is like a second type of saving. One save is me working, and one save is me ready for someone else to test. But the best thing about version control is how it saves changes. You check in code, and SVN (or Git), and the server checks the changes and records what changed in a way that is easy to read. Here’s an example picked at random from the hundreds I skimmed today:

    An example of a diff
    KatePhiz’s checkin of changed code

    See how beautiful that is? Right away you can see what changed between versions! You, and anyone else who wants to troll a revision log, can see what you changed, which makes it easier for people to write a change log for you (if you happen to work that way).

    Where I see the most people making mistakes with version control is missing out on the two rules you need to adhere to, if you want to use them effectively.

    1. Never Delete Files
    2. Trust The Tool

    That’s it. That’s all you have to do. I see a lot of people correct files by deleting them and uploading new versions. This is flat out doing it wrong, but I can see why people think it’s what they should do. You have to trust your tool, and know that it will see the new file, tell the differences and record that. If you delete a file, it stops you from being able to compare it to earlier versions and that’s a problem. Bug tracking becomes much harder, as you no longer have a quick and easy way to see what changed. Sure you can compare two files, but you’ve now put up a barrier for the next guy who picks up your code. What if she doesn’t have that previous version? What if she has no way to get to it, and you were hit by a bus and are in a coma? Or not. But still, building barriers between yourself and the next person is lacking foresight. Worse, you build barriers for yourself.

    It’s hard to trust the tool, and just as it took me months to get used to the iPad’s way of saving files, you have to get used to how version control saves things. This isn’t FTP where you’re always replacing a whole file, you’re making incremental changes. A check in is not a delete and replace (unless you’re using some of the horrific tools I’ve had the dubious pleasure of using in the past). Getting past that one hurdle will make your life much better with any tool you use.

    As for never deleting, I come to this from working at a bank. We never deleted anything. Ever. Not once. You always keep all versions of your code, even the broken stuff, because legally you had to. But in the end, I feel that was a great practice to get into. Disk space is cheap and you won’t ‘run out’ of space any time soon. I keep a copy of every plugin’s latest version on my hard drive, and I’m not out of space.(I don’t have SVN checkouts, that would be a little much.) Also there’s no point to deleting your older code, since they’ll just show up in SVN anyway. It remembers everything you checked in. Ever.

    Now, I cannot give you advice on the best way to tag or branch code, as each person comes up with their own methodology. I will say this: Don’t use ‘trunk’ as your stable releases on SVN. Git’s a little different, but I wouldn’t use it there either. Instead, use trunk as your playground. When you have a functional change, commit that minor change. When you have a major change and it’s ready to go, tag it and release it. In that way, your beta testers can safely use trunk, and your normal users never get hurt. By the way, making frequent commits may feel like a smart move, but you don’t need to. Check in a working copy. Oh and don’t go back and edit your tagged versions, unless it’s a very minor change. Someone is sure to have downloaded it, just tag a new version and go forward. As I always explained to people at the bank “You don’t go backwards with code, you go forward.”

    I don’t expect this to be a perfect primer on how to use version control, nor was it meant to be, but I hope I demystified it a little. If you have great primers for people on SVN or GIT, aimed at first time users, please share them!

  • Multisite Stands Alone

    Multisite Stands Alone

    NKOTBWhile I wrote up a lot of reasons why you shouldn’t use Multisite, the truth is I really like it and find it well suited to my needs. But one of the big problems with it is that everyone’s network setup is different. Many times, when people ask for help in the forums, I have to sketch out the bare ideas of what to do and why. This brings people to their biggest complaint in Multisite: Why isn’t there a plugin for this already?

    First and formost, Multisite is still ‘new’ for the mainstream. Thelonius, the 3.0 release, is only two and a half years old! WordPress 1.0 came out in 2004, just as a reminder. 3.0 is when Multisite was folded into full WordPress, and it’s not been there very long, but it’s changed a lot since the start. In 2010, when 3.0 came out, there were 10,000 plugins in the repository. Today we’re at 22,000 and growing every day. When it comes to single site WordPress, the plugin world is mature and populated. Of those 22,000, about 300 are specific for Multisite. That’s a pretty small number when you look at the over 1000 plugins that do something with Twitter. Of course, most plugins work with Multisite anyway, but the ones that are Multisite specific are the ones to look at here.

    A plugin is developed to fit a need. A good developer tries to keep the plugin simple and adaptable, so as many people as possible can use it for as many situations as suit their needs. Doing that has a lot of weird scope creep, of course, and if you consider that we do have 1000 twitter related plugins, you may understand why. Plugins fit a need, and when they don’t we extend/fork/hack the plugin to fit our specific need. Multisite, in and of itself, is fitting a need, and while that need is very specific, it’s also very broad. There are myriad reasons to use Multisite, and because of that, those 300 plugins that are built specifically for Multisite have to meet all of our needs. Of course, that’s not how it works.

    While the majority of themes and plugins work just fine on Multisite, the ones people get in arms about are the ones that are supposed to be ‘for’ Multisite. These plugins should do more, but not too much. They should meet my specific needs, as well as all of yours and hers and his too. There should be a plugin for everything. Why am I the only person who wants this? I walk away from those arguments a lot, or I point out “You’re not the only person who wants it, but you’re possibly the only person who wants it in that way.”

    Plugins are not the silver bullet for everyone. Your site may be a werewolf, mine a zombie, and his a vampire. Each one has their own needs and because of that, their own requirements. So let’s be direct. The whole reason you can’t find the perfect plugin is because no one’s a mind reader. The reason you can’t find everything you want in one plugin is because you didn’t write it (or have it written).

    What does that mean? Multisite is still young, and those 300 Multisite specific plugins aren’t all Multisite specific first of all. At least a third are listed as Multisite because they work on Multisite. For example, bbPress is tagged ‘multisite’ but it wasn’t built ‘for’ Multisite. On the other hand, Networks for WordPress is built for Multisite, and nothing else.

    The best way to tell if a plugin is built just for Multisite is to see if it set ‘Network:true’ in the code. If you open up the code of the plugin, you can see this in the header:

    Now, not all Multisite plugins are meant to be Network enabled, but only plugins that are for Multisite will be Network only like that, so it’s one way to make sure that plugin is intended for Multisite. The downside to that is expressed via something like BuddyPress, which if you use on a Multisite must be network activated, but you don’t have to use it on Multisite. This means the check isn’t perfect.

    NKOTB 2010The point to all this is that Multisite’s still the new kid in town. It isn’t perfect, and it is still evolving and changing in pretty dramatic ways. Also, I find it pretty cool to watch it grow. But the reason you can’t find all the plugins you want with it is really simple: They haven’t been written. You may actually be the first person who wants something done in that specific way, and with the myriad new methods Multisite gives us to do amazing things, there’s a lot of room for different options.

    What should you do if you’re not a coder and want something that’s never been done? Well, learn to code. Or hire a coder. I wish there was another way, but when you want that special one-off toy that really isn’t suitable for everyone, you’re going to need to meet the challenge head out. None of this is meant as an excuse, by the way, but an explanation. It’s just not done. Yet.