DEV Community

Chris Gustin
Chris Gustin

Posted on • Originally published at Medium on

WordPress Tip: Internal categories for pages


Photo by Justin Morgan on Unsplash

I recently had a feature request for a WordPress site I’ve been working on, and as I went Googling to see what info was already out there, I was surprised to come up a little empty. So I decided to put together a quick article for anyone else who might end up in the same boat.

The request: The site is big and has hundreds of pages and posts. In the admin area, when viewing “Pages”, there was a need to be able to internally categorize pages as a certain type, e.g. “Landing Page”, and then filter pages by that type. And since these categories would be for administrative use only, it was crucial that they not show up on the front-end or be accessible by regular users.

The (almost) solution: My first pass at this was to enable the built-in WordPress categories and tags for pages using the register_taxonomy_for_object_type() function. The code looked like this (added to functions.php):

function register_category_and_tag_for_pages() {
  register_taxonomy_for_object_type('category', 'page');
  register_taxonomy_for_object_type('post_tag', 'page');
}

add_action('init', 'register_category_and_tag_for_pages');
Enter fullscreen mode Exit fullscreen mode

At first glance, it worked. Under “Pages” in the admin area, I now had “Categories” and “Tags” as options. However, when I clicked into Categories, all of the categories that had been added for blog posts were already in there, and same for Tags. I needed a solution that would keep the page categories and post categories separate (I ended up not needing tags, but tried on the first pass to see if they would work), since the page categories needed to be private and the post categories needed to be public.

The working solution: In WordPress, categories and tags fall under the larger umbrella of “taxonomies”, which is just a fancy word for ways to group or sort items based on similar properties. And WordPress allows users to create custom taxonomies, which are just variations of the built in category and tag taxonomies. For my use case, I registered a “Page Category” taxonomy:

function create_page_category_taxonomy() {
  register_taxonomy(
    'page_category',
    'page',
    array(
     'label' => __('Page Category'),
     'hierarchical' => true,
     'public' => false,
     'show_ui' => true,
     'show_admin_column' => true
    )
 );
}

add_action('init', 'create_page_category_taxonomy');
Enter fullscreen mode Exit fullscreen mode

register_taxonomy takes three arguments: the slug for your taxonomy, what to apply it to (posts, pages, custom post), and an array of customization options. For mine, I set hierarchical to true so the taxonomy would behave like a category (categories can have sub-categories and create a hierarchy, tags cannot). Setting it to false would cause it to behave like a tag.

I set public to false to ensure the taxonomy can’t be queried from the front-end, since these would be for internal use only. I set show_ui to true so they would be easy to edit and work with in the Dashboard, and I set show_admin_column to true so they would be visible when viewing the list of pages on the site.

The last step was to make it so a user could filter by a specific category from the “Pages” view in the Dashboard. Thanks to this article https://thestizmedia.com/custom-post-type-filter-admin-custom-taxonomy/, it was a snap to set up. This snippet adds a dropdown box above the list of pages that allows for filtering by page category (make sure to change the code on the two lines indicated in the comments):

add_action('restrict_manage_posts', 'tsm_filter_post_type_by_taxonomy');

function tsm_filter_post_type_by_taxonomy() {
  global $typenow;
  $post_type = 'page'; // change to your post type
  $taxonomy = 'page_category'; // change to your taxonomy
  if ($typenow == $post_type) {
    $selected = isset($_GET[$taxonomy]) ? $_GET[$taxonomy] : '';
    $info_taxonomy = get_taxonomy($taxonomy);
    wp_dropdown_categories(array(
      'show_option_all' => sprintf(__('Show all %s', 'textdomain'), $info_taxonomy->label),
      'taxonomy' => $taxonomy,
      'name' => $taxonomy,
      'orderby' => 'name',
      'selected' => $selected,
      'show_count' => true,
      'hide_empty' => true,
    ));
  };
}
Enter fullscreen mode Exit fullscreen mode

And this snippet processes the actual query (again make sure to update the two lines indicated):

add_filter('parse_query', 'tsm_convert_id_to_term_in_query');

function tsm_convert_id_to_term_in_query($query) {
  global $pagenow;
  $post_type = 'page'; // change to your post type
  $taxonomy = 'page_category'; // change to your taxonomy
  $q_vars = &$query->query_vars;

  if ($pagenow == 'edit.php' && isset($q_vars['post_type']) && $q_vars['post_type'] == $post_type && isset($q_vars[$taxonomy]) && is_numeric($q_vars[$taxonomy]) && $q_vars[$taxonomy] != 0) {
    $term = get_term_by('id', $q_vars[$taxonomy], $taxonomy);
    $q_vars[$taxonomy] = $term->slug;
  }
}
Enter fullscreen mode Exit fullscreen mode

And with those three snippets in place, the feature was up and running. I hope that helps anyone else who might have need for a similar feature!

Top comments (0)