About Travis Smith

As a WordPress Enthusiast, Travis writes about his journey in WordPress trying to help other WordPress travelers and enthusiasts with tutorials, explanations, & demonstrations of the things he learns.

post

How to orderby include Argument for get_terms()

WordPress 3.5 came out with an awesome feature of ordering by post__in (Codex). So when I got to my current issue, I noticed that I could not use the default orderby options (alphabetical title, ID, etc.), so the code used to create the post__in orderby can also be extended to be used for get_terms, which by default is not available in WordPress core. However, there is a great filter to enable this (see WordPress ticket).

Call get_terms()

So, first, I need to setup the function. In this scenario, I am using WooCommerce, but it could work with any theme, or ecommerce solution. For more information on get_terms() please see the WordPress Codex.

<?php

/**
 * Output the homepage categories HTML Markup
 *
 * @uses wps_category_image() Outputs image HTML Markup
 */
function wps_homepage_categories() {
  
	$args = array(
		'orderby'       => 'include', 
		'order'         => 'ASC',
		'hide_empty'    => false, 
		'include'       => array( 28 /* Appearal */, 27 /* Accessories */, 30 /* Outerwear */, 29 /* Hiking */, 22 /* Grooming */, ),
		'fields'        => 'all', 
		'pad_counts'    => false, 
		'd2c_home'      => true, //optional
	); 
	$product_cats = get_terms( 'product_cat', $args );
	
	foreach ( $product_cats as $cat ) {
		wps_category_image( $cat->term_id, $size );
	}
}

In this code, I use wps_category_image() which outputs the WooCommerce category image.

<?php

/**
 * Outputs HTML markup for category image for WooCommerce.
 *
 * @param  int    $cat_id  Category ID.
 * @param  string $size    Image size.
 * @param  array  $attr    Image attributes.
 * @return string $orderby Modified orderby SQL string.
 */
function wps_category_image( $cat_id, $size, $attr = array() ) {
  // get the thumbnail id user the term_id
  $thumbnail_id = get_woocommerce_term_meta( $cat_id, 'thumbnail_id', true ); 
  
  // get the image URL
  $image = wp_get_attachment_url( $thumbnail_id ); 
  
  // print the IMG HTML
  echo wp_get_attachment_image( $thumbnail_id, $size, false, $attr );

}

Filter get_terms_orderby

Next, is the really cool part. You want to filter the get_terms_orderby SQL.

<?php

add_filter( 'get_terms_orderby', 'wps_get_terms_orderby', 10, 2 );
/**
 * Modifies the get_terms_orderby argument if orderby == include
 *
 * @param  string $orderby Default orderby SQL string.
 * @param  array  $args    get_terms( $taxonomy, $args ) arg.
 * @return string $orderby Modified orderby SQL string.
 */
function wps_get_terms_orderby( $orderby, $args ) {
  if ( isset( $args['orderby'] ) && 'include' == $args['orderby'] ) {
		$include = implode(',', array_map( 'absint', $args['include'] ));
		$orderby = "FIELD( t.term_id, $include )";
	}
	return $orderby;
}

First, you need to check to see if include is the preferred orderby argument.

Second, you want to sanitize it with absint().

Third, set the order to the FIELD include (see here for more information).

post

Add a Nagging Fixed Top Menu to Your Genesis Site

Recently, someone asked me to assist them with their nagging menu. Simply they wanted a menu that became fixed at the top after the user scrolled past the menu. In their case, they had a primary navigation menu at the top and then a secondary menu below the slider. So when the user scrolled past the slider to the store, the secondary menu would be fixed at the top as the user scrolled through the various store items. So I pointed them to an online tutorial by 1stwebdesigner.com (with example) that would help them get about 75% there. In some WordPress themes, this would get you all the way, but with Genesis, the JavaScript needed some massaging to be 100% correct. (NOTE: If you are reading this post on the single page, you can see this example on this page.)

The Script

First, let’s review the script needed. I modified the script from 1stwebdesigner.com for Genesis themes.

jQuery(document).ready(function($) {
  "use strict";
  
  // Change #nav to #subnav for Genesis default Secondary Menu
  var menu = $('#nav').find('.menu'),
		pos = menu.offset();
		
		// Add Default class
		menu.addClass('default');
		$(window).scroll(function(){
			if($(this).scrollTop() > pos.top+menu.height() && menu.hasClass('default')){
				menu.fadeOut('fast', function(){
					$(this).removeClass('default').addClass('fixed').fadeIn('fast');
				});
			} else if($(this).scrollTop() <= pos.top && menu.hasClass('fixed')){
				menu.fadeOut('fast', function(){
					$(this).removeClass('fixed').addClass('default').fadeIn('fast');
				});
			}
		});

});

This script will make the primary menu appear at the top, but if you’d like the secondary menu to appear, then change #nav to #subnav. The rest is basic copy and paste. However, I recommend making two files: nagging-menu.js and nagging-menu.min.js.

Now, I place these two files in my js folder which is found beside my images folder in my child theme. Some people can place this within a lib (for library) or inc (for includes) folder within their child theme. Whatever you prefer, but if you change the location, be sure to change the code in functions.php (below) to match your location.

Enqueuing Script

Next, you want WordPress to enqueue the script.

<?php

add_action( 'init', 'wps_register_nagging_script' );
/**
 * Register Nagging script
 * 
 * @uses CHILD_THEME_VERSION set this via wp_get_theme()->Version
 * @link https://gist.github.com/4477270 Sets Child Theme Constants via wp_get_theme()
 * @link https://gist.github.com/4083811 For jQuery alternative to be placed in footer
 */
function wps_nagging_script() {
  $suffix = ( WP_DEBUG || SCRIPT_DEBUG ) ? '.js' : '.min.js';
  wp_enqueue_script(
    'nagging-menu',
    get_stylesheet_directory_uri() . '/js/nagging-menu' . $suffix,
    array( 'jquery' ),
    CHILD_THEME_VERSION, // I set this via wp_get_theme()->Version, @link https://gist.github.com/4477270 
    true 
  );
} 

In this function, I have a tertiary statement determining the suffix. For those of you who don’t know what that is, it is a shortcut for an if-then block. For example, instead of this:

if ( WP_DEBUG || SCRIPT_DEBUG )
    $suffix = '.js';
else
    $suffix = '.min.js';

We simply can write:

$suffix = ( WP_DEBUG || SCRIPT_DEBUG ) ? '.js' : '.min.js';

This reads: “If WP_DEBUG or SCRIPT_DEBUG is true, then assign suffix variable to ‘.js’ else assign the suffix variable to ‘.min.js’.” So what then are WP_DEBUG or SCRIPT_DEBUG? These are WordPress constants for debugging, which all developers regardless of skill should have on while developing a site.

So, my functions-enqueue.php code enqueues the appropriate script based on whether WordPress has been optimized for output or for debugging (nothing is worse than trying to access a JavaScript file when debugging and the JS file being minimized).

However, this function enqueues this script globally on every page. Some, however, may want to not have the script on every page, so then you would register the script and enqueue it conditionally, as below.

<?php

add_action( 'init', 'wps_register_nagging_script' );
/**
 * Register Nagging script
 * 
 * @uses CHILD_THEME_VERSION set this via wp_get_theme()->Version
 * @link https://gist.github.com/4477270 Sets Child Theme Constants via wp_get_theme()
 * @link https://gist.github.com/4083811 For jQuery alternative to be placed in footer
 */
function wps_register_nagging_script() {
  $suffix = ( WP_DEBUG || SCRIPT_DEBUG ) ? '.js' : '.min.js';
  wp_register_script(
    'nagging-menu',
    get_stylesheet_directory_uri() . '/js/nagging-menu' . $suffix,
    array( 'jquery' ),
    CHILD_THEME_VERSION, // I set this via wp_get_theme()->Version, @link https://gist.github.com/4477270 
    true 
  );
} 

add_action( 'wp_enqueue_scripts', 'wps_nagging_script' );
/**
 * Enqueue Nagging script if on home/archive page
 */
function wps_nagging_script() {
  if ( is_home() || is_front_page() || is_archive() || is_tax() )
    wp_enqueue_script( 'nagging-menu' );
}

The Style

Minimally, you need this CSS to make this menu happen (though you don’t really need the background possibly or the box-shadow properties).

#nav .fixed,
#subnav .fixed,
.fixed {
	background: rgb(0,0,0); /* Fallback */
	background: rgba(0,0,0,0.97); /* All modern browsers */
	filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#00000000', endColorstr='#00000000'); /* IE */
	-webkit-box-shadow: 0 0 40px #222;
	-moz-box-shadow: 0 0 40px #222;
	box-shadow: 0 0 40px #222;
	left: 0;
	top: 0;
	position: fixed;
	width: 100%;
}

#nav .default,
#subnav .default,
.default {
}

You can do a whole lot here, just as 1stwebdesigner.com does, to fancy up the menu as it sits on top.

post

The Role of Online Learning for Churches with WordPress

Online Church Opportunities

Online Church OpportunitiesIn my experience, churches have failed dismally in the area of providing learning opportunities to their members. Please don’t get me wrong here…many churches have great learning opportunities, in person, one, maybe two, days a week. Typically, however, as it pertains to online opportunities, churches typically only provide the Sunday Morning message as a podcast, and that’s it! It is true that some churches have more elaborate children ministries’ resources for parents and children. Yet, for the most part, opportunities for teens are typically centered around social media (if at all) and for adults, abismally non-existent. Education pastors design and develop curricula, possibly even publish the curriculum. Rarely, however, do churches provide online member areas to provide more than just the sermon podcast. Churches rarely integrate the sermon with supportive learning exercises during the week.

Yes, there is power in the preaching of the Word of God. Recently, my own pastor of a larger church in Atlanta admitted from the pulpit that he doubts that any of his sermons will be remembered. Yet, he believes that the sermons in totality over the course of a year or more will have an impact. What if his sermons can have even more of an impact through online supporting materials? Journal questions? Discussion boards? Supportive online inductive Bible Studies? Etc. What if?
Church Podcast
Almost any full-time Evangelist would admit that their job is “easy.” It’s easy to go in and preach and leave. They, however, would also admit that the difficult part of their job is knowing whether the church will effectively follow-up with the fruit of their labor. Many times, people fall through the cracks. So I am suggesting that online activities and opportunities, such as “I’m a new believer. Now what?” kind of courses. Just as new hire orientation greatly helps organizations orient new employees to their culture, the church can do something very similar.

Recently, I was contacted by one church who wanted to do a series where they gave the sermon, provided extra videos for Monday through Wednesday with follow-up discussion questions for their small groups Tuesday through Saturday. It’s the first time they’ve done this! What a great idea! One very similar model would be Pantego Bible Church when Randy Frazee as described in The Connecting Church.The Connecting Church by Randy Frazee They integrate the sermon with their community group curricula so that the big idea or the main proposition is studied through the week at different levels/depth, embodied, and thoroughly learned. So instead of the believer being bombarded with all sorts of knowledge on Sunday AM, Sunday PM, Wednesday PM, and any other day. It’s tragic that though churches offer so much learning opportunities, the body of Christ in America is becoming more and more biblically illiterate and unaware (from Dallas Theological Seminary survey but supported by Barna here and here).

Now, if churches would provide online modules to supplement the sermons, life change can be reinforced during the week thus making a deeper impact and a deeper change. Furthermore, besides further formal (courses and workshops) or informal learnings (such as journal/reflection questions, more videos, other podcasts or presentations, blog entries, etc.), if churches provide discussion boards/forums (via bbPress) or various social online situations (BuddyPress), immense growth can happen, maybe even have exponential, grassroots growth. Not only can spiritual growth take place, if an authentic and dynamic community can be encouraged and managed, then the church becomes even more connected…more like the church. However, in larger communities and cities where members are greatly dispersed throughout the city (and with traffic as bad as it is in Atlanta!!), having an online arena would be a great place to connect during the week. Instead, churches depend on email newsletters (e.g., MailChimp & Constant Contact), and well…I have no idea what else.

Recently, a friend of mine developed a site for pastors to network about small groups, Small Group Network utilizing BuddyPress and bbPress. From their site,

Founded by Steve Gladen, the Small Group Network is a free world-wide network for leaders of small group ministry. Our goal is to provide these leaders with relevant information and resources while connecting them to each other so that they might build relationships and encourage one another in creating healthy small group ministries.

However, I believe this is completely doable with churches (Now the caveat with churches will be to determine the legal ramifications, forum moderation, etc. for extensions like BuddyPress and bbPress).

Many churches have classes or workshops for new members and new believers. However, they are often at the worst times. For example, my wife and I have been trying to become members of a church in Atlanta, but due to our schedule, due to sickness and other random circumstances (sometimes our fault even), it has been over a year since we began “trying” to become members. However, membership class is only offered either once a month or once a quarter. What if the church provided some online modules (via a Learning Management System, or also known as a LMS) and then only one Sunday morning discussion and conversation to finalize the memberships. This could be slated for one of the Sunday morning hours rotating elders and pastoral staff as needed/desired. In this manner, instead of a bottlenecked entry point, becoming members is entirely dependent on the member-to-be.

This can be done in WordPress alongside a church’s WordPress website. If the church wants to accomplish a course-like feel (like Moodle) then consider what Chris Lema just wrote about in his recent elearning post. The other approach would be Learn Dash, which I haven’t tried or tested. WooThemes will be releasing Sensei this month, which I am excited to see. WooThemes was nice enough to give me the plugin to test today, so I will be writing about it soon!

Yes, I can hear it now…”We like to have the interaction.” Or, “We like to see their faces.” Or, “As the church, we should be rubbing shoulders with one another.” Yes, very true. But how much interaction really takes place at medium to larger churches? In all honesty, not much. I am not negating meeting face-to-face and the importance of gathering together as believers. However, I am encouraging churches to optimize the face-to-face meeting times. Most of the workshops tend to be question-less anyways even though most of them provide opportunities for members-to-be to ask questions. I’ve sat through these seminars, and I find them extremely boring and hope and pray no one asks any questions. For the average member-to-be, I imagine that people fear asking questions, or the questions have percolated yet, or spouses and families haven’t had a chance to discuss what they’ve heard and aren’t able to come up with questions in less than 5 minutes. Instead, if online learnings (and every church has a base curriculum that needs to be pushed to the potential member) to provide a base for discussion, then membership classes can take meaning.

post

How to Add a Genesis Top Navigation System

Adding a top navigationn menu to a Genesis child theme is quite easy. There are a couple of approaches. First, one can simply move the primary navigation to the top.

<?php

/** Reposition the primary navigation */
remove_action( 'genesis_after_header', 'genesis_do_nav' );
add_action( 'genesis_before', 'genesis_do_nav' );

Howevever, if you are already using the primary navigation, this may not work for you and a different approach may be necessary.

The approach depends on what menus you are currently using (e.g., using both primary and secondary or just primary with secondary not registered, etc). You would need to first, register the menu and second, then, output the menu.

Register the Menu

First locate something like the following in your functions.php file.

If you don’t then, you have the default Genesis setup. This is the same as having the following in your functions.php file.

<?php

add_theme_support(
  'genesis-menus', 
	array(
		'primary'   => __( 'Primary Navigation Menu', 'child-domain' ) 
		'secondary' => __( 'Secondary Navigation Menu', 'child-domain' ) 
	)
);

So you have two options:

  1. If not using the secondary navigation, you can use secondary navigation as the top menu
  2. Create a new top menu navigation system

Use Secondary Navigation as Top Menu

Create Top Navigation

To create a new navigation system, you need to do the following in your functions.php:

<?php

add_theme_support(
  'genesis-menus', 
	array(
		'primary'   => __( 'Primary Navigation Menu', 'child-domain' ),
		'secondary' => __( 'Secondary Navigation Menu', 'child-domain' ), 
		'top'       => __( 'Top Navigation Menu', 'child-domain' ), 
	)
);

This will add a menu system of Top that you can find in Appearance > Menus. If you just want primary and top, remove the secondary menu from the middle.

<?php
 
add_theme_support(
  'genesis-menus', 
  array(
		'primary'   => __( 'Primary Navigation Menu', 'child-domain' ), 
		'top'       => __( 'Top Navigation Menu', 'child-domain' ), 
	)
);

Output the Menu

Finally, you will need to output the menu.

<?php

add_action( 'genesis_before', 'wps_do_top_nav' );
/**
 * Output Top Navigation
 */
function wps_do_top_nav() {
  /** Do nothing if menu not supported */
	if ( ! genesis_nav_menu_supported( 'top' ) )
		return;

	/** If menu is assigned to theme location, output */
	if ( has_nav_menu( 'top' ) ) {
		$args = array(
			'theme_location' => 'top',
			'container'      => '',
			'menu_class'     => genesis_get_option( 'nav_superfish' ) ? 'menu genesis-nav-menu menu-top superfish' : 'menu genesis-nav-menu menu-top',
			'echo'           => 0,
		);

		$nav = wp_nav_menu( $args );

		/** Wrap nav menu with div and .wrap div if applied to #nav */
		$nav_output = sprintf( '<div id="top-nav">%2$s%1$s%3$s</div>', $nav, genesis_structural_wrap( 'nav', 'open', 0 ), genesis_structural_wrap( 'nav', 'close', 0 ) );

		echo $nav_output;
	}
}

This will output your top navigation the same as you output your primary navigation with all references to nav changed to top-nav.

post

Genesis Grid Loop in Genesis 1.9

Some people may be experiencing some issues with the Genesis Grid Loop in Genesis 1.9 (and rightly so).

if ( function_exists( 'genesis_grid_loop' ) ) {
	genesis_grid_loop(
		array(
			'features'              => 0,
			'feature_image_size'    => 0,
			'feature_image_class'   => 'alignright post-image',
			'feature_content_limit' => 0,
			'grid_image_size'       => 'thumbnail',
			'grid_image_class'      => 'alignleft',
			'grid_content_limit'    => 250,
			'more'                  => __( '[Read more...]', 'child-domain' ),
			'posts_per_page'        => 25,
			/** Remove categories from loop */
			'category__not_in'      => array( 1, 2, 3, )
		) 
	);
} else {
	genesis_standard_loop();
}

However, with Genesis 1.9, this will no longer work. Instead you must modify the query as you should via pre_get_posts hook. Bill Erickson has a great tutorial on how to do customize the WordPress Query, which I will also re-iterate here.

Custom Grid Loop Conditional

First, I love the Grid Loop setup that Gary and Bill did here. However, both Gary and Bill admit that there are other better options than using the genesis_grid_loop() such as Bill’s Better, Easier Grid Loop.

However, some sites are just not worth re-doing. So in the meantime a fix is necessary. So here it is. Personally, I would use the function child_is_doing_grid_loop() from the Advanced Grid Loop. This will be the function where you declare all the places that you want the Grid Loop to appear using the WordPress Conditionals. This will keep your code organized.

<?php

/**
 * Possibly amend the loop.
 * 
 * Specify the conditions under which the grid loop should be used.
 *
 * @author Bill Erickson
 * @author Gary Jones
 * @author Travis Smith
 * @link   http://code.garyjones.co.uk/genesis-grid-loop-advanced/
 * @link   http://wpsmith.net/2013/genesis/genesis-grid-loop-in-genesis-1-9/
 *
 * @return boolean Return true of doing the grid loop, false if not. 
 */
function wps_is_doing_grid_loop() {
 
  // Amend this conditional to pick where this grid looping occurs.
	// This says to use the grid loop everywhere except single posts,
	// single pages and single attachments.
	return ( ! is_singular() );
 
}

Modify the WordPress Query Correctly

Then you need to modify the WordPress Query via pre_get_posts hook. Here’s how you can modify the query to exclude a category.

<?php
 
add_action( 'pre_get_posts', 'wps_exclude_cat_in_grid' );
/**
 * Exclude Category from Grid
 * 
 * @author Bill Erickson
 * @author Travis Smith
 * @link http://www.billerickson.net/customize-the-wordpress-query/
 * @link http://wpsmith.net/2013/genesis/genesis-grid-loop-in-genesis-1-9/
 * @param object $query WP Query data
 *
 */
function wps_exclude_cat_in_grid( $query ) {
  
	if( $query->is_main_query() && wps_is_doing_grid_loop() ) {
		$query->set( 'cat', '-1,-2' );
	}
 
}

Here’s how you can modify the query to limit the query to a category.

<?php
 
add_action( 'pre_get_posts', 'wps_include_cat_in_grid' );
/**
 * Limit Query to one Category
 * 
 * @author Bill Erickson
 * @author Travis Smith
 * @link http://www.billerickson.net/customize-the-wordpress-query/
 * @link http://wpsmith.net/2013/genesis/genesis-grid-loop-in-genesis-1-9/
 * @param object $query WP Query data
 *
 */
function wps_include_cat_in_grid( $query ) {
  
  if( $query->is_main_query() && wps_is_doing_grid_loop() ) {
		$query->set( 'cat', '4' );
	}
 
}

Here’s how you can modify the query to change the posts_per_page.

<?php
 
add_action( 'pre_get_posts', 'wps_change_posts_per_page_in_grid' );
/**
 * Change Posts Per Page
 * 
 * @author Bill Erickson
 * @author Travis Smith
 * @link http://www.billerickson.net/customize-the-wordpress-query/
 * @link http://wpsmith.net/2013/genesis/genesis-grid-loop-in-genesis-1-9/
 * @param object $query WP Query data
 *
 */
function wps_change_posts_per_page_in_grid( $query ) {
  
	global $wp_the_query;
	if( $query->is_main_query() && wps_is_doing_grid_loop() ) {
		$query->set( 'posts_per_page', '15' );
	}
 
}

Please note that all of this code belongs in functions.php or some other custom file. I personally recommend a custom query.php or grid.php file to keep your code clean.

So back in your template file, you can change the original loop function to:

if ( function_exists( 'genesis_grid_loop' ) ) {
	genesis_grid_loop(
		array(
			'features'              => 0,
			'feature_image_size'    => 0,
			'feature_image_class'   => 'alignright post-image',
			'feature_content_limit' => 0,
			'grid_image_size'       => 'thumbnail',
			'grid_image_class'      => 'alignleft',
			'grid_content_limit'    => 250,
			'more'                  => __( '[Read more...]', 'child-domain' ),
		) 
	);
} else {
	genesis_standard_loop();
}

These are the necessary components for displaying the loop, which is modified via pre_get_posts now.

post

Create Genesis Constants Based on Theme

In my child themes, this little function that I wrote based on the new wp_get_theme() function (Codex, WP Ticket). Previously, I had to create style.css with all the data and then had to do the same thing in functions.php (or my child init.php). So to save 30 seconds or so, I have no fully automated this entirely, so everything in style.css matters. Everything!

Let’s step through the style.css header.

/*
  Theme Name: Genesis Child
  Theme URI: http://wpsmith.net/
  Description: Default Genesis Child Theme.
  Author: Travis Smith
  Author URI: http://wpsmith.net/
  Version: 1.0.0
  Text Domain: genesis-child
  Tags: black, white, red, one-column, two-columns, three-columns, left-sidebar, right-sidebar, fixed-width, custom-background, custom-header, custom-menu, editor-style, full-width-template, sticky-post, theme-options, threaded-comments, translation-ready

  Template: genesis
  Template Version: 1.9.0

  License: GNU General Public License v3.0 (or later)
  License URI: http://opensource.org/licenses/gpl-license.php
*/

Obviously, Template and Template version should be set for every child theme.

So Theme Name will determine CHILD_THEME_NAME, which will automatically appear in the Genesis Footer connected with the Theme URI, which is set as CHILD_THEME_URL. WordPress pulls in the Description on the Appearance > Themes page. I have an admin script that I make better use of Author and Author URI besides the basic WordPress listing them in Appearance > Themes (as it also uses Tags). It places it in the footer stating, “Thank you for creating with WordPress & CHILD_THEME_NAME designed by CHILD_DEVELOPER” linked with CHILD_DEVELOPER_URL.

What’s even more awesome is that Genesis 1.9 makes use of CHILD_THEME_VERSION if it is set in enqueuing the style. So, it’s important, but I also use it elsewhere. Then the even more awesome thing is Text Domain! Text Domain sets two constants: CHILD_DOMAIN (localization) and CHILD_THEME_SETTINGS (admin page). So if Text Domain is set as ‘genesis-child’ then the CHILD_DOMAIN will be ‘genesis-child’ and the CHILD_THEME_SETTINGS will be ‘genesis-child-settings’.

Now, I don’t have to think a single bit for my theme constants. I just use this function in all child themes I create.

post

Add private/draft/future/pending pages to parent dropdown in page attributes and Quick Edit

Fast WordPress Hosting