In the last tutorial I’ve explained how to create a custom post type. In that tutorial I also explained how to create a custom fields in your custom taxonomy. Today, we’ll use that knowledge and re purpose it – this time, we’ll be adding a pages drop down in the regular post categories. This will enable us to assign a page to each category, from which we’ll show the content on our category page. Let’s get started.
Notice: This article was written in 2016. WordPress has changed a lot since then, so take this article with a grain of salt…
As always I’m using Twenty Sixteen theme as my playground. So in my functions.php file I’ll use category_edit_form_fields and category_add_form_fields hooks to add my additional form field to the categories page.
/**
* Adding custom taxonomy field
*
* @var object $taxonomy Taxonomy
* @since 1.0.0
*/
add_action ( 'category_add_form_fields', 'mytheme_extra_add_category_fields', 10, 2);
if ( ! function_exists( 'mytheme_extra_add_category_fields' ) ){
function mytheme_extra_add_category_fields( $taxonomy ) {
?>
<div class="form-field">
<label for="selected_page"><?php esc_attr_e('Page select', 'mytheme'); ?></label>
<?php wp_dropdown_pages(array('name'=>'selected_page', 'id'=>'selected_page', 'show_option_none' => '--')); ?>
<p><?php esc_attr_e('Select the page you want to show the content of in your category.', 'mytheme'); ?></p>
</div>
<?php
}
}
/**
* Adding custom taxonomy field in edit screen
*
* @var object $term Term object for taxonomy
* @since 1.0.0
*/
add_action ( 'category_edit_form_fields', 'mytheme_extra_category_fields');
if ( ! function_exists( 'mytheme_extra_category_fields' ) ){
function mytheme_extra_category_fields( $term ) {
$selected_page = get_term_meta( $term->term_id, 'selected_page', true );
?>
<tr class="form-field">
<th scope="row" valign="top"><label for="selected_page"><?php esc_attr_e('Page select', 'mytheme'); ?></label></th>
<td>
<?php wp_dropdown_pages(array('name'=>'selected_page', 'id'=>'selected_page', 'selected'=> $selected_page, 'show_option_none' => '--')); ?>
<p class="description"><?php esc_attr_e('Select the page you want to show the content of in your category.', 'mytheme'); ?></p>
</td>
</tr>
<?php
}
}
Code language: HTML, XML (xml)
Notice that we’ve used the wp_dropdown_pages() function. It does exactly what we need – give us a select field with all available pages. Notice that in the edit screen we want to get our term that we’ve saved, and make it selected in the wp_dropdown_pages() function. Of course this code will only show our fields, we need to save them. For that we’ll be using created_category and edited_category hooks
/**
* Saving extra custom taxonomy fields upon creation
*
* @var array $term_id Taxonomy term id
* @since 1.0.0
*/
add_action ( 'created_category', 'mytheme_save_extra_category_fileds');
if ( ! function_exists( 'mytheme_save_extra_category_fileds' ) ){
function mytheme_save_extra_category_fileds( $term_id ) {
if ( isset( $_POST['selected_page'] ) ) {
$selected_page = intval($_POST['selected_page']);
add_term_meta( $term_id, 'selected_page', $selected_page, true );
}
}
}
/**
* Saving extra custom taxonomy fields upon edit
*
* @var array $term_id Taxonomy term id
* @since 1.0.0
*/
add_action ( 'edited_category', 'mytheme_update_extra_category_fileds');
if ( ! function_exists( 'mytheme_update_extra_category_fileds' ) ){
function mytheme_update_extra_category_fileds( $term_id ) {
if ( isset( $_POST['selected_page'] ) ) {
$selected_page = intval($_POST['selected_page']);
update_term_meta( $term_id, 'selected_page', $selected_page, false );
}
}
}
Code language: PHP (php)
Again, we’re exploiting the add_term_meta() function. That way if we remove the category, all the meta values associated with it will get deleted as well. So what you have at this point is something like this
Sorting it out
I like to add extra columns for any extra field I’ve added. Not only do you see what page is associated with which category, but you get to code a bit, and I find that useful in developing your coding skills :) So first we add a new column to our category screen, and populate it with the page title like this
/**
* Adding custom column to taxonomy
*
* @var array $cat_columns Columns array in custom taxonomy
* @return array Returns updated category columns
* @since 1.0.0
*/
add_filter('manage_edit-category_columns', 'mytheme_selected_page_column', 10, 2);
if (!function_exists('mytheme_selected_page_column')) {
function mytheme_selected_page_column( $cat_columns ){
$cat_columns['selected_page'] = esc_attr__('Selected Page', 'mytheme');
return $cat_columns;
}
}
/**
* Managing custom column in taxonomy display
*
* @var array $deprecated
* @var array $column_name Column name
* @var array $term_id Taxonomy term id
* @since 1.0.0
*/
add_filter ('manage_category_custom_column', 'mytheme_manage_category_custom_fields', 10,3);
if (!function_exists('mytheme_manage_category_custom_fields')) {
function mytheme_manage_category_custom_fields($deprecated, $column_name, $term_id){
if ($column_name == 'selected_page') {
$selected_page = get_term_meta( $term_id, 'selected_page', true );
if (isset($selected_page) && $selected_page != '') {
echo get_the_title($selected_page);
}
}
}
}
Code language: PHP (php)
Next we want to be able to sort the new column alphabetically (by the page name). First we make the column sortable, and then we use the terms_clauses hook to make a custom query
/**
* Make column sortable
*
* @param array $sortable Sortable columns array
* @return array Updated sortable columns array
* @since 1.0.0
*/
add_filter('manage_edit-category_sortable_columns', 'mytheme_manage_category_sortable_columns');
if(!function_exists('mytheme_manage_category_sortable_columns')){
function mytheme_manage_category_sortable_columns($sortable){
$sortable['selected_page'] = 'selected_page';
return $sortable;
}
}
/**
* Column sortable query
*
* @param array $pieces Terms query SQL clauses.
* @param array $taxonomies An array of taxonomies.
* @param array $args An array of terms query arguments.
* @return array Modified query array
* @since 1.0.0
*/
add_filter( 'terms_clauses', 'mytheme_filter_category_terms', 10, 3 );
if (!function_exists('mytheme_filter_category_terms')) {
function mytheme_filter_category_terms( $pieces, $taxonomies, $args ) {
global $wpdb;
$orderby = isset($_REQUEST['orderby']) ? trim(wp_unslash($_REQUEST['orderby'])) : 'selected_page';
if($orderby == 'selected_page' ) {
$pieces['fields'] .= ", trm.*";
$pieces['join'] .= " INNER JOIN {$wpdb->termmeta} AS trm ON tt.term_id = trm.term_id";
$pieces['orderby'] = "ORDER BY trm.meta_value";
}
return $pieces ;
}
}
Code language: PHP (php)
If you’re still having some issues with MySQL, and to see if your syntax is correct, you can see the whole query by adding anything in the query strings – this will trigger an error (assuming that you have wp_debug enabled, and you should if you’re developing stuff) with the whole query string, so that you can see the full syntax. For instance I added 1 in my fields string after the * which revealed the full query as
SELECT t.*, tt.*, trm.* FROM wp_terms AS t INNER JOIN wp_term_taxonomy AS tt ON t.term_id = tt.term_id INNER JOIN wp_termmeta AS trm ON tt.term_id = trm.term_id WHERE tt.taxonomy IN ('category') ORDER BY trm.meta_value ASC
Code language: PHP (php)
With that you’ll have something like this
So… how do you show your content in the category page?
Yeah, almost forgot the most important part – using the new field that we’ve added in our categories. If you take a look at template hierarchy page, and especially the hierarchy diagram, you’ll notice that there is a certain procedure that WordPress will follow when trying to fetch all the posts from the category and displaying it.
First, WordPress will check for the category-{slug}.php template file. So if the category is narwhal, the file it searches for is category-narwhal.php.
Second, if category-narwhal.php is missing, and the id of the category is 9, WordPress will try to find category-9.php template file.
Third, if category-9.php is missing, WordPress turns to the generic category template, category.php.
If category.php is missing, then the WordPress looks for generic archive template archive.php. And lastly if that file is missing, WordPress will use index.php as a default fallback. And you must have index.php in your theme, otherwise the theme won’t work. So we’ve cleared that up.
Since Twenty Sixteen doesn’t have category page template files, the first file it uses when you go to a category page is archive.php. One way to check what template file you’re on is to inspect the page, and look at the classes in the body tag. Most of the themes use body_class() function that will show you the template file you’re on. I’ve added the code below, before the main tag in the archive.php template
<?php
$cat_id = get_query_var('cat');
$cat_page = get_term_meta( $cat_id, 'selected_page', true );
if(isset($cat_page) && $cat_page != ''){
$page = get_post($cat_page);
echo apply_filters('the_content', $page->post_content);
}
?>
Code language: HTML, XML (xml)
First we get the category id from the query variable, then we get our page, which was assigned to the category, from the term meta, and if we have anything we’ll get the page object. Using the get_post() function (get_page() is deprecated) we have all the information about that page at our disposal. And lastly we need only the content from that page, so we apply the filter the_content on the post content. You can choose to fetch featured image that is added to this page, or just some meta data you’ve added in that page. Really, you can use any information you have on that page in any way you want.
And that’s it. Simple as that. Hope this helps you and as always, if you have any kind of questions and suggestions comment bellow. Happy coding!
Leave a Reply