wordpress: how to add hierarchy to posts wordpress: how to add hierarchy to posts wordpress wordpress

wordpress: how to add hierarchy to posts


Here is my workaround. This achieves exactly what you want, to be able to set post parents for the builtin post type post. You can achieve this by adding an action to the registred_post_type action hook. Just add this to your theme's functions.php.

add_action('registered_post_type', 'igy2411_make_posts_hierarchical', 10, 2 );// Runs after each post type is registeredfunction igy2411_make_posts_hierarchical($post_type, $pto){    // Return, if not post type posts    if ($post_type != 'post') return;    // access $wp_post_types global variable    global $wp_post_types;    // Set post type "post" to be hierarchical    $wp_post_types['post']->hierarchical = 1;    // Add page attributes to post backend    // This adds the box to set up parent and menu order on edit posts.    add_post_type_support( 'post', 'page-attributes' );}

There can be dozens of reasons why making posts hierarchical can be helpful. My use case is that the client wanted to structure their (already existing) posts into issues, where child posts are articles of one issue (parent posts).

This is easily achieved by limiting the query to only show posts that have no parents, using.

 'post_parent' => 0,

in your query $args.


WP 4.9.*

Workaround above makes it crazy with Friendly URLs.

My solution to add hierarchy to any existent post type:

add_filter( 'register_post_type_args', 'add_hierarchy_support', 10, 2 );function add_hierarchy_support( $args, $post_type ){    if ($post_type === 'post') { // <-- enter desired post type here        $args['hierarchical'] = true;        $args['supports'] = array_merge($args['supports'], array ('page-attributes') );    }    return $args;}

Resave wp settings at /wp-admin/options-permalink.php


I came here looking to achieve:

  1. Adding page attributes to post_type posts to add parent posts
  2. Being able to add a page template to post_type posts
  3. Being able to get hierarchical permalink structure on post_type posts

I was able to use the accepted answer to accomplish 1 & 2, but not 3.

Note: to fully get 2 to work, you need to specify the post_type in the template comments of your page template like this:

<?php/*Template Name: Your Post Template NameTemplate Post Type: post*/

For 3, I found a plugin that ruined my post_type pages, and it was a lot of pretty awful, unmaintained code.

So I wrote a solution to accomplish all this, borrowing from this answer:

(Tested with 4.9.8)

<?phpadd_action('registered_post_type', 'make_posts_hierarchical', 10, 2 );// Runs after each post type is registeredfunction make_posts_hierarchical($post_type, $pto){    // Return, if not post type posts    if ($post_type != 'post') return;    // access $wp_post_types global variable    global $wp_post_types;    // Set post type "post" to be hierarchical    $wp_post_types['post']->hierarchical = 1;    // Add page attributes to post backend    // This adds the box to set up parent and menu order on edit posts.    add_post_type_support( 'post', 'page-attributes' );}/** * Get parent post slug *  * Helpful function to get the post name of a posts parent */function get_parent_post_slug($post) {  if (!is_object($post) || !$post->post_parent) {    return false;  }  return get_post($post->post_parent)->post_name;}/** *  * Edit View of Permalink *  * This affects editing permalinks, and $permalink is an array [template, replacement] * where replacement is the post_name and template has %postname% in it. *  **/add_filter('get_sample_permalink', function($permalink, $post_id, $title, $name, $post) {  if ($post->post_type != 'post' || !$post->post_parent) {    return $permalink;  }  // Deconstruct the permalink parts  $template_permalink = current($permalink);  $replacement_permalink = next($permalink);  // Find string  $postname_string = '/%postname%/';  // Get parent post  $parent_slug = get_parent_post_slug($post);  $altered_template_with_parent_slug = '/' . $parent_slug . $postname_string;  $new_template = str_replace($postname_string, $altered_template_with_parent_slug, $template_permalink);  $new_permalink = [$new_template, $replacement_permalink];  return $new_permalink;}, 99, 5);/** * Alter the link to the post *  * This affects get_permalink, the_permalink etc.  * This will be the target of the edit permalink link too. *  * Note: only fires on "post" post types. */add_filter('post_link', function($post_link, $post, $leavename){  if ($post->post_type != 'post' || !$post->post_parent) {    return $post_link;  }  $parent_slug = get_parent_post_slug($post);  $new_post_link = str_replace($post->post_name, $parent_slug . '/' . $post->post_name, $post_link);  return $new_post_link;}, 99, 3);/** * Before getting posts *  * Has to do with routing... adjusts the main query settings *  */add_action('pre_get_posts', function($query){  global $wpdb, $wp_query;  $original_query = $query;  $uri = $_SERVER['REQUEST_URI'];  // Do not do this post check all the time  if ( $query->is_main_query() && !is_admin()) {    // get the post_name    $basename = basename($uri);    // find out if we have a post that matches this post_name    $test_query = sprintf("select * from $wpdb->posts where post_type = '%s' and post_name = '%s';", 'post', $basename);    $result = $wpdb->get_results($test_query);    // if no match, return default query, or if there's no parent post, this is not necessary    if (!($post = current($result)) || !$post->post_parent) {      return $original_query;    }    // get the parent slug    $parent_slug = get_parent_post_slug($post);    // concat the parent slug with the post_name to get most of the url    $hierarchal_slug = $parent_slug . '/' . $post->post_name;    // if the concat of parent-slug/post-name is not in the uri, this is not the right post.    if (!stristr($uri, $hierarchal_slug)) {      return $original_query;    }    // pretty high confidence that we need to override the query.    $query->query_vars['post_type'] = ['post'];    $query->is_home     = false;     $query->is_page     = true;      $query->is_single   = true;     $query->queried_object_id = $post->ID;      $query->set('page_id', $post->ID);    return $query;  }}, 1);

You can save this to a file custom-posts-hierarchy.php and include it in your functions.php file in your theme, or you can add to the top:

/*Plugin Name: Custom Posts HierarchyPlugin URI:Description: Add page attributes to posts and support hiearchichalAuthor: Angela MurrellVersion:Author URI: */

And drop it into your plugins folder. Good luck!