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 );
            
	if($r['echo']){
    	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>
</div>

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



What Health Insurance Is and Isn’t

March 4, 2010 4 comments

I’m not going to use this blog to stump for any particular side of the health care debate, but I want to clear up a misconception that’s been bothering me since the debate began.

Many of the arguments made for reform include comments about insurance companies denying coverage to individuals with pre-existing conditions. This has been represented as a greedy and heartless practice by insurance companies to avoid having to pay claims. This argument is being made by many who (in my opinion) do not understand the basic concept of what insurance is.

Insurance is the management of risk. Each of us lives in risk of suffering harm or illness at any point in our lives; health insurance helps us manage that risk by allowing us to pay (comparatively) small amounts of money over our lifetimes with the promise that funds will be provided for our care should such harm or illness befall us. We enter into this agreement with an insurance company knowing full well that we may never need those funds — we may pay out our entire lives and never get back. On the other hand, we may end up needing far more than we ever pay in. Several people doing the same allow the risks of these outcomes to be spread out over a larger group so that no one person bears the entire burden.

Insurance is not a discount program. It is not a way to get medical services for less than their market value. The money for insurance coverage has to come from somewhere, and there has to be enough of it available to cover any needs that may arise.

A person with a pre-existing medical condition who has to see a doctor or have procedures performed regularly will draw out more than he or she puts in. They are not managing risk, but receiving discounted care. They are denied coverage because there is no chance that their premium payments will ever equal or exceed the benefits they receive, so there is no risk to manage.

To borrow an analogy from a popular (if misinformed) YouTube video, imagine that maintaining a fire department was not one of the normally responsibilities of government. Instead, imagine that you had to pay $6,000 each time a fire needed to be put out at your home. You may never need fire service during your lifetime, or you may need it several times.

To help manage the risk, you and 9 other people in your neighborhood decide to pool your resources. You research statistics on home fires and determine that it is likely that one of your homes will catch fire in any 10-year period1. To manage this risk, each of will pay $5 per month (10 people × $5 per month × 120 months = $6,000). Your expectation is that any one of you may need to draw out this money at any time in a 10-year period. You may go 10 years with no fires, or there may be 2 fires, but at least this way the risk (and the charge) are spread out among the 10 of you so no one bears the burden by themselves.

One day a neighbor comes to you who is not part of your pool. His house is on fire and he wants to pay his $5 to become part of your pool. There is no risk to spread out here; you know that if he enters the pool you will have to immediately pay out the $6,000 to cover his bill, for which he will pay only $5. He is under no obligation to continue in your pool after he receives his money. This is what it is like when someone who has a pre-existing condition is applying for health insurance. He is asking you to pay his costs — which is not insurance, it is a subsidy.

Now I’m not saying that we shouldn’t have ways for everyone to have affordable access to health care. I’m not defending any other practices that insurance companies may or may not engage in. I am simply saying let’s stop using coverage denials due to pre-existing conditions to demonize insurers. Insurance is not a subsidy or discount program, it is risk management. If there is not a chance that you may not need your benefits, then it defeats the entire purpose and function of insurance.

Now let’s get back to debating.


1. This is of course not a real statistic and is only being used for illustrative purposes.


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.

Relationship

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.

Wrap-Up

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?


CSS-Only Triangles with Hover Effects

February 18, 2010 1 comment

I was giddy when I saw this post about creating CSS triangles on Jon Rohan’s blog and quickly realized two things:

  1. I am officially a CSS geek.
  2. Because the code relies on creating a div with a height and width of 0, there is no way to create hover effects — which is fine if I’m using the triangles for a design element, but not as good if I’m using it for navigation.

Fortunately, there is a very easy fix (for #2, at least): wrap the element in an anchor tag.

The final code looks something like this:


<a class="css-arrow-multicolor" href="#">
	<span></span>
</a>



.css-arrow-multicolor {
	display: block;
	width: 20px;
	height: 40px;
	overflow: hidden;
}


.css-arrow-multicolor span {
	border-color: transparent transparent transparent #000066;
	border-style: solid;
	border-width: 20px;
	dispay: block;
	width: 0;
	height: 0;
}



.css-arrow-multicolor:hover span {
	border-color: transparent transparent transparent #0000ff;
}

In this case I set the width of the containing <a> element to the same as the border width of the span, and the height of the <a> element to twice the border width of the span so that the <a> is exactly the size of the arrow. I set the overflow to hidden for the same reason.

Unfortunately I can’t show you an example of the triangle with its hover effects due to code limitations on free WordPress blogs, so you’ll either have to take my word for it or try it out yourself.

Edit 2013-04-30: Original code used a <div> instead of span, which is not good practice. Updated to use a span instead with styling set to display: block.

Categories: Web Design Tags: ,

The Celebration of Love, Trust, Partnership, Tolerance and Tenacity

February 16, 2010 2 comments

About this time two years ago I was driving to the Portland, Oregon Temple of the Church of Jesus Christ of Latter-Days Saints to marry the love of my life when she called me on my cell phone.

“We can’t do this,” she said to me (or something to that effect). I had only a moment for the shock and disbelief that she might be backing out to register before she clarified that her father (who was driving to Portland from La Grande) was stuck about two hours from Portland because his truck had broken down.

Fortunately an LDS wedding is a relatively small and simple affair, so we moved the time later in the day without much difficulty. We had scheduled the wedding and the reception several hours apart and the new wedding time fit nicely into the new schedule. We even still had time for our family luncheon between the two — of course, Melissa spent most of the luncheon time on a couch trying to sleep off the flu she had caught that morning, an illness that would last throughout the week of our honeymoon.

It seems that many of the best things in our lives have started with little disasters. Melissa and I had our first real conversation talking about all how depressed I was over some bad personal and family situations. On our first date we missed hearing one of Melissa’s favorite Jazz singers because that night the restaurant she was singing in (which didn’t normally take reservations) was completely reserved. I spent too much for not-so-great food at Greek Cuisina* and we saw the catastrophe that was Ghost Rider.

Who would have thought that failing so miserably would actually bring us closer together? Both Melissa and I later admitted that we went home from that date feeling really good about the night — and of course we later began dating and got married about a year after that first date.

The little disasters continue, but always seem to end in something better than if we were blessed with smooth sailing. I lost my job a year ago this month, but now I own my own business. Labor was a multi-day ordeal for Melissa, but now our son Isaac is 4 months old and almost crawling. Decisions we had to make during that labor started us on an early path of putting his needs above our own, and I am convinced that we treasure him more because of it.

So here’s to the little disasters — they got me where I am today: celebrating a second year with my beautiful bride, happier than I have ever been.



*This is not to say that Greek Cuisina didn’t have good food, just that what we ordered was not.

Categories: Personal Tags: ,