Testing these waters

Okay, this is the second time I’m actually typing on this Gutenberg plugin and I’m not 100% sure how I feel just yet. The reason is because I am so used to working with the previous TinyMCE editor and working with some HTML markup in order to create my posts. I will say that I do like some of the things already laid out. Being able to add things with a click of a button is a great thing. I know I won’t be writing an article every day so this really won’t be a huge hinderance for me. I can, however, see a good side to those who live in the editor. It may take some getting used to for some but in the long run, it will be a better experience.

A small primer on theme mods

Oh, the many things I encounter while doing reviews is amazing.

One of the reasons I love contributing to the review team is to get a better understanding of how WordPress at its core works and it is because of this I feel like there are some things that still are not being mentioned or shared.

A fairly good example of this is what I saw today. I’ve seen this on several themes but I think I finally reached a point where it really, truly irks me.

What are settings?

WordPress themes can use two things to save user inputs – or better yet theme mods. The neat part is there are two ways those can be saved. Using option or theme_mod when registering a setting in the customizer. What I want to focus on for this is the use of theme_modsince it is the recommended method for most themes. Notice I say most. There are cases where it makes sense to use option but that’s for another time. The WordPress theme mods are saved and retrieved using a few functions.

  • get_theme_mods() – gets all theme settings
  • get_theme_mod() – gets a single setting
  • set_theme_mod() saves a theme setting

Now, there are two other functions for theme mods.

  • remove_theme_mod() – remove a single theme setting
  • remove_theme_mods() – removes all theme settings

Those are least likely to be used but they are good to know.

How it works

The WordPress customizer is magic. Okay, not completely and I only say that because if you look at how things work in the JavaScript file it quite literally says, “return magic;

The way the customizer saves things is by using a few object methods. It uses the save() method, which calls the update() method, and tfinally the set_root_value() method of the Setting class. It’s here where our setting actually gets saved.

If we look over the highlighted code we can see what is actually happening.

protected function set_root_value( $value ) {
	$id_base = $this->id_data['base'];
	if ( 'option' === $this->type ) {
		$autoload = true;
		if ( isset( self::$aggregated_multidimensionals[ $this->type ][ $this->id_data['base'] ]['autoload'] ) ) {
			$autoload = self::$aggregated_multidimensionals[ $this->type ][ $this->id_data['base'] ]['autoload'];
		}
		return update_option( $id_base, $value, $autoload );
	} elseif ( 'theme_mod' === $this->type ) {
		set_theme_mod( $id_base, $value );
		return true;
	} else {
		/*
		 * Any WP_Customize_Setting subclass implementing aggregate multidimensional
		 * will need to override this method to obtain the data from the appropriate
		 * location.
		 */
		return false;
	}
}

The default setting for registering a theme option is theme_mod and what this means is that when the user clicks that save button, the function set_theme_mod() will be triggered and the setting will be saved to the database. Super cool! Now, what does that little function actually do?

Well, let’s take a look over it:

function set_theme_mod( $name, $value ) {
	$mods = get_theme_mods();
	$old_value = isset( $mods[ $name ] ) ? $mods[ $name ] : false;

	/**
	 * Filters the theme mod value on save.
	 *
	 * The dynamic portion of the hook name, `$name`, refers to the key name of
	 * the modification array. For example, 'header_textcolor', 'header_image',
	 * and so on depending on the theme options.
	 *
	 * @since 3.9.0
	 *
	 * @param string $value     The new value of the theme mod.
	 * @param string $old_value The current value of the theme mod.
	 */
	$mods[ $name ] = apply_filters( "pre_set_theme_mod_{$name}", $value, $old_value );

	$theme = get_option( 'stylesheet' );
	update_option( "theme_mods_$theme", $mods );
}

It gets all the theme mods, then creates a filter for us to use, gets the name of the currently active theme, and finally updates an option.

An option?

Yes. An option. I know. I know. We were talking about theme mods but the way the customizer works with theme_mods is by creating an associative array per theme. For example, if my theme were called For Real Yo, the $theme would be for-real-yo.

WordPress then turns it to a slug. So, the best way to get those options would be to get the option or use the core functions get_theme_mod() and get_theme_mods() to do things for me and because we like using good practices we use get_theme_mod() in order to get the single setting – or rather theme_mod.

You are probably wondering what get_theme_mods() does. I know I did when I first read the code.

function get_theme_mods() {
	$theme_slug = get_option( 'stylesheet' );
	$mods = get_option( "theme_mods_$theme_slug" );
	if ( false === $mods ) {
		$theme_name = get_option( 'current_theme' );
		if ( false === $theme_name )
			$theme_name = wp_get_theme()->get('Name');
		$mods = get_option( "mods_$theme_name" ); // Deprecated location.
		if ( is_admin() && false !== $mods ) {
			update_option( "theme_mods_$theme_slug", $mods );
			delete_option( "mods_$theme_name" );
		}
	}
	return $mods;
}

From the core code, we can see that it gets the theme slug, gets the option ( from the options table ) for the active theme, then it checks to see if it is populated or not, and finally returns the array of theme_mods.

So, why this post?

I am making this because the code that I stumbled across looked a little like:

<?php
/**
 *  Default theme options
 */
if ( ! function_exists( 'for_real_yo_default_options' ) ) :
	function for_real_yo_default_options() {
		$default_options = array(
			/* super long list of "defaults" */
		);
		return apply_filters( 'for_real_yo_defaults', $default_options );
	}
endif;


/**
*  Get theme options
*/
if ( ! function_exists( 'for_real_yo_theme_options' ) ) :

	function for_real_yo_theme_options() {

		$for_real_yo_defaults = for_real_yo_default_options();

		$for_real_yo_option_values = get_theme_mod( 'for_real_yo' );

		if ( is_array( $for_real_yo_option_values ) ) {
			return array_merge( $for_real_yo_defaults ,$for_real_yo_option_values );
		} else {
			return $for_real_yo_defaults;
		}
	}
endif;

Looks rather harmless, right? It is until you realize how they were registering the setting.

$wp_customize->add_setting(
	'for_real_yo[rando-setting]',
	array(
		'default' 			=> 'title-text',
		'sanitize_callback' => 'for_real_yo_sanitize_select'
	)
);

If you can spot the issue, awesome. If not, it is creating an array for one setting of a setting. Yes, a little odd to say the least but I’ll show a quick example.

Let’s say we are comparing one of the core themes with our above code. Okay, let us look at the returned array from each one. Twenty Seventeen would yeild something like:

Array
(
    [header_image] => path/to/file
    [header_image_data] => stdClass Object
        (
            [attachment_id] => id
            [url] => path/to/file
            [thumbnail_url] => path/to/file
            [height] => 1198
            [width] => 2000
        )

    [page_layout] => one-column
    [header_textcolor] => cfe23d
    [colorscheme] => light
    [colorscheme_hue] => 0
)

Now, if we look at the above example’s way of registering you can see the difference much better.

Array
(
    [for_real_yo] => Array
        (
            [some_setting] => 
            [another_setting] => 
            [top_bar_left] => menu
            [right_social] => 
            [right_hours] => 
        )

)

Hopefully this does help in understanding how theme_mods are saved and retrieved and does at least help out one person.

A metabox for your layout options

It’s no surprise I can be vocal when I am reviewing a theme. Many know that I’ll spurt out what I end up seeing in a lot of themes. There is one thing that really does drive me crazy though and that is when people copy and paste code to their theme without actually knowing how the code actually works.

One file that has really been rather popular is using a metabox in order to choose the layout of the post or page. That’s great. I love that ability but then again who doesn’t love having that control? I think what drives me bonkers is that this code is super predictable before the file is opened. The file adds two actions. One to add_meta_boxes and the second to the save_post hooks. Great! Very super simplistic and hard to mess up, right?

I created a gist with the name of the theme changed. The code is the same that I’ve seen in many other themes though. From authors who have several themes in the repo to new authors to the repo.

One of the first things that you may notice is the use of two globals.

global $post, $deargodwhy_sidebar_layout;

First there should be no reason for that and second those hooks pass the $post object. We’ll look at the first one: add_meta_boxes

Using the developer resources as a guide we see that the hook for adding metaboxes uses two arguments. The post type and the post.

do_action( 'add_meta_boxes', string $post_type, WP_Post $post )

The first one being the string of the current post type and the second being the WordPress post object. Now, what’s super cool about that is that we can now register a metabox in any post type we want and it does on every post type if we don’t pay attention to what we are doing. There is also one more hook we could potentially use in order to use a metabox in only one specified post type. That hook is add_meta_boxes_{$post_type} and the developer docs does explain it a little better. For example, if you wanted to add a metabox to only your EDD downloads, you could do something like:

add_action( 'add_meta_boxes_download', 'jmc_download_extra_metaboxes', 10 );
function jmc_download_extra_metaboxes( $post ) {
	// Do our magic here.
}

In order to now add our metabox we do need to use the function add_meta_box() so let’s take a look at how that function is used.

add_meta_box( $id, $title, $callback, $screen = null, $context = 'advanced', $priority = 'default', $callback_args = null )

Now, if you want to take a closer look at what each one of those parameters actually does then I suggest you take a look over the developer docs. It is well worth your time if you really want to understand how to create a better user experience and understand how WordPress creates those.

Another thing I wanted to look over was the save_post callback being used. The biggest issue is the use of the foreach() loop.

foreach( $deargodwhy_sidebar_layout as $field ){  
        //Execute this saving function
        $old = get_post_meta( $post_id, 'deargodwhy_sidebar_layout', true ); 
        $new = sanitize_text_field( $_POST['deargodwhy_sidebar_layout'] );
        if ( $new && $new != $old ) {  
            update_post_meta($post_id, 'deargodwhy_sidebar_layout', $new );  
        } elseif ('' == $new && $old ) {  
            delete_post_meta( $post_id,'deargodwhy_sidebar_layout',  $old );  
        } 
     }

The reason is it is creating an unnecessary loop. The only thing that needs to be checked is the value being input and to make sure that it is a valid option. A quick change to the code and we have:

if ( ! empty( $_POST['deargodwhy_sidebar_layout'] )
	&& in_array( $_POST['deargodwhy_sidebar_layout'], array( 'right-sidebar', 'no-sidebar' ), true )
	) {
	update_post_meta( $post_id, 'deargodwhy_sidebar_layout', $_POST['deargodwhy_sidebar_layout'] );
}

Knowing those things we could make changes to the file and not only will we have a better understanding of how WordPress creates metaboxes but we have a file that doesn’t pollute the $GLOBALS with info that we only use in one place. If you look at what those changes were in the diff, you will see that not a lot was changed. It only looks that way since I removed a lot of the linting errors.

Creating a diff file

The other day I made a quick video on how to create PHPCS reports. Later on during the day I was asked about creating a patch to meta. Of course I’m going to make another video to help somebody else out.

In the video I go over on how to create a diff file using SVN and atom. With that file you can submit patches to core and meta.

There are two places to look for. If you are submitting a new ticket, you will see a checkbox that will take you to an upload screen.

Or if you are contributing to an already existing ticket you will see a field where you can upload files.

Hope this helps some of you out!

Creating sample PHPCS reports

I created a quick video in hopes to help some people understand the great thing that is using the PHP_CodeSniffer and how good it can be for not only developing plugins but WordPress themes as well.

In the video I create two sample reports. The first one a source report and the second just a summary report. The documentation does provide some useful information to help along the way in creating those reports.

Hope this helps some people out!

It’s not about your theme

Lately I’ve stayed away from the theme review only because it can be such a negative feeling and a negative space. It’s not the people I interact with but rather those who feel like they have a solution for all the things.

I’m not saying I do and I don’t try to but what I do have is a feeling that things can only get worse.

Theme reviews have been great for my learning about WordPress as well as PHP. The last couple of weeks have been great in that we did manage to reduce the queue down by a lot and I mean a lot. We went from about 600 themes to 400. There were rules set in place and of course there will always be some sort of backlash whether it be from reviewers or authors. This time authors.

Okay, a lot of the time it’s authors.

I get it. I do. You want to share your creation with the world and the community. The thing many really forget is that you don’t have to have your listed in the repo for it to be shared.

Incentives

I’m for them but when it comes to certain things. I volunteer my time to conduct reviews and I don’t actually expect anything in return. Okay, that’s a bit of a lie because there is one thing I expect.

Gratitude.

The thing to remember is that I take time out of my day to look at code and pass on some knowledge when I can.

And it’s not a great feeling when you get back a slew of negativity and comments like it’s taking too long.

I’ll give an example.

Retail on Holidays

When I worked at Starbucks it would get crazy. We were one of the few places open. My last store we were open 24/7. You read that right. Rain, shine, local shoot-out, fire-next-door, gas line on fire down the street, we would be open. Okay a bit of an exaggeration but fairly true.

I recall one day we had not only a line in our lobby that was almost five feet out the door but we also had our drive-thru creating a circle around the building so as one new car would enter one would be leaving. This was Thanksgiving. This was Christmas week.

Every so often we would get one car that would chime-in with a solution:

You should limit to only one drink order per car.

Yes! Brilliant! This makes it so we only focus on one drink at a time. The thing is Starbucks standard is one drink at a time when you are on bar. Granted not always followed to the T but there is a great reason for that. Just ask any 5 year old partner and they will share knowledge with you.

Those holiday orders were always insane because a lot of the time it was 6 drinks for one car, 8 drinks for the next and the occasional food order with 4 sandwiches, a cake pop, and all the croissants in the store.  This of course creates a new set of obstacles if you weren’t used to that but seeing how as a barista you only should be focusing on making one drink at a time it can take a lot of time for one.

Setting a standard workflow does make it easier because you can then crank things out in an expected amount of time per drink or even per order.

The one drink at a time standard is so that every single cup of coffee, frappuccino, tea, or latte is not only to your needs but a quality drink as well.

Comparison

Okay. That’s great but what relevance does it have, right? See in the example above the barista is the theme author. You are the creator.

What happens when you start skipping steps, start making drinks out of order, or even forget to make them? The customer gets upset, you start holding up the queue of drinks and possible others along the way. Your customers suffer from this. So really your users suffer from this.

Much like baby steps: One at a time.

This needs to be your focus.

If you are a theme author, a theme shop, or just wanting to create for the sake of creating themes, you should have a workflow in place if you don’t already – specially if you are going to submit a theme to the WordPress.org repo.

One I suggest:

  • Design the theme
  • Design review of the theme
  • Begin coding the theme
  • Code review
    • Stress Cases
    • Who are you really coding for?
    • Testing Environment
  • Testing of the theme
    • Asking friends
    • Asking family
    • Reach out to community

Honestly, even having something in place is truly better than not. Asking for help is not a big deal in particular the testing of the theme. Reach out to your peers, reach out to companies, individuals. You would be amazed how much information you can actually get.

Don’t let your user suffer because you want to speed things up. I mean after all you don’t want to be giving out half empty cups of Gingerbread Lattes to an angry mother who is shopping for the last gaming console on one of the busiest weeks of the year, right?

WordPress and MediaElement styles

Okay, this is more of an experiment I was running because I was reached out by a friend about a theme question.

This actually got me thinking about the shortcodes. The audio and video ones in particular. The reason is that when you use the [audio] shortcode WordPress will use MediaElementJS and enqueue both the JavaScript file and the CSS stylesheet.

Turns our there is a filter for those! Well, two really. One for each one. I wanted to dig deep for this one because styling the player is something I have wanted to do for a long time. Today I found out I can!

Yes, I am excited about it.

Yes, I am writing about it.

Yes, I will share what I found with you.

The steps

This took me about a day’s worth of effort only because I didn’t really know what I was looking for. I knew I needed to figure out what styles were being used and where. By default WordPress registers a few scripts and styles for MediaElements. The styles are registered in the script-loader file. There are two that are registered. The second one –wp-mediaelement– depends on the first registered one so really it is loading two files when either shortcode is used.

Now, how did I find this out?

I looked up wp-mediaelement in the project and found 16 results. The first place I looked was the ajax-actions file only because it was the first result and I wanted to see how it was done as well. Looked at the file and noticed that it uses wpview_media_sandbox_styles() to get the stylesheet URLs but not exactly what I was looking for. Though it is a neat little function.

Next up was the media.php file. This was the one I really should have been looking in. 6 results and one was from the wpview_media_sandbox_styles function so I was making some progress I guess. In the first result it was inside of the wp_playlist_scripts() function and it enqueues the style and a playlist script. Not exactly what I need but getting close.

The second result landed me where I needed to be. A nice filter. The wp_audio_shortcode_library to be precise. What’s really nice is the video is much like it as well. It is wp_video_shortcode_library and they work the same way.

The Filters

apply_filters( 'wp_audio_shortcode_library', 'mediaelement' );
apply_filters( 'wp_video_shortcode_library', 'mediaelement' );

Pretty cool, right? So then how would it be used?

In the functions.php of your theme you could potentially do something like:

add_filter( 'wp_audio_shortcode_library', 'jmc_new_lib' );
add_filter( 'wp_video_shortcode_library', 'jmc_new_lib' );
function jmc_new_lib(){
	// Because we still want the script to load but not the styles
	wp_enqueue_script( 'wp-mediaelement' );
	wp_script_add_data( 'wp-mediaelement', 'conditional', 'lt IE 9' );

	// Enqueue our own styles here.
	wp_enqueue_style( 'jmc-media-styles', get_template_directory_uri() . '/css/media.css' );

	return '';
}

Super sweet if you ask me. That’s great and all but what about the markup? Now we have to think about what needs to be styled right?

Well, I’ve gone ahead and extracted some of the classes for both the audio and video markup to make it easier:

.mejs-offscreen {}
.mejs-container {}
.svg {}
.wp-audio-shortcode {}
.mejs-audio {}
.mejs-inner {}
.mejs-mediaelement {}
.mejs-layers {}
.mejs-poster {}
.mejs-layer {}
.mejs-controls {}
.mejs-button {}
.mejs-playpause-button {}
.mejs-play {}
.mejs-time {}
.mejs-currenttime-container {}
.mejs-currenttime {}
.mejs-time-rail {}
.mejs-time-total {}
.mejs-time-slider {}
.mejs-time-buffering {}
.mejs-time-loaded {}
.mejs-time-current {}
.mejs-time-handle {}
.mejs-time-float {}
.mejs-time-float-current {}
.mejs-time-float-corner {}
.mejs-duration-container {}
.mejs-duration {}
.mejs-volume-button {}
.mejs-mute {}
.mejs-horizontal-volume-slider {}
.mejs-horizontal-volume-total {}
.mejs-horizontal-volume-current {}
.mejs-horizontal-volume-handle {}
.mejs-clear {}
.wp-video {}
.wp-video-shortcode {}
.mejs-video {}
.mejs-overlay {}
.mejs-overlay-loading {}
.mejs-overlay-error {}
.mejs-overlay-play {}
.mejs-overlay-button {}
.mejs-volume-slider {}
.mejs-volume-total {}
.mejs-volume-current {}
.mejs-volume-handle {}
.mejs-fullscreen-button {}

Those are some of the common classes that are used in the final markup. It may not be a complete list but it is a starting point for many and I hope it does help somebody out in theming the audio and video post formats. I will mention this because I know it may be asked down the road: some of those classes may have inline styles so it would be w

I also created a quick gist for the files if you only wanted to target one media type. This is useful if the user has a playlist.

In the following example, I’ve removed the core action and am only documenting the basics.

// remove the scripts/styles originally enqueued
remove_action( 'wp_playlist_scripts', 'wp_playlist_scripts' );

// enqueue ours instead
add_action( 'wp_playlist_scripts', 'jmc_new_liststyles', 10, 2 );
function jmc_new_liststyles( $type, $style ) {
	// $type is the type of playlist either an 'audio' or 'video'.
	// $style can be core 'light' or 'dark' but can add more by having user input
	// and enqueueing the needed style.
	wp_enqueue_style( 'jmc-style', 'path/to/file' );

	// Because we still want to enqueue the script just not the style.
	wp_enqueue_script( 'wp-playlist' );
}

What’s cool about that is that you really can add your own styles if you want. I know there are some themes that take advantage of “skins” or color schemes and could really benefit from this. I may just try and do this on one of my days off or when I can. In the meantime I hope this helps some plugin authors and even more theme authors with styling and using core methods rather than relying on using wp_deregister_style() for this.

Getting WordPress Custom Post Types in the customizer

It’s no surprise I love a good theme. I love it even more when I get a choice of what can go where – extra cookie points if I don’t have to input that information. A while back I wrote out a post about presenting content within themes.

In the course of reviewing so many themes, I noticed one thing in common with many themes. They love trying to control my content, and that is great, as that is what they are meant to do; but when they start creating some content this is where my headache begins. Yes, there is some trivial content like a small span of text but that is very dismissable. What I’m talking about is when I see a theme using textarea when they register a theme setting. This concerns me. This worries me.

Why worry?

This worries me because I can insert a novel in that option. An entire novel if I wanted to. Okay, perhaps not an entire novel but about 4,294,967,295 characters in that theme option. Granted I’m never going to be doing that inside of an option but why would you even give me that option? What happens if I have a recipe that I would like to display? Would I have to copy and paste it or find a hackish way of doing it? I mean you could potentially use shortcodes but then you get an even bigger headache.

As a theme reviewer I try to think about different types of content a user could have. It makes it easy to know what to look for rather than having to rely on having the user ( me in this case ) input all that content or info all over again. Portability. It’s a great thing.

Using the customizer to get a live preview is what drove me to actually writing out this post. Earlier in the day I was trying out a different theme because I’m looking for a grid style. Not for the entire site but only some parts. Sort of a e-commerce if you will. I have the content, I have what I need. I am only looking to display it but when I’m asked to input what I already have over and over I just gave up.

Getting content

One of the things I would love to see more is a dropdown of my content. The customize menu component that was added to core is a great example of this. It gives you a list of all your pages, posts and even other post types that you have registered.

The other day I was talking to a few other theme reviewers and shared a snippet of code. I’ll post a simplified version first and then break it down and expand upon it as we progress.

add_action( 'customize_register', 'jmc_customize' );
function jmc_customize( $wp_customize ) {
	// get list of post types
	// Check if we have any
	// create an associative array for later use
	// register our setting
	// register our control
}

What’s super neat about that little snippet is that it will create a dropdown of post types that are registered. The second part of the snippet would be:

// get our setting and make sure it's not empty
if ( get_theme_mod( 'section-one-type' ) ) {
	// create a new WP_Query
	// create a new loop
	// make sure we wp_reset_postdata()
}

That little snippet would be in the template file of your choosing. What do you say we break it down a little to get an idea of what the code is actually doing, yeah?

What are we doing?

The first thing we do is hook to the customize_register hook and create our function callback. Inside of that function a lot of our logic will reside. We get all the available post types by using get_post_types() and create a variable to contain them if there are any.

// We create a variable to house our post types
$post_types = get_post_types( array(
	'public'   => true,
	'_builtin' => false
), 'object' );

Then we check to see if there are any and if there are we will create our setting and create our control.

// check to make sure we have any and if we don't we won't even register anything
if ( ! empty( $post_types ) ) { // register setting and control }

Now that we have our post types we need to create an associative array to pass our control. These are the options our users will see.

// create empty array to house types and names.
$types = array();
// we loop and assign.
foreach ( $post_types as $type ) {
	// name is the registered name and label is what the user sees.
	$types[ $type->name ] = $type->label;
}

We then register our setting.

// We register our setting.
$wp_customize->add_setting( 'section-one-type',
array(
	// we set a default just in case.
	'default' => key( $post_types ),
	// make sure we validate/sanitize our setting.
	'sanitize_callback' => 'jmc_post_type_validate',
) );

You will notice that I’m using a custom function in order to validate the setting. I called it jmc_post_type_validate and it looks like:

/**
 * Validate that we really are using a registered post type otherwise we return a default set
 * by the registered setting.
 *
 * @param  [type] $value   Value that is passed by customizer.
 * @param  [type] $setting The setting object.
 * @return [type] Return a validated value.
 */
function jmc_post_type_validate( $value, $setting ) {
	// Get a list of available post types.
	$post_types = get_post_types( array(
		'public'   => true,
		'_builtin' => false,
	), 'object' );

	// Check if what the user selected is valid.
	if ( array_key_exists( $value, $post_types ) ) {
		// If it is we return it.
		return $value;
	} else {
		// Otherwise return a default setting.
		return $setting->default;
	}
}

Finally, we create our control.

// register our control.
$wp_customize->add_control( 'section-one-type',
	// we pass our array.
	array(
		// The label for the markup.
		'label'       => __( 'The post type for section one', 'jmc' ),
		// A helpful description that display in the customizer.
		'description' => __( 'Choose what post type you would like to show', 'jmc' ),
		// What setting this control is attached to.
		'settings'    => 'section-one-type',
		// The type of control we want to display.
		'type'        => 'select',
		// We pass our $types associative array we made earlier.
		'choices'     => $types,
		// The section we want this to show on.
		'section'     => 'static_front_page',
	)
);

Super cool, right?

That is great and all but now what about displaying that on the front end? Enter get_metadata() and WP_Query. Yes, a new loop. Even better is that we can now use metadata within post types. How amazing is that?

Take the following for example:

if ( ! get_theme_mod( 'section-one-type' ) === false ) {
	// create a new WP_Query.
	$type = new WP_Query(
		array(
			// use the post type passed in the setting.
			'post_type'      => get_theme_mod( 'section-one-type' ),
			// depending on how many columns we want set it accordingly.
			'posts_per_page' => 3,
		)
	);

	// create our custom loop.
	if ( $type->have_posts() ) {
		while ( $type->have_posts() ) {
			$type->the_post();
			the_title( '<h3>', '</h3>' );
		}
	}
	// because we are nice, we reset the post data not the query.
	wp_reset_postdata();
}

This can be expanded of course but you sort of get the idea. I’ll post the snippet that does include a little more inline documentation in hopes it does help somebody out.

add_action( 'customize_register', 'jmc_customize' );
/**
 * Register our customizer settings for the theme.
 *
 * @method jmc_customize
 * @param  [type] $wp_customize The customizer object.
 */
function jmc_customize( $wp_customize ) {
	// get list of post types.
	$post_types = get_post_types( array(
		'public'   => true,
		'_builtin' => false,
	), 'object' );

	// check if there are types that can be used.
	if ( ! empty( $post_types ) ) {
		// create empty array.
		$types = array();

		// loop over post types.
		foreach ( $post_types as $type ) {
			// name is the registered type and label is what user sees.
			$types[ $type->name ] = $type->label;
		}

		// We register our setting.
		$wp_customize->add_setting( 'section-one-type',
			array(
				// we set a default just in case.
				'default'           => key( $post_types ),
				// make sure we validate/sanitize our setting.
				'sanitize_callback' => 'jmc_post_type_validate',
			)
		);

		// register our control.
		$wp_customize->add_control( 'section-one-type',
			// we pass our array.
			array(
				// The label for the markup.
				'label'       => __( 'The post type for section one', 'jmc' ),
				// A helpful description that display in the customizer.
				'description' => __( 'Choose what post type you would like to show', 'jmc' ),
				// What setting this control is attached to.
				'settings'    => 'section-one-type',
				// The type of control we want to display.
				'type'        => 'select',
				// We pass our $types associative array we made earlier.
				'choices'     => $types,
				// The section we want this to show on.
				'section'     => 'static_front_page',
			)
		);
	}
}

/**
 * Validate that we really are using a registered post type otherwise we return a default set
 * by the registered setting.
 *
 * @param  [type] $value   Value that is passed by customizer.
 * @param  [type] $setting The setting object.
 * @return [type] Return a validated value.
 */
function jmc_post_type_validate( $value, $setting ) {
	// Get a list of available post types.
	$post_types = get_post_types( array( 'public' => true, '_builtin' => false ), 'object' );
	// Check if what the user selected is valid.
	if ( array_key_exists( $value, $post_types ) ) {
		// If it is we return it.
		return $value;
	} else {
		// Otherwise return a default setting.
		return $setting->default;
	}
}

Oh, if you do want to use get_post_meta() you can use it a little something like:

get_post_meta( get_the_ID(), 'subtitle', true );

Grunt your way to automation

WordPress theme development can feel repetitive. At times there are things you are always doing over and over again. This is true when you are building a WordPress theme for distribution. Thankfully there are tools that can make your workflow a bit easier.

Tools

In order to make your theme workflow a little easier we will need a few things.

Yes, a few things to set up but when you are building a roller coaster you don’t use just one tool, right? Same applies to building a theme – or even a plugin.

Grunt can make your life easier by taking redundant tasks and automating them. A good example of this is minifying all your files. The big benefit of this of course is a smaller file size but what happens when you have to redo this when you change the main file? You have to re-minify. What if you have more than one file? This can be frustrating because you may have to do this so many times.

This is where Grunt comes in super handy. It helps run repetitive tasks like minifying, copying, and even compressing things for us.

Copy paste is hurting your theme

I’ve seen quite a few themes that have been doing this thing of passing an argument to the function when they could be using a filter. I get it we all have our methods. But when there is a better practice would you rather use the better practice or a wrong one?

I choose the better practice. Any day. The last several themes I’ve encountered have been using a snippet that has driven me up a wall. A very unhappy wall. The following code appears to be used a quite a few themes and it needs to stop. Like quickly.

<?php
$commenter = wp_get_current_commenter();
$req = get_option( 'require_name_email' );
$aria_req = ( $req ? " aria-required='true'" : '' );

$comments_args = array(
	// change the title of send button
	// 'label_submit'=>'Send',
	// change the title of the reply section
	// 'title_reply'=>'Write a Reply or Comment',
	// remove "Text or HTML to be displayed after the set of comment fields"
	'comment_notes_after' => ' ',
	// redefine your own textarea (the comment body)
	'comment_field' => '<p class="comment-form-comment"><textarea id="comment" name="comment" aria-required="true" placeholder="'. __('Your Message...', 'text-domain') .'" rows="8" cols="37" wrap="hard"></textarea></p>',
	'fields' => apply_filters( 'comment_form_default_fields', array(
		'author' => '<div class="row"><div class="col-md-4"><p class="comment-form-author">' . '<input id="author" placeholder="'. __('Your name *....', 'text-domain') .'" name="author" type="text" value="' . esc_attr( $commenter['comment_author'] ) . '" size="30"' . $aria_req . ' />' . ( $req ? '<span style="color:red" class="required"></span>' : '' ) . '</p></div>',
		'email' => '<div class="col-md-4"><p class="comment-form-email">' . '<input id="email" placeholder="'. __('Your email *...','text-domain') .'" name="email" type="text" value="' . esc_attr(  $commenter['comment_author_email'] ) . '" size="30"' . $aria_req . ' />' . ( $req ? '<span style="color:red" class="required"></span>' : '' ) . '</p></div>',
		'url' => '<div class="col-md-4"><p class="comment-form-url">' . '<input id="url" placeholder="'.  __('Your website...', 'text-domain') .'" name="url" type="text" value="' . esc_attr( $commenter['comment_author_url'] ) . '" size="30" /></p></div></div>'
		) ),
);

comment_form($comments_args); ?>

The biggest reason is that you can use a filter for all of that. Not only is it cleaner it is much, much child-theme friendlier as well. Actually there are two filters that you can use as well! The first one is the comment_form_default_fields. The second is the comment_form_defaults. Each one returns an associative array.

Let’s look at the first one:

Default Fields

The default fields filter is super simple and you can add, remove and modify the input fields for the comment form. I can’t think of a major reason to want to add to that in a theme but that is a possibility. Let’s see a quick example of just removing the wrapping p tags:

add_filter( 'comment_form_default_fields', 'jmc_commentd_fields' );
function jmc_commentd_fields( $fields ) {

	// get the current commenter if available
	$commenter = wp_get_current_commenter();

	// core functionality
	$req      = get_option( 'require_name_email' );
	$aria_req = ( $req ? " aria-required='true'" : '' );
	$html_req = ( $req ? " required='required'" : '' );

	// Change just the author field
	$fields['author'] = '<label for="author">' . __( 'Name:', 'text-domain' ) . ( $req ? ' <span class="required">*</span>' : '' ) . '</label><input id="author" name="author" type="text" value="' . esc_attr( $commenter['comment_author'] ) . '" size="30" maxlength="245"' . $aria_req . $html_req . ' />';
	return $fields;

}

For those fields, there are three that are available:

  • name
  • email
  • url

Do make sure that that you are somehow showing that the site owner does or does not require the name and email to be filled out.

Form Defaults

The comment_form_defaults is very much like the comment_form_default_fields in that it returns an associative array as well. The possible keys are:

  • fields
  • comment_field
  • must_log_in
  • logged_in_as
  • comment_notes_before
  • comment_notes_after
  • action
  • id_form
  • id_submit
  • class_form
  • class_submit
  • name_submit
  • title_reply
  • title_reply_to
  • title_reply_before
  • title_reply_after
  • cancel_reply_before
  • cancel_reply_after
  • cancel_reply_link
  • label_submit
  • submit_button
  • submit_field
  • format

Very much like the previous filter we can use something like:

add_filter( 'comment_form_defaults', 'jmc_change_comment_form' );
function jmc_change_comment_form( $defaults ) {

	// Change the "cancel" to "I would rather not comment" and use a span instead
	$defaults['cancel_reply_before'] = '<span class="cancel-reply">';
	$defaults['cancel_reply_link'] = __( 'I would rather not comment', 'text-domain' );
	$defaults['cancle_reply_acter'] = '</span>';

	return $defaults;
}

It is very important that you return that array otherwise your fields will not show.