In the previous two articles I have attempted to explain filters. Since each article builds on the previous article I recommend catching up on the entire Genesis Explained series, and at the very least the filters sub series.
The last article dealt with using filters to change “strings,” that is simple text and html phrases. I demonstrated simple replacement as well as a more advanced technique for changing a string within the string.
This article will use similar examples and techniques, but focused on objects, or arrays. Think of an array as an ordered group of strings. There are two parts to an array, the key and the value. They can be assigned in a few different ways, and will show up in the code differently based on how the value is being assigned. Here is a simple example
$array_1 = array( 'key1' => 'value1', 'key2' => 'value2'); $array_2 = array( 'value1', 'value2' ); $array_2[] = 'value3'; $array_2['3'] = 'value4';
In the first example, the keys are listed as “key1”, which has the string value of “value1” and “key2” with a string value of “value2.”
The second example doesn’t list the keys, so they are automatically assigned as a 0 and 1. The next example would have a key value of 2, it is put onto the end of the existing $array_2 string and the last example manually assigns the key of “3” the value of “value4.”
One more thing to note, the array can contain only string, or it can contain additional objects, that is nested arrays like
$array_1 = array( 'odd' => array( 1, 3, 5 ), 'even' => array( 2, 4, 6 ) );
In this case $array_1 is made of two object arrays, one with odd numbers and the other with even numbers.
The reason arrays are build is because they are efficient ways of storing related information without needing to have dozens, hundreds, or even thousands of separate variables. The information can then be unpacked using many different methods, none of which really matter right now.
Adding to an Array
This might be the most simple way of working with an array, but it is also tricky because you need to know what values will be useful. A great example would be working with the comment form. Genesis uses this code to create the comment form
add_action( 'genesis_comment_form', 'genesis_do_comment_form' ); /** * Defines the comment form, hooked to <code>genesis_comments_form()</code> * * @since 1.0 * * @global unknown $user_identity * @global unknown $id * @return null Returns null if Genesis disables comments for this page or post */ function genesis_do_comment_form() { global $user_identity, $id; // Check if ( ( is_page() && ! genesis_get_option( 'comments_pages' ) ) || ( is_single() && ! genesis_get_option( 'comments_posts' ) ) ) return; $commenter = wp_get_current_commenter(); $req = get_option( 'require_name_email' ); $aria_req = ( $req ? ' aria-required="true"' : '' ); $args = array( 'fields' => array( 'author' => '<p class="comment-form-author">' . '<input id="author" name="author" type="text" value="' . esc_attr( $commenter['comment_author'] ) . '" size="30" tabindex="1"' . $aria_req . ' />' . '<label for="author">' . __( 'Name', 'genesis' ) . '</label> ' . ( $req ? '<span class="required">*</span>' : '' ) . '</p><!-- #form-section-author .form-section -->', 'email' => '<p class="comment-form-email">' . '<input id="email" name="email" type="text" value="' . esc_attr( $commenter['comment_author_email'] ) . '" size="30" tabindex="2"' . $aria_req . ' />' . '<label for="email">' . __( 'Email', 'genesis' ) . '</label> ' . ( $req ? '<span class="required">*</span>' : '' ) . '</p><!-- #form-section-email .form-section -->', 'url' => '<p class="comment-form-url">' . '<input id="url" name="url" type="text" value="' . esc_attr( $commenter['comment_author_url'] ) . '" size="30" tabindex="3" />' . '<label for="url">' . __( 'Website', 'genesis' ) . '</label>' . '</p><!-- #form-section-url .form-section -->' ), 'comment_field' => '<p class="comment-form-comment">' . '<textarea id="comment" name="comment" cols="45" rows="8" tabindex="4" aria-required="true"></textarea>' . '</p><!-- #form-section-comment .form-section -->', 'title_reply' => __( 'Speak Your Mind', 'genesis' ), 'comment_notes_before' => '', 'comment_notes_after' => '', ); comment_form( apply_filters( 'genesis_comment_form_args', $args, $user_identity, $id, $commenter, $req, $aria_req ), $id ); }
That’s quite a few arguments being passed to the comment_form() function, but give the codex article a read and you will see there are even more options you can add. For the sake of this tutorial we will be changing the submit button text, which means we need to add to the list of arguments. Now we can unhook the action and add a new action with our own function that has this full list, plus the label_submit value (see the codex article). That is a lot of unneeded code. Look how simple this is with a filter.
add_filter( 'genesis_comment_form_args', 'child_comment_form_args' ); function child_comment_form_args( $args ) { $args['label_submit'] = 'Publish Comment'; return $args; }
That’s all it takes. Now let’s look at it to see what happens. The first line adds the filter. It could include up to 6 arguments in the function, but we only need the 1, so the default is fine. The second line defines our function, and the next line adds the label_submit key to the $args array with a value of “Publish Comment.” We know this value matters because we looked at the WordPress codex article and saw it is a valid argument for the function. All that is left is to return the object to be used in the comment_form() function.
Replacing Array Values
Replacing a value is much easier, since you can look in the file and replace the currently assigned value. No need to figure out what hidden values might work. One place you might do this is with the breadcrumbs arguments. Let’s look at the file. This one is a bit trickier to find. It isn’t in the genesis/lib/structure/ files, nor the genesis/lib/functions/ files. The last likely place, since it isn’t an admin function, is in genesis/lib/classes/. Fortunately there is a breadcrumb.php file there. Now this is a class, and reading them is a tiny bit different, so let me help by posting the code we will be working with and trying to explain how to know what is happening
/** * Constructor. Set up cacheable values and settings. * * @since 1.5 * * @param array $args */ function genesis_breadcrumb() { $this->on_front = get_option( 'show_on_front' ); /** Default arguments **/ $this->args = array( 'home' => __( 'Home', 'genesis' ), 'sep' => ' / ', 'list_sep' => ', ', 'prefix' => '<div class="breadcrumb">', 'suffix' => '</div>', 'heirarchial_attachments' => true, 'heirarchial_categories' => true, 'display' => true, 'labels' => array( 'prefix' => __( 'You are here: ', 'genesis' ), 'author' => __( 'Archives for ', 'genesis' ), 'category' => __( 'Archives for ', 'genesis' ), 'tag' => __( 'Archives for ', 'genesis' ), 'date' => __( 'Archives for ', 'genesis' ), 'search' => __( 'Search for ', 'genesis' ), 'tax' => __( 'Archives for ', 'genesis' ), 'post_type' => __( 'Archives for ', 'genesis' ), '404' => __( 'Not found: ', 'genesis' ) ) ); } /** * Return the final completed breadcrumb in markup wrapper. Public. * * @since 1.5 * * @return string HTML markup */ function get_output( $args = array() ) { /** Merge and Filter user and default arguments **/ $this->args = apply_filters( 'genesis_breadcrumb_args', wp_parse_args( $args, $this->args ) ); return $this->args['prefix'] . $this->args['labels']['prefix'] . $this->build_crumbs() . $this->args['suffix']; }
That’s a lot of code, and there is a lot more in the file, but this is what is relevant. The most important line would be line 46, I highlighted it so you don’t miss it. I highlighted a couple other lines because those are the ones we will be changing. Line 46 is special because it includes “apply_filters()” which means we can change the value of something. The something is the get_output( $args ) and $this->args. If you look up to line 12 you will see $this->args, which is what we want to change. Perfect. Ok, so now lets change those values.
add_filter( 'genesis_breadcrumb_args', 'child_breadcrumb_args' ); function child_breadcrumb_args( $args ) { $args['sep'] = ' | '; $args['labels']['prefix'] = 'Path to here: '; $args['labels']['category'] = 'Category: '; return $args; }
See, all we have to do is provide the same key then we can change the value. In the case of nested values like the “labels” object you need to provide the key of the object (labels) then the string (prefix and category). Finally, always remember to return your array when you are done with it.
Changing an Array
If you read the last article you should have an idea of what to expect here. Basically we are going to use a string replace to change part of a value. For this example we will be removing some invalid markup. The specific markup can be left, and generally I’d recommend leaving it alone, but sometimes you have very strict validation requirements, so you have to remove certain html that is used for accessibility to achieve those requirements. In this case I am referring to the aria-require attribute in the comment form. we have to go back to the genesis/lib/structure/comments.php file for this one. In fact I’ve already posted the code for this in the first example. We could replace any value with the aria-required attribute, but that is quite a bit of code, changing part of the value is much more efficient.
add_filter( 'genesis_comment_form_args', 'child_comment_form_remove_aria_required' ); function child_comment_form_remove_aria_required( $args ){ $args = str_replace( ' aria-required="true"', '', $args ); $args[fields] = str_replace( ' aria-required="true"', '', $args[fields] ); return $args; }
OK, so far the first two lines should look very familiar. The important thing to note is that I used a different callback function than the first example. If I had two functions with the same name the site would break. Always give your functions unique names.
The second two lines are changing the values, any string in the $args array that had ‘ aria-required=”true”‘ won’t after line 3 and any of the strings in the fields object will have lost the attribute after line 4. Once again, always remember to return your value when done.
This concludes the filters sub series. I imagine the haze is starting to lift, but filters still feel like some kind of dark voodoo you want to learn, but are a bit afraid of. I can totally relate to that feeling. Because the subject can be hazy at best when you first start down this path I don’t want to overwhelm you right now, but I will be coming back to filters in a future series. When I start the child theme creation series we will be dealing with several filters, but in a solid and practical way. After completing that the theoretical foundation this series helped put in place will make much more sense, and filters should become your best friend.
Since you don’t want to miss any of the upcoming articles, why not subscribe to my feed right now. You can also subscribe in your email by using the form in the sidebar.
Alok says
When you wrote:
add_action( ‘genesis_breadcrumb_args’, ‘child_breadcrumb_args’ );
should that be:
add_filter( ‘genesis_breadcrumb_args’, ‘child_breadcrumb_args’ );
The other example for changing an array also needs to be changed to add_filter .. right?
nickthegeek says
yes on both counts, I’ve updated the post. Can’t believe I made that error. Thanks for the heads up.
David M says
Hi, I’m curious how to add a tabindex=5 to the submit comment button. Thanks
Tim says
your series is a real help, Nick – thanks!
thought I’d mention that there are some glitchy single quotes in line 1 of your first arrays code demo: ”key 2
nickthegeek says
Thanks for the head’s up. I’ll get those fixed.