Adding page content to your category page

Adding page content to your category page

Category page field

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.

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
    }
}

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 );
        }
    }
}

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

Custom field in the category screen
Custom field in the category screen

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);
            }
        }
    }
}

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 ;

	}
}

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

With that you’ll have something like this

Custom field column
Custom field column that can be sorted. Ignore the names, this is just the test environment :D
Sorting fields
Categories are sorted by the new field alphabetically

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);
	}
?>

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 comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.