WP Smith

Creating WordPress & Genesis Websites Since 2010

  • Home
  • About
  • Services
  • Blog
  • Contact

Dec 08 2011

How to Add Genesis Custom Content Columns to the Editor (to Appear in Visual Mode)

Recently, I had a need to have the custom columns of WordPress on the backend to be used in the Visual Editor. So thanks to a few tutorials out there regarding this, especially Alison's Mastering the TinyMCE Styles Dropdown in the WordPress Visual Editor, who has a great plugin, Custom Styles Dropdown, and WPEngineer's, Customize WordPress WYSIWYG Editor (more for a better understanding). Another option is the Advanced TinyMCE WordPress Plugin. I plan to develop this into a plugin, coming soon...

However, this tutorial will focus solely on the Custom Content Columns for Genesis users. If you need an explanation, please see Alison's Mastering the TinyMCE Styles Dropdown in the WordPress Visual Editor post.

Add this to your functions.php file.
[php]
add_filter( 'mce_buttons_2', 'wps_mce_buttons_2' );
/**
* Show the style dropdown on the second row of the editor toolbar.
*
* @param array $buttons Exising buttons
* @return array Amended buttons
*/
function wps_mce_buttons_2( $buttons ) {

// Check if style select has not already been added
if ( isset( $buttons['styleselect'] ) )
return;

// Appears not, so add it ourselves.
array_unshift( $buttons, 'styleselect' );
return $buttons;

}

add_filter( 'tiny_mce_before_init', 'wps_mce_before_init' );
/**
* Add column entries to the style dropdown.
*
* 'text-domain' should be replaced with your theme or plugin text domain for
* translations.
*
* @param array $settings Existing settings for all toolbar items
* @return array Amended settings
*/
function wps_mce_before_init( $settings ) {

$style_formats = array(

array(
'title' => __( 'First Half', 'text-domain' ),
'block' => 'div',
'classes' => 'one-half first',
),
array(
'title' => __( 'Half', 'text-domain' ),
'block' => 'div',
'classes' => 'one-half',
),
array(
'title' => __( 'First Third', 'text-domain' ),
'block' => 'div',
'classes' => 'one-third first',
),
array(
'title' => __( 'Third', 'text-domain' ),
'block' => 'div',
'classes' => 'one-third',
),
array(
'title' => __( 'First Quarter', 'text-domain' ),
'block' => 'div',
'classes' => 'one-fourth first',
),
array(
'title' => _( 'Quarter', 'text-domain' ),
'block' => 'div',
'classes' => 'one-fourth',
),
array(
'title' => __( 'First Fifth', 'text-domain' ),
'block' => 'div',
'classes' => 'one-fifth first',
),
array(
'title' => __( 'Fifth', 'text-domain' ),
'block' => 'div',
'classes' => 'one-fifth',
),
array(
'title' => __( 'First Sixth', 'text-domain' ),
'block' => 'div',
'classes' => 'one-sixth first',
),
array(
'title' => __( 'Sixth', 'text-domain' ),
'block' => 'div',
'classes' => 'one-sixth',
),
);

// Check if there are some styles already
if ( $settings['style_formats'] )
$settings['style_formats'] = array_merge( $settings['style_formats'], json_encode( $style_formats ) );
else
$settings['style_formats'] = json_encode( $style_formats );

return $settings;

}
[/php]

This will result in this:
Custom Columns in the Editor

However, the HTML will contain the necessary classes and styles and will be:
[html]
<div class="one-half first">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean quam massa, iaculis vel vehicula aliquam, iaculis ut risus. Mauris luctus, justo quis blandit vestibulum, dui lorem rhoncus massa, non aliquam ante erat at dolor. In facilisis libero in libero pharetra eu pellentesque mauris convallis. In vitae tortor lorem. Nullam aliquet ligula vel lectus pretium eget elementum massa laoreet. In hac habitasse platea dictumst. Quisque lacinia odio vitae nisl dictum euismod. Suspendisse eget nisl quis leo pulvinar cursus. Aliquam vel elit vehicula neque consectetur blandit eu eget nisi. Maecenas vitae risus quis lacus feugiat dictum sed eget arcu. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nulla feugiat massa ut mauris viverra porta.</div>
<div class="one-half">Fusce porttitor libero ut libero aliquam vitae faucibus lorem tincidunt. Phasellus pharetra libero et eros pellentesque eget feugiat eros adipiscing. Pellentesque massa augue, interdum ut facilisis et, pellentesque et justo. Proin consectetur venenatis vehicula. Aliquam interdum ullamcorper urna, quis volutpat massa dictum non. Integer placerat nunc porttitor lacus volutpat ultricies. Integer ornare ultrices nibh sed hendrerit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.</div>
[/html]

Now you can also add the following to incorporate your CSS into the Visual Editor to achieve a closer representation on the backend (that will eventually appear on the front end):
[php]
add_editor_style();
[/php]
Now, the add_editor_style(); is a really cool feature. Now you can add a stylesheet to your child theme's folder called editor-style.css, and any style that you want to appear in the editor will now appear in the visual editor as it would on the external pages. So to get the custom column classes, you will need to create the editor-style.css.

Here is what your visual editor will look like with the use of add_editor_style();
Custom Columns with add_editor_style()

However, you do not need to add the add_editor_style(); for this to work. Adding the add_editor_style(); only allows the style to be applied inside the Visual editor.

[css]
/* Column Classes
------------------------------------------------------------ */

.five-sixths,
.four-fifths,
.four-sixths,
.one-fifth,
.one-fourth,
.one-half,
.one-sixth,
.one-third,
.three-fifths,
.three-fourths,
.three-sixths,
.two-fifths,
.two-fourths,
.two-sixths,
.two-thirds {
float: left;
margin: 0 0 20px;
padding-left: 3%;
}

.one-half,
.three-sixths,
.two-fourths {
width: 48%;
}

.one-third,
.two-sixths {
width: 31%;
}

.four-sixths,
.two-thirds {
width: 65%;
}

.one-fourth {
width: 22.5%;
}

.three-fourths {
width: 73.5%;
}

.one-fifth {
width: 17.4%;
}

.two-fifths {
width: 37.8%;
}

.three-fifths {
width: 58.2%;
}

.four-fifths {
width: 78.6%;
}

.one-sixth {
width: 14%;
}

.five-sixths {
width: 82%;
}

.first {
clear: both;
padding-left: 0;
}
[/css]

Or simply download the file below and place inside your child theme folder.
Download: [download id="17"]

Written by Travis Smith · Categorized: Genesis, Tutorials

Dec 06 2011

How to Automatically Add a Class (like 'first' or 'last') to a WordPress Menu

So recently, I needed a way to dynamically add a 'first' class to all the first child nav menu items of a particular parent nav menu item item. On a simple Google, one tutorial by @WPBeginner suggests that we use a filter.
[php]
//Filtering a Class in Navigation Menu Item
add_filter( 'nav_menu_css_class' , 'special_nav_class' , 10 , 2 );
function special_nav_class( $classes, $item ){
if( is_single() && $item->title == 'Blog' ){
$classes[] = 'current-menu-item';
}
return $classes;
}
[/php]
However great this filter is, this approach won't and cannot be very dynamic.

So I wrote a function (and generalized it) that would accomplish this easily and nicely. This uses a function that I wrote about previously called get_nav_menu_item_children() in a post called How to Get All the Children of a Specific Nav Menu Item that I have modified (12/6).

Given a menu id and a parent item id and the optional class name, the function will automatically add that class to the first child nav menu item. So here is the new function:
[php]
/*
* Adds a class to the first menu item.
*
* Uses update_post_meta() to update a nav menu item.
*
* @param int $menu_id Menu ID, defaults to 0.
* @param int $parent_id Menu item ID, defaults to 0.
* @param string $newclass Class to add, defaults to 'first'.
* @param boolean $remove Remove class from other children, defaults to true.
* @return boolean, false: if no $menu_id or $parent_id, else true.
*/
function wps_update_classes( $menu_id = 0 , $parent_id = 0 , $newclass = 'first' , $remove = true ) {

// Validate inputs
$menu_id = intval ( $menu_id );
$parent_id = intval ( $parent_id );

if ( ( $menu_id == 0 ) || ( $parent_id == 0 ) || ( !is_bool ( $remove ) ) || ( !is_string ( $newclass ) ) )
return false;

// Get & filter nav menu items
$nav_menu_items = wp_get_nav_menu_items( $menu_id , array( 'post_status' => 'publish,draft' ) );
$children = get_nav_menu_item_children( $parent_id , $nav_menu_items );
$first_item = true;

// Cycle through child nav menu items
foreach ( $children as $child ) {
if ( $first_item ) {
//found first item
$first_item = false;
$match = false;

// Cycle through to check for first
foreach ( $child->classes as $class ) {
// Match found
if ( $class == $newclass ) {
$match = true;
break;
}
}

// Update Post if match found
if ( ! $match ) {
if ( $child->classes[0] == '' )
$child->classes[0] = $newclass;
else
$child->classes[] = $newclass;

$menu_item_data = array(
'menu-item-classes' => $child->classes,
);
update_post_meta( $child->ID, '_menu_item_classes', $child->classes );
}
continue;
}

// Cycle through and remove $newclass from other children
if ( $remove ) {
foreach ( $child->classes as $key => $class ) {

// If match, remove $newclass from other children
if ( $class == $newclass ) {
$child->classes[$key] = '';
update_post_meta( $child->ID, '_menu_item_classes', $child->classes );
}
}
}
}

return true;
}
[/php]

So to call this function, you can use something like this:
[php]
add_action( 'init' , 'wps_update_menus' );
function wps_update_menus() {
wps_update_classes( 3 , 277 );
wps_update_classes( 3 , 7 , 'test-class' );
}
[/php]
This bit of code adds 'first' to the first child of menu item 277 on menu 3 and 'test-class' to the first child of menu item 7 on menu 3.

If you want to add the ability to add a 'last' class, you can use this:
[php]
/*
* Sorts a multidimensional array of nav menu items.
*
* @link http://php.net/manual/en/function.sort.php
* @param array $array Multidimensional array to be sorted.
* @param string $index Index to determine the sort.
* @param string $order Must be either asc or desc.
* @param boolean $natsort Sort an array using a "natural order" algorithm.
* @param boolean $case_sensitive Sort via case sensitivity.
* @return boolean, false: if no $menu_id or $parent_id, else true.
*/
function wps_sort_nav_menu_items ( $array, $index, $order, $natsort = FALSE, $case_sensitive = FALSE ) {
if( is_array ( $array ) && count( $array ) > 0 ) {
foreach ( array_keys ( $array ) as $key )
$temp[$key] = $array[$key]->$index;
if( ! $natsort ) {
if ( strtolower( $order ) == 'asc' )
asort( $temp );
else
arsort( $temp );
}
else
{
if ( $case_sensitive === true )
natsort( $temp );
else
natcasesort( $temp );
if( strtolower( $order ) != 'asc' )
$temp = array_reverse ( $temp , TRUE );
}
foreach( array_keys ( $temp ) as $key )
if ( is_numeric ( $key ) )
$sorted[] = $array[$key];
else
$sorted[$key] = $array[$key];
return $sorted;
}
return $sorted;
}

/*
* Adds a class to first/last menu item.
*
* Uses update_post_meta() to update a nav menu item.
*
* @param int $menu_id Menu ID, defaults to 0.
* @param int $parent_id Menu item ID, defaults to 0.
* @param string $newclass Class to add, defaults to 'first'.
* @param boolean $remove Remove class from other children, defaults to true.
* @return boolean, false: if no $menu_id or $parent_id, else true.
*/
function wps_update_classes( $menu_id = 0 , $parent_id = 0 , $newclass = 'first' , $firstlast = 'first' , $remove = true ) {

// Validate inputs
$menu_id = intval ( $menu_id );
$parent_id = intval ( $parent_id );

if ( ( $menu_id == 0 ) || ( $parent_id == 0 ) || ( !is_bool ( $remove ) ) || ( !is_string ( $newclass ) ) || ( !is_string ( $firstlast ) ) )
return false;

// Get & filter nav menu items
$nav_menu_items = wp_get_nav_menu_items( $menu_id , array( 'post_status' => 'publish,draft' ) );
$children = get_nav_menu_item_children( $parent_id , $nav_menu_items );
if ( strtolower( $firstlast ) == 'last' )
$children = wps_sort_nav_menu_items( $children , 'menu_order' , 'desc' );
$first_item = true;

// Cycle through child nav menu items
foreach ( $children as $child ) {
if ( $first_item ) {
//found first item
$first_item = false;
$match = false;

// Cycle through to check for first
foreach ( $child->classes as $class ) {
// Match found
if ( $class == $newclass ) {
$match = true;
break;
}
}

// Update Post if match found
if ( ! $match ) {
if ( $child->classes[0] == '' )
$child->classes[0] = $newclass;
else
$child->classes[] = $newclass;

$menu_item_data = array(
'menu-item-classes' => $child->classes,
);
update_post_meta( $child->ID, '_menu_item_classes', $child->classes );
}
continue;
}

// Cycle through and remove $newclass from other children
if ( $remove ) {
foreach ( $child->classes as $key => $class ) {

// If match, remove $newclass from other children
if ( $class == $newclass ) {
$child->classes[$key] = '';
update_post_meta( $child->ID, '_menu_item_classes', $child->classes );
}
}
}
}

return true;
}
[/php]

So to call this function, you can use something like this:
[php]
add_action( 'init' , 'wps_update_menus' );
function wps_update_menus() {
wps_update_classes( 3 , 277 );
wps_update_classes( 3 , 7 , 'last' , 'last' );
}
[/php]
This bit of code adds 'first' to the first child of menu item 277 on menu 3 and 'last' to the last child of menu item 7 on menu 3.

Written by Travis Smith · Categorized: Tutorials, WordPress

Sep 29 2011

How to Include Another Post Type and Custom Taxonomy on the Genesis Blog Page

So recently, someone asked me to help them assimilate two post types on the Genesis blog page. Since because of the Genesis loops, this becomes quite easy. So here's what we need to do:

  1. Setup the Template Name
  2. Create the Custom Loop
  3. Modify the Post Meta
  4. Customize the Content Display

Setup the Template Name

First and as always, we need to set up the template. You can start by scratch, which this tutorial will do, or you can copy page_blog.php from the genesis folder.
[php]<?php
/**

Template Name: Blog

*/
[/php]

You may want to change the template name to something different so there aren't any confusions with Genesis's version. So something like this would work:
[php]<?php
/**

Template Name: Custom Blog

*/
[/php]

Create the Custom Loop

Now, I have a site with multiple custom post types and what I want to do is to combine two of those post types (post and wps_videos) into the blog feed. Then I want to limit them based on the Genesis category settings as well as incorporate the Video Category (wps_vidcats) in the same manner.

So first, I have to unhook the genesis standard loop.
[php]
remove_action('genesis_loop', 'genesis_do_loop');
[/php]

Then I add my own loop with its custom function.
[php]
add_action( 'genesis_loop', 'wps_custom_do_loop' , 5 );
function wps_custom_do_loop() {
$include = genesis_get_option( 'blog_cat' );
$exclude = genesis_get_option( 'blog_cat_exclude' ) ? explode( ',' , str_replace ( ' ' , '' , genesis_get_option( 'blog_cat_exclude' ) ) ) : '';
[/php]

These lines are right out of the Genesis standard loop. They pull the information set on the Theme Settings page and place them in variables to be used later. However, these are limited to just categories. Now, it is important to note that $include only contains one category id and $exclude contains an array of categories (even if there is only one).

Now, I need to build my $args. In my args, I want to add my post types as well as build my taxonomy query. So continuing inside wps_custom_do_loop:
[php]
$args = array(
'showposts' => genesis_get_option('blog_cat_num'),
'post_type' => array( 'post' , 'wps_videos' ),
'tax_query' => array(
'relation' => 'OR',
array(
'taxonomy' => 'wps_vidcategory',
'field' => 'id',
'terms' => array( 92 )
),
array(
'taxonomy' => 'category',
'field' => 'id',
'terms' => array( $include )
),
)
);
[/php]

So let me break this down for you. 'showposts' pulls from the Genesis Theme Settings page. 'post_type' is where we add the registered names of all the post types we would like to include in an array. 'tax_query' is where I limit the query based on my requirements. Now I wanted to only include posts from one category, which was set on the Genesis Theme Settings page, and I also wanted to do likewise with my videos and include videos from one specific Video Category (here term ID of 92). And since posts and videos do not share the same taxonomy, the tax_query is simple. So, in summary, I wanted posts from one category ($include) OR (and that's my relation argument) posts from my custom taxonomy video category (here 92).

Now, if I wanted, I could replace the last array with a different array to allow for all categories except (again based on category ids entered in Genesis Theme Settings). It would look something like this:
[php]
$args = array(
'showposts' => genesis_get_option('blog_cat_num'),
'post_type' => array( 'post' , 'wps_videos' ),
'tax_query' => array(
'relation' => 'OR',
array(
'taxonomy' => 'wps_vidcategory',
'field' => 'id',
'terms' => array( 92 )
),
array(
'taxonomy' => 'category',
'field' => 'id',
'terms' => $exclude,
'operator' => 'NOT IN'
),
)
);
[/php]

Now, we can finish the function by calling the Genesis Custom Loop.
[php]

genesis_custom_loop( $args );
}
[/php]

So all together the function looks like this (to simply limit posts to one category and vids from another category):
[php]<?php
remove_action('genesis_loop', 'genesis_do_loop');
add_action( 'genesis_loop', 'custom_do_loop' , 5 );

function custom_do_loop() {
$include = genesis_get_option('blog_cat');
$exclude = genesis_get_option('blog_cat_exclude') ? explode(',', str_replace(' ', '', genesis_get_option('blog_cat_exclude'))) : '';
$cf = genesis_get_custom_field('query_args'); /** Easter Egg **/
$args = array(
'showposts' => genesis_get_option('blog_cat_num'),
'post_type' => array( 'post' , 'wps_videos' ),
'tax_query' => array(
'relation' => 'OR',
array(
'taxonomy' => 'wps_vidcategory',
'field' => 'id',
'terms' => array( 92 )
),
array(
'taxonomy' => 'category',
'field' => 'id',
'terms' => array( $include )
),
)
);
genesis_custom_loop( $args );
}
[/php]

Modify the Post Meta

Now, because my videos do not share the same taxonomy with posts (and it could have [dare I say, should have] but the client didn't want it that way). My posts on the blog page that are from the videos custom post type won't have any post meta. I could simply remove it, but since the client wanted it, I simply filter them.

To filter the post meta to include terms from categories and my video categories, simply do a basic if-then statement. Normally Genesis has $post_meta = '[ post_categories] [ post_tags]';. However, I wanted to change it to just display categories.
[php]<?php
/** Customize the post meta function */
add_filter( 'genesis_post_meta' , 'post_meta_filter' );
function post_meta_filter( $post_meta ) {
global $post;
if ( $post->post_type == 'wps_videos' ) {
$vid_cats = get_the_term_list( $post->ID, 'wps_vidcategory' , '' , ', ' , '' );
$post_meta = sprintf( '<span class="categories">%2$s%1$s</span> ', $vid_cats, 'Filed Under: ' );
}
else {
$post_meta = 'Filed Under: Custom Post Types, Genesis, Tutorials, WordPress';
}
return $post_meta;
}
[/php]

Customize the Content Display

Now, because of UX, the video custom post type had a metabox to make displaying the videos consistent. However, if we do nothing then the videos never appear, which is not what we want.

First, I must unhook the standard Genesis content function.
[php]
/** Customize the content */
remove_action( 'genesis_post_content', 'genesis_do_post_content' );
[/php]

Second, I write a basic if-then function to display my videos on the blog page.
[php]<?php
add_action( 'genesis_post_content', 'custom_do_post_content' );
function custom_do_post_content() {
global $post;
if ( $post->post_type == 'wps_videos') {
if( genesis_get_custom_field('_wps_videoembedcode') != '' ) {
?>
<div id="post-<?php the_ID(); ?>" class="video-entry">
<div class="video-embed">
<?php echo genesis_get_custom_field('_wps_videoembedcode'); ?>
</div><!-- end .video-embed -->
<div class="clear"></div>
<?php genesis_do_post_content(); ?>
</div><!-- end .video-entry -->
<?php
}
} //end wps_videos
else {
genesis_do_post_content();
}
}
[/php]

Now, in both, I simply referred back to the genesis_do_post_content() because I just wanted a way to insert my videos for posts with the video custom post type.

Now as with any Genesis template, to initiate the framework, we have to add the Genesis call.
[php]<?php
genesis();
?>[/php]

All Together

[php]<?php
/**

Template Name: Custom Blog

*/

// Custom Loop
remove_action('genesis_loop', 'genesis_do_loop');
add_action( 'genesis_loop', 'custom_do_loop' , 5 );
function custom_do_loop() {
$include = genesis_get_option('blog_cat');
$exclude = genesis_get_option('blog_cat_exclude') ? explode(',', str_replace(' ', '', genesis_get_option('blog_cat_exclude'))) : '';
$cf = genesis_get_custom_field('query_args'); /** Easter Egg **/
$args = array(
'showposts' => genesis_get_option('blog_cat_num'),
'post_type' => array( 'post' , 'wps_videos' ),
'tax_query' => array(
'relation' => 'OR',
array(
'taxonomy' => 'wps_vidcategory',
'field' => 'id',
'terms' => array( 92 )
),
array(
'taxonomy' => 'category',
'field' => 'id',
'terms' => array( $include )
),
)
);
genesis_custom_loop( $args );
}

// Customize the post meta function
add_filter( 'genesis_post_meta' , 'post_meta_filter' );
function post_meta_filter( $post_meta ) {
global $post;
if ( $post->post_type == 'wps_videos' ) {
$vid_cats = get_the_term_list( $post->ID, 'wps_vidcategory' , '' , ', ' , '' );
$post_meta = sprintf( '<span class="categories">%2$s%1$s</span> ', $vid_cats, 'Filed Under: ' );
}
else {
$post_meta = 'Filed Under: Custom Post Types, Genesis, Tutorials, WordPress';
}
return $post_meta;
}

// Customize the content
remove_action( 'genesis_post_content', 'genesis_do_post_content' );
add_action( 'genesis_post_content', 'custom_do_post_content' );
function custom_do_post_content() {
global $post;
if ( $post->post_type == 'wps_videos') {
if( genesis_get_custom_field('_wps_videoembedcode') != '' ) {
?>
<div id="post-<?php the_ID(); ?>" class="video-entry">
<div class="video-embed">
<?php echo genesis_get_custom_field('_wps_videoembedcode'); ?>
</div><!-- end .video-embed -->
<div class="clear"></div>
<?php genesis_do_post_content(); ?>
</div><!-- end .video-entry -->
<?php
}
} //end wps_videos
else {
genesis_do_post_content();
}
}

genesis();
?>
[/php]

Written by Travis Smith · Categorized: Custom Post Types, Genesis, Tutorials, WordPress

Sep 12 2011

How to Add a Login Form to the Primary Navigation Menu in Genesis

Someone contacted me to develop a function that would add a login form to the primary navigation for their Genesis menu, and I would like to share it with you.

Primary Navigation with Login

[php]';
$login .= '';
$login .= '';
$login .= '';
$login .= '';
$login .= '';
$menu .= '

  • ' . $login . '
  • ';
    }
    // if logged in, do logout link
    else {
    global $current_user;
    get_currentuserinfo();
    $logout = '';
    $logout = 'Welcome ' . $current_user->display_name;
    $logout .= 'Logout';
    $menu .= '

  • ' . $logout . '
  • ';
    }

    return $menu;
    }
    [/php]

    Written by Travis Smith · Categorized: Tutorials, WordPress

    Aug 26 2011

    How to Add Menu Descriptions & Featured Images to WordPress Menu Items

    Recently I read an awesome post by Bill Erickson about customizing WordPress menus. However, there are two things I wanted this class to do that in its original form it doesn't do.

    So since out of the box, WordPress doesn't intuitively allow you to add descriptions to the menu without requiring some custom code, rather the Walker class extended.

    Since Bill has done an excellent job at this I will extend his code to add the options of having a featured image and/or descriptions applied based on depth.

    Add this to your functions.php file.

    <?php
    class Menu_With_Description extends Walker_Nav_Menu {
    function start_el( &$output, $item, $depth, $args ) {
    global $wp_query;
    $indent = ( $depth ) ? str_repeat( "t", $depth ) : '';
    $class_names = $value = '';
    $classes = empty( $item->classes ) ? array() : (array) $item->classes;
    $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
    $class_names = ' class="' . esc_attr( $class_names ) . '"';
    $output .= $indent . '<li id="menu-item-' . $item->ID . '"' . $value . $class_names . '>';
    $attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) . '"' : '';
    $attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) . '"' : '';
    $attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) . '"' : '';
    $attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) . '"' : '';
    // get user defined attributes for thumbnail images
    $attr_defaults = array(
    'class' => 'nav_thumb',
    'alt' => esc_attr( $item->attr_title ),
    'title' => esc_attr( $item->attr_title )
    );
    $attr = isset( $args->thumbnail_attr ) ? $args->thumbnail_attr : '';
    $attr = wp_parse_args( $attr, $attr_defaults );
    $item_output = $args->before;
    // thumbnail image output
    $item_output .= ( isset( $args->thumbnail_link ) && $args->thumbnail_link ) ? '<a' . $attributes . '>' : '';
    $item_output .= apply_filters( 'menu_item_thumbnail', ( isset( $args->thumbnail ) && $args->thumbnail ) ? get_the_post_thumbnail( $item->object_id, ( isset( $args->thumbnail_size ) ) ? $args->thumbnail_size : 'thumbnail', $attr ) : '', $item, $args, $depth );
    $item_output .= ( isset( $args->thumbnail_link ) && $args->thumbnail_link ) ? '</a>' : '';
    // menu link output
    $item_output .= '<a' . $attributes . '>';
    $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
    // menu description output based on depth
    $item_output .= ( $args->desc_depth >= $depth ) ? '<br /><span class="sub">' . $item->description . '</span>' : '';
    // close menu link anchor
    $item_output .= '</a>';
    $item_output .= $args->after;
    $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    }
    }
    view raw Menu_With_Description.php hosted with ❤ by GitHub

     

    All Menus

    To highjack ALL of your menus, enter this code in your functions.php.

    <?php
    add_filter( 'wp_nav_menu_args', 'my_add_menu_descriptions' );
    function my_add_menu_descriptions( $args ) {
    $args['walker'] = new Menu_With_Description;
    $args['desc_depth'] = 0;
    $args['thumbnail'] = true;
    $args['thumbnail_link'] = false;
    $args['thumbnail_size'] = 'nav_thumb';
    $args['thumbnail_attr'] = array( 'class' => 'nav_thumb my_thumb', 'alt' => 'test', 'title' => 'test' );
    return $args;
    }
    view raw my_add_menu_descriptions.php hosted with ❤ by GitHub

    Menus Based on Location

    To highjack a menu based on registered and assigned location, then use this code in your functions.php.

    <?php
    add_filter( 'wp_nav_menu_args', 'my_add_menu_descriptions' );
    function my_add_menu_descriptions( $args ) {
    if ( $args['theme_location'] == 'primary' ) {
    $args['walker'] = new Menu_With_Description;
    $args['desc_depth'] = 0;
    $args['thumbnail'] = true;
    $args['thumbnail_link'] = false;
    $args['thumbnail_size'] = 'nav_thumb';
    $args['thumbnail_attr'] = array( 'class' => 'nav_thumb my_thumb', 'alt' => 'test', 'title' => 'test' );
    }
    return $args;
    }
    view raw my_add_menu_descriptions.php hosted with ❤ by GitHub

     

    Menus via WordPress Custom Menu Widget

    To highjack a custom menu based menu id that is called using the custom menu widget, or even a manual method (if the menu is being called by a location, you must use 'theme_location'), then use this code in your functions.php. This will highjack any menu called by the custom menu widget assuming you only have the standard registered theme locations. The example below assumes a standard theme custom menu registered locations for Genesis. Change 'primary' and/or 'secondary' to whatever your theme adds and add whatever more menus that your theme has to only target the custom menu widget.

    <?php
    add_filter( 'wp_nav_menu_args', 'my_add_menu_descriptions' );
    function my_add_menu_descriptions( $args ) {
    if ( $args['theme_location'] != 'primary' && $args['theme_location'] != 'secondary' ) {
    $args['walker'] = new Menu_With_Description;
    $args['desc_depth'] = 0;
    $args['thumbnail'] = true;
    $args['thumbnail_link'] = false;
    $args['thumbnail_size'] = 'nav_thumb';
    $args['thumbnail_attr'] = array( 'class' => 'nav_thumb my_thumb', 'alt' => 'test', 'title' => 'test' );
    }
    return $args;
    }
    view raw my_add_menu_descriptions.php hosted with ❤ by GitHub

    There is a caveat though. There are certain menu items that may not have a featured image such as custom links, categories, etc. There is a possible work-around that I am trying to work out.

    Here is the result of a sandbox description and featured images for all types (not just pages and posts), which I will be posting soon or writing up into a plugin...

    Sandbox Genesis Menu with Descriptions and Featured Images

    Written by Travis Smith · Categorized: Tutorials, WordPress

    • « Previous Page
    • 1
    • 2
    • 3
    • 4
    • …
    • 18
    • Next Page »
    • Twitter
    • Facebook
    • LinkedIn
    • Google+
    • RSS

    Copyright © 2025 � WP Smith on Genesis on Genesis Framework � WordPress � Log in