Archive for the ‘Social Media’ Category

Better Includes and Excludes for wp_list_pages

The wp_list_pages() template tag forms the navigation core of most WordPress-powered websites, but it has a few issues:

  1. The exclude_tree parameter doesn’t work. If you include a list of page ID numbers after “exclude_tree=” in your wp_list_pages() tag, all of those pages (and all of their child pages) are supposed to be excluded from the page list. However, only the first page ID actually works this way; the others are ignored.
  2. There’s no such thing as an include_tree parameter.

That second one really became a pain working on a non-profit site recently. After I turn the site over, I want the director to be able to add and move pages whenever he wants without it breaking the nice drop-down menus I worked so hard styling for him.

The Function

That’s where this handy little function comes in. It adds an include_tree parameter and solves the exclude_tree problem by taking the list of page IDs in your exclude- and include_tree parameters, finding all of the child pages (to the depth you specify), then adding those parent and child IDs to your exclude and include parameters before passing everything on to the wp_list_pages function.

function md_list_pages( $args ) {

	$defaults = array(
		'depth' => 0, 'show_date' => '',
		'child_of' => 0, 'exclude' => '',
		'title_li' => __('Pages'), 'echo' => 1,
		'authors' => '', 'sort_column' => 'menu_order, post_title',
		'link_before' => '', 'link_after' => '',
		'include' => '', 'include_tree' => '',
		'exclude_tree' => '',

	$r = wp_parse_args( $args, $defaults );

	$exclude = list_pages_tree( $r[ 'exclude' ], $r[ 'exclude_tree' ],
			$r[ 'depth' ] );
	$include = list_pages_tree( $r[ 'include' ], $r[ 'include_tree' ],
			$r[ 'depth' ] );

	$pages = wp_list_pages( 'depth=' . $r[ 'depth' ] . '&show_date='
			. $r[ 'show_date' ] . '&child_of=' . $r[ 'child_of' ]
			. '&exclude=' . $exclude . '&title_li='
			. $r[ 'title_li' ] . '&echo=0&authors=' 
            . $r[ 'authors' ] . '&sort_column=' 
            . $r[ 'sort_column' ] . '&link_before=' 
            . $r[ 'link_before' ] . '&link_after=' 
            . $r[ 'link_after' ] . '&include=' . $include );
    	echo $pages;
	} else {
    	return $pages;


function list_pages_tree( $param, $tree, $depth ) {

	// get the parent pages of the tree
	$parent_pages = get_pages( 'include=' . $tree );

	foreach ( $parent_pages as $parent ) {
		if (!empty( $param ) ) {
			$param .= ",";

		$param .= $parent->ID;

		// get the child pages of the tree
		$child_pages = get_pages ( 'child_of=' . $parent->ID
			. '&depth=' . $depth );

		foreach ( $child_pages as $child ) {
			$param .= "," . $child->ID;

	return $param;

How to Use It

Copy and paste the above functions into your functions.php file. Then replace all instances of wp_list_pages() in your template with md_list_pages(). The parameters are the same as the wp_list_pages parameters, with the addition of the include_tree parameter.

For example, I replaced this call on the non-profit site:

<?php wp_list_pages( 'depth=2&sort_column=menu_order&title_li=
			&include=5,9,11,14,2,16' ); ?>

…which only returns the included pages, with this call:

<?php md_list_pages( 'depth=2&sort_column=menu_order&title_li=
			&include_tree=5,9,11,14,2,16' ); ?>

…which returns the included pages and all of their child pages (for the drop-down menu on the site).

I realize that this method results in the template tag parameters being parsed twice, but I decided to keep wp_list_pages in the mix rather than bypass it completely because some plugins (including some on the aforementioned non-profit site) function by adding or removing actions to that template tag.

Hope this is helpful to someone else out there — I’ll be using it myself more in the future (unless WP3.0 eliminates my need for a workaround).

Update: Wow, over 350 pingbacks, and all of them spam. Thank goodness for Akismet…

Update 23 July 2011: I thought the new menu system in WordPress 3.0 pretty much killed the need for this workaround, but I guess there are still reasons to use wp_list_pages(). I’d love to hear how people are still using the function (wp_list_pages(), not my md_list_pages()) and whether they prefer it to wp_nav_menu() or not. Depending on response, I may have to rework my solution a bit to reduce the processing overhead and to weed out the bugs.


WordPress Wednesday: How to Use paginate_comments_links Only When You Really Mean It

March 10, 2010 Comments off

I was pretty happy when WordPress added paginate_comments_links because now I didn’t have to write a custom function to break blog comments into separate pages and give them a nice navigation (instead of just “next” and “previous”). However, I like to put my navigation in a div, and I like to style that div…and it can look pretty bad when my styled div shows up with no navigation (depending on my design).

The solution is pretty simple (as most of my solutions are): I wrote a simple function that only echoes my div and pagination links if the comments are paginated:

function comment_pagination() {
	//read the page links but do not echo
	$comment_page = paginate_comments_links('echo=0');

	//if there are page links, echo the navigation div and the page links
	if (!empty($comment_page)) {
		echo "<div class=\"navigation\">\n";
		echo $comment_page;
		echo "\n</div>\n";

All that’s left at this point is styling the pagination links.  The above code will give you a markup along these lines:

<div class="navigation">
	<a class='prev page-numbers'>&laquo; Previous</a>
	<a class='page-numbers'>1</a>
	<span class='page-numbers current'>2</span>
	<a class='page-numbers'>3</a>
	<a class='next page-numbers'>Next &raquo;</a>

Hopefully I’ll learn more about paginate_comments_links in the future and be able to better customize the output. We’ll see.

WordPress Wednesday: Turn Any Shortcode into a Template Tag

March 3, 2010 18 comments

I previously discussed WordPress’s shortcode API, which allows you to turn any function into a shortcode that you can embed in the content of your pages or posts. Though the example I gave was for a function I wrote, you can use this API for WordPress template tags. The easiest way is to get the Template Tag Shortcodes plugin by Justin Tadlock, although you can also write your own by adding the following line to your functions.php file:

add_shortcode('shortcode_name', 'template_tag');

But what about the other way around? The solution is just as simple with the do_shortcode function.

You may remember that my previous shortcode allowed a client to enter [link pagename=’example’] into the content of any page, and the function would insert the named page’s permalink into the content for him. If I wanted to call that shortcode as a template tag, the tag would look like this:

<?php echo do_shortcode("[link pagename='example']"); ?>

All you have to do to turn any shortcode into a template tag is substitute your shortcode (with the desired parameters defined) between the double quotes (“) and you’re good to go. This is especially helpful when plugins come with shortcodes included but not template tags (like NextGen Gallery).

What will you use the do_shortcode function for?

Update: Thanks to Holling for pointing out that I forgot to include the echo statement. Fixed now.

Survivor: Twitter – 3 Guidelines for Managing Who You Follow and Who Follows You

March 2, 2010 Comments off

A few weeks ago was a first for me: I stopped following someone on Twitter.

The person in question is a webcomic artist who is well known for the drama that swirls around him. I started following him for the chance to pick his brain on becoming successful with my own webcomic. Instead of insight into the world of webcomics, however, I got insight into a very angry individual. I got to see frequent, vulgar complaints about inconsequential things. One day he picked a fight about social views (not the first time), starting off by insulting those who hold my personal views.

I decided it was time to stop following. Then I decided that it was time I started managing who I follow and who follows me.

You Are Who You Hang Out With

The way I see it, your social network associations say as much about you as your real-life associations. We all tend to associate with those who we are like, whose views we share or whose company we enjoy. I had stopped enjoying this person’s company a long time ago but for some reason kept associating with him. When I realized that my association could be considered a tacit approval of or agreement with the views he was airing so rudely, I knew I had to end the association.

The same holds true people following me. If you’ve used Twitter with any frequency at all, you’ve probably noticed that you will suddenly have an increase in followers anytime you’re actively tweeting, but that half of them are spambots — and at least half of those are porn spambots. I try to block those as soon as I find them, because I don’t want the association.

Managing Your Twitter Followers Can Be Like a Reality TV Show

Inspired by one of Sid Raisch’s tweets, I’m proposing an UN-Follow Friday — but I want to make it fun and establish some guidelines for who gets unfollowed or blocked.

Think of the people and companies you’re following or who follow you as contestants on Survivor. Each week at Tribal Council you have a chance to vote them off your island. Each Twitterer is judged based on three criteria:

  1. Tweet Content
  2. Tweet Frequency
  3. Relationship

No one person or company needs to satisfy all three guidelines to stay on the island, but anyone who doesn’t satisfy at least one is getting voted off.

Tweet Content

The first guideline is the most obvious: what does the person tweet about? Are the tweets relevant, interesting and/or humorous? In short, why am I following them and what am I getting from the association? You can follow people just because it’s fun (like @CobraCommander or @pagecrusher) or because they’re a celebrity you like (like @wilw), but have some reason why you’re following their tweets. If you never read the person’s tweets (or if their content insults you, like my example), it’s time to cut them loose.

The guideline gets a little relaxed for people following you. Generally, I suggest that as long as they’re not an obvious spammer or particularly offensive they can stay.

Tweet Frequency

One of the people I follow tweets at least 10 times each hour. There is no way I can keep up with all the content that he is pointing to, and sometimes I see the same tweet more than once each day (which may fall under tweet content above). I haven’t stopped following him yet because he does tweet some useful articles, but I’m seriously thinking about it.


I follow a few people just because they’re friends of mine, and I don’t see anything wrong with that. In fact, it’s sometimes a good way for us to keep tabs on each other, and occasionally we’ll use Twitter as a way to point each other to content we know the other will like. Additionally, I’ve started to make some friends on Twitter (using some of techniques I discussed in a previous post) who I only know through Twitter. I’m not likely to drop anyone I have a relationship with (real or virtual) unless their tweets become too much of a problem under the first two guidelines.


So there are my Twitter follow/follower management guidelines. As before, I plan to follow my own advice. Not sure which day I’ll pick to be my Tribal Council day, but it will probably be Friday or Saturday since I usually have fewer pressing deadlines on those days.

What will your Tribal Council day be?

WordPress Wednesday: How to Transfer Your Plugin Data Using phpMyAdmin

February 10, 2010 1 comment

I often use Stray Random Quotes for clients who want to display random testimonials (or quotes, natch) on their WordPress sites. Of course, I build their sites completely on my webspace to test them before installing on the client domain. While WordPress has export and import functions for pages, posts and media, my quotes don’t transfer over so easily. Fortunately, the built-in functions of phpMyAdmin can pick up the slack.

The following assumes that you already have WordPress installed on both your test domain and the live domain. I’m using the specific example of Stray Random Quotes but you can do the same with any plugin that creates tables in your WordPress database.

First, make sure you have Stray Random Quotes (or whichever plugin you’re transferring data for) installed on the live site. This is important because the plugin will create the necessary tables for you (saves you a few steps and a lot of headache).

Second, open your WordPress database using phpMyAdmin on your test site. In the left-hand column, click on the database name to expand it, then click on the wp_stray_quotes table.

Click on the “Export” tab in the  main window. Make sure your export format is set for “SQL” and your export type is “INSERT,” then click “Go.”

You should see a text representation of the database export. Copy only the text rows that start with “INSERT INTO.” Paste these into a text file using Notepad and save as a .txt file.

Next, open the WordPress database on your live site using phpMyAdmin. Click on the database name to expand and then on wp_stray_quotes.

Click the “Import” tab, then the “Browse” button. Locate the text file you created previously and click “Open,” then click “Go.”

Your quotes should be imported into the live database.

Twitter Tuesday: Why to Not Be a Broadcaster (and How I’m Going to Stop)

February 9, 2010 3 comments

It’s easy to fall into the trap of treating Twitter like a P.A. system; you tell everyone about the articles you’re reading online, your latest blog post or even the food you just had for dinner and expect that you’ll gain followers and readers.

However, unless you’re a major brand or some kind of celebrity, it probably won’t work like that. Instead, you’ll tweet and tweet and tweet and get very little attention.

Why is that?

Well, in Twitter-speak you’re being a broadcaster. That is, you’re talking a lot but not really “joining the conversation.”

Think of real life: do you like to talk to someone who keeps talking endlessly without giving you a chance to respond (or who completely ignores you when you do)? Of course not. People like to have interaction; a chance to ask questions and to make observations of their own.

Now, you’re not a bad person if you’ve acting like a broadcaster — at least, I hope not, since I’ve fallen into the broadcasting trap myself. However, you’re not using Twitter to its full potential. The true strength of Twitter, like any social network, is in building relationships — because, as LinkedIn says, relationships matter.

So how am I going to stop being a broadcaster and start building relationships? Here are my thoughts:

Remember it’s not all about me

Everyone on Twitter wants to be heard, and it’s good to acknowledge someone who’s tweeted something interesting or relevant. A great way to do this, of course, is the retweet; forwarding someone else’s tweet to your followers. Twitter has a function for this now, but I still like to do it the old-fashioned way: either a) cut-and-paste the tweet, adding “RT” to the front, or b) using the retweet function on TweetDeck. This lets me explain why I think it’s worth retweeting.

When my friend JosephRanseth co-hosted an webinar on “Guerilla Social Marketing,” I didn’t just forward his announcements, I encouraged people to come and then sent out the link to the recorded version after along with my thoughts on how the webinar went.

Make Good Use of Follow Fridays

As long as I’m acknowledging other people, I really need to take part in Follow Fridays. #FollowFriday or #ff gives me a chance to point to someone else who I think is worth following on Twitter, and — as with retweets — tell others why I think this person is worth following.

My friend Joseph had some good thoughts on the subject over at his blog. I’m not sure he always follows his own advice, but it’s good advice anyway.

Comment, Ask Questions, Answer Questions

I can’t expect people to reply to me unless I’m willing to reply to them. It’s kind of like dating. I didn’t date very much before I got married, largely because I didn’t do my part to engage members of the opposite sex. I didn’t talk enough to them, so they didn’t talk enough to me.

When Dave Kellett asked his followers what typeface captured the fun and energy of “Squee!,” I answered. In fact, I posted an image on TwitPic with my choice (Alpha Thin) and sent a download link if he decided to use my suggestion. I forgot to adjust my kerning on the image and Dave never replied, but hey, I actually engaged someone. I need to do this more — there’s no better way to show someone that their tweet is important to you than to actually reply to it.

Join a conversation

I think the best experience I’ve had on Twitter was joining #webcomicschat hosted by Patrick Scullin. This is Twitter taken to a logical conclusion: a mass instant messaging system. I enjoy webcomics and hope to get back to one of my own someday, so I like joining in with other like-minded twitterers to discuss whatever topics get thrown out.

I haven’t had a chance to join in on the chat for awhile, but hopefully I’ll be free tomorrow for the next one.

Start a conversation

This is the step I’m not sure I’m ready for quite yet. I’d like to host a regular chat like Patrick does. I have a few that I’d like to do, ranging in topics from graphic design to creating a more focused webcomics chat that would specifically be a big brainstorming session for concepts and stories. I think that I’ll hold this as a goal while I work on the first four steps a little longer. Hopefully, the next time I post about this topic I’ll be able to say that I’m not a broadcaster anymore.

We’ll see.

Got any more ideas for how to make the move from being a broadcaster to forming actual (virtual) relationships? Leave them below — I’d love the help!

Categories: Social Media Tags: ,

WordPress Wednesday: All-in-One SEO Without Using wp_head()

February 3, 2010 24 comments

One of my favorite plugins to use for client sites is the All-in-One SEO Pack. I like how it allows me (or the client) to specify unique keywords, descriptions, menu text, etc. for each page or post on their site. I don’t like that it requires me to use the wp_head() function in order to edit keywords and descriptions.

For those who don’t know already, wp_head() automatically adds data to the header of your WordPress pages. Some of this data is helpful (like adding the descriptions and keywords from the All-in-One SEO Pack); some of it is not (like what version of WordPress your site uses, which helps hackers know which vulnerabilities they should try to exploit).

My workaround is to add a couple of simple php functions to my functions.php file. For example, the following function write the SEO Pack meta keywords into my WordPress page:

// function to insert All-in-One SEO Pack keywords
function keyword_insert() {
 global $post; // VERY important!

 // Retrieve keyword meta data from the SEO Pack
 $seokeywords = stripslashes(get_post_meta($post->ID, '_aioseop_keywords', true));

 // Default keywords in case none are specified for the page
 if (empty($seokeywords)) $seokeywords = "Homestar Runner, Strong Bad, The Cheat";

 // Output the html code
 $seokeyword_block = "<meta name=\"keywords\" content=\"".$seokeywords."\"/>\n";
 echo $seokeyword_block;

If I want to use the SEO Pack meta description, I alter the function like so:

// function to insert All-in-One SEO Pack description
function description_insert() {
 global $post; // VERY important!

 // Retrieve description meta data from the SEO Pack
 $seodesc = stripslashes(get_post_meta($post->ID, '_aioseop_description', true));

 // Default description in case none is specified for the page
 if (empty($seodesc)) $seodesc = "Oh! I am Homestar, and This is A Website!";

 // Output the html code
 $seodesc_block = "<meta name=\"description\" content=\"".$seodesc."\"/>\n";
 echo $seodesc_block;

If I wanted to create functions to pull additional information from the SEO Pack, they would also follow this same format. The different meta keys used by the All-in-One SEO Pack are:

  • _aioseop_keywords: meta keywords for the page; if your template already includes a <meta> keywords tag, the SEO Pack function will write a second tag — it is better to use one or the other and not both
  • _aioseop_description: meta description for the page; like the keywords, the SEO Pack function will write a second <meta> description if one is already included in the template
  • _aioseop_title: as in page title; the SEO Pack will rewrite any instances of the post title with this value unless you uncheck the “Rewrite Titles” option in the plugin settings; otherwise defaults to post title if no value is specified
  • _aioseop_menulabel: this is the text that is retrieved by the wp_list_pages() function; defaults to post title if no menu label is specified
  • _aioseop_titleatr: this is the “title” attribute for the links retrieved by the wp_list_pages() function; defaults to post title if no title attribute is specified

You will probably use the other meta keys less frequently than _aioseop_keywords and _aioseop_description since the other keys work through existing WordPress functions, although I have had use special functions for those keys on a few occasions.

Update: Silly me, I forgot to mention how to use these.

Place the following lines of code between the <head> and </head> tags in your template:

<?php description_insert(); ?>

<?php keyword_insert(); ?>

But then you probably already knew that.