The question:
I’m looking to style my wp_list_pages with a span class. I’d like to give it a unique class so that I can give each a specific icon.
'link_before' => '<span class="'.[unique-identifier-here].'"></span>',
I was thinking of using the page slug but the menu I use also has child pages involved so it would have to pull the target links page slug not the $post->post_name
one.
I’m not sure if it’s a good option which just needs better logic or if there’s a better solution altogether.
Here’s my full menu code:
global $post;
if ( is_page() && wap8_has_children( $post->ID ) == '1' || wap8_has_siblings() == '1' ) {
if ( $post->post_parent ) {
$args = array(
'sort_column' => 'menu_order',
'title_li' => '',
'child_of' => $post->post_parent,
'echo' => 1,
'link_before' => '<span class="'.$post->post_name.'"></span>',
);
} else {
$args = array(
'sort_column' => 'menu_order',
'title_li' => '',
'child_of' => $post->ID,
'echo' => 1,
'link_before' => '<span class="'.$post->post_name.'"></span>',
);
}
echo "<ul>n";
wp_list_pages( $args );
echo "</ul>n";
}
-edit- What I’d like the output to look like.
<ul>
<li>
<a>
<span class="unique_class1"></span>
</a>
<li>
<li>
<a>
<span class="unique_class2"></span>
</a>
<li>
<li>
<a>
<span class="unique_class3"></span>
</a>
<li>
</ul>
The Solutions:
Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.
Method 1
Okay well in that case the way you’ve suggested in your question will not work as intended. It will put the same class on each <span>
, that class would also be the post_name
of the current page you are on.
You do have two options that you can use, one being much easier than the other:
Method One
Each <li>
item generated by wp_list_pages()
is given a unique class. The class follows a pattern of page-item-$ID
where $ID
is the ID of the page currently being processed by wp_list_pages()
.
If you change the link_before
parameter to be just <span></span>
then you can target the spans I’m your css like so .page-item-$ID span
. Though I imagine this would get tedious if you had loads of pages.
Method Two
You could write a custom walker for the wp_list_pages()
function and pass it into the walker
parameter of the function. This would give you considerably more control over the naming of classes. Attached is a custom walker that you can use, with an explanation beneath.
Add to functions.php:
class WPSE_130877_Custom_Walker extends Walker_Page {
function start_el( &$output, $page, $depth, $args, $current_page = 0 ) {
if ( $depth )
$indent = str_repeat("t", $depth);
else
$indent = '';
extract($args, EXTR_SKIP);
$css_class = array('page_item', 'page-item-'.$page->ID);
if ( !empty($current_page) ) {
$_current_page = get_post( $current_page );
if ( in_array( $page->ID, $_current_page->ancestors ) )
$css_class[] = 'current_page_ancestor';
if ( $page->ID == $current_page )
$css_class[] = 'current_page_item';
elseif ( $_current_page && $page->ID == $_current_page->post_parent )
$css_class[] = 'current_page_parent';
}
elseif ( $page->ID == get_option('page_for_posts') ) {
$css_class[] = 'current_page_parent';
}
$css_class = implode( ' ', apply_filters( 'page_css_class', $css_class, $page, $depth, $args, $current_page ) );
$icon_class = get_post_meta($page->ID, 'icon_class', true); //Retrieve stored icon class from post meta
$output .= $indent . '<li class="' . $css_class . '">';
$output .= '<a href="' . get_permalink($page->ID) . '" rel="nofollow noreferrer noopener">' . $link_before;
if($icon_class){ //Test if $icon_class exists
$output .= '<span class="' . $icon_class . '"></span>'; //If it exists output a span with the $icon_class attached to it
}
$output .= apply_filters( 'the_title', $page->post_title, $page->ID );
$output .= $link_after . '</a>';
if ( !empty($show_date) ) {
if ( 'modified' == $show_date )
$time = $page->post_modified;
else
$time = $page->post_date;
$output .= " " . mysql2date($date_format, $time);
}
}
}
Call your wp_list_pages()
like below:
wp_list_pages(array(
'sort_column' => 'menu_order',
'title_li' => '',
'echo' => 1,
'walker' => new WPSE_130877_Custom_Walker()
));
Take note that we have removed the link_before
parameter and added in a walker
parameter, which takes an instance of our custom walker class. Notice it has the same name as the snippet of code i’ve asked you to put into your functions.php
.
The code for the custom walker is essentially default WordPress code but we are overriding it with the new walker. We are only making a small edit in the middle of the default WordPress function that handles the markup for the beginning of each page-item
. All of the code I added has comments next to it.
So as build the markup for each page-item
we check to see if it has a meta key of icon_class
, if it does then we add in a <span>
tag with our icon_class
value before the page-item
link. The conditional is there to prevent printing out redundant elements, however the code could easily be edited to add a default icon in.
Essentially all you need to do is build a meta box for your pages and then replace icon_class
in the above code with whatever you decide to call the key that holds the class name. It should be noted that the code expects icon_class
to return a string.
Method 2
There is no need for extra markup. Your menu items have a unique CSS class page-item-{ID}
, which you could use.
First, give your list an ID, like <ul id="my-list">
.
Then, target the items, for instance, like so:
#my-list .page-item-123 a {
padding-left: 20px;
background-image: url(...);
...
}
or
#my-list .page-item-123 a:before {
content: '123';
font-family: SomeIconFont;
...
}
Method 3
To avoid error on debug, The declaration of this function has to have the parameters defined like this:
function start_el(&$output, $page, $depth = 0, $args = array(), $current_page = 0)
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0