WordPress pages can have a parent page, posts cannot. Sometimes you want that for posts or a custom post type too: a guide split into chapters, documentation with sections, or a parent post that lists its child posts.
This snippet makes WordPress posts hierarchical. The editor gets the Parent and Order fields that pages have, the admin list shows children indented under their parent, and you can query child posts with post_parent.
The snippet
<?php
/**
* Make WordPress posts (and other post types) hierarchical, with a Parent option in the editor.
*/
// ===== Config =====
function dpc_hierarchical_post_types() {
// Post types that get a parent. Custom post types: add their slug, e.g. 'docs'.
$post_types = array( 'post' );
// ===== End of config =====
return (array) apply_filters( 'dpc_hierarchical_post_types', $post_types );
}
add_filter( 'register_post_type_args', 'dpc_hierarchical_post_type_args', 10, 2 );
function dpc_hierarchical_post_type_args( $args, $post_type ) {
if ( ! in_array( $post_type, dpc_hierarchical_post_types(), true ) ) {
return $args;
}
$args['hierarchical'] = true;
// No 'supports' given means WordPress's default: title and editor. false means none.
$supports = $args['supports'] ?? array( 'title', 'editor' );
if ( ! is_array( $supports ) ) {
$supports = array();
}
if ( ! in_array( 'page-attributes', $supports, true ) ) {
$supports[] = 'page-attributes';
}
$args['supports'] = $supports;
return $args;
}
Add it with Scripts Organizer
In Scripts Organizer go to Code Blocks → Add New and give the block a name. Set Trigger location to Everywhere, tick PHP under Script location, paste the code into the PHP editor, edit the config and publish. Leave Action/Hook empty.
Everywhere is needed: the filter must be in place before WordPress registers the post types on every request, in wp-admin, the REST API and the front end.
The same code also works unchanged in a small plugin or an mu-plugin.
How it works
register_post_type_argslets you change the arguments of any post type while it is registered, including core’spostand post types from other plugins.hierarchical => trueallows apost_parent. Thepage-attributesfeature adds the Parent and Order fields to the editor’s sidebar.- A custom post type registered without
supportsgets WordPress’s defaults (title and editor) pluspage-attributes. The older version usedarray_merge()on a missingsupportsvalue, which throws a TypeError on PHP 8 and stops the whole page. - The post type list sits in the config function, and other code can change it with the
dpc_hierarchical_post_typesfilter.
Customise it
- Custom post types: add their slug to
$post_types, for examplearray( 'post', 'docs' ). - List child posts on the parent: use a Query Loop block, or
get_children( array( 'post_parent' => get_the_ID(), 'post_type' => 'post' ) )in PHP.
Gotchas
- Post permalinks stay flat. A child post keeps
/child-post/(or your date-based structure), not/parent/child/as pages do. - Hierarchical post types are listed differently in wp-admin: sorted by title and grouped under their parent, not by date. On a site with thousands of posts the list loads all post IDs to build the tree, which is slow.
- Making
posthierarchical is not an officially supported setup. Most themes and plugins handle it, but check RSS feeds, archives and SEO plugins after enabling it. - Removing the snippet keeps the
post_parentvalues in the database; they are just no longer shown.
In the Scripts Organizer library Import it with one click from Scripts Organizer.