I have a custom post type which comes with a category taxonomy. This taxonomy shows as a meta box at the side. Pretty basic so far.
Now I want to add additional meta boxes below the content on the "normal" location. I want to display one meta box for each public taxonomy in the system. So far I use this code to add the boxes:
public function add_meta_boxes_rfe_taxonomy_related__premium_only($post)
{
$taxonomies = get_taxonomies(['public' => true], 'objects');
foreach ($taxonomies as $taxonomy) {
if ('rfe_taxonomy_related_category' === $taxonomy->name) {
continue;
}
$taxonomy_name = $taxonomy->labels->name;
$taxonomy_slug = $taxonomy->name;
$taxonomy_is_hierarchical = $taxonomy->hierarchical;
$object_type = $taxonomy->object_type;
$post_type_names = [];
foreach ($object_type as $post_type) {
$post_type_name = isset($post_type_names[$post_type]) ? $post_type_names[$post_type] : false;
if (!$post_type_name) {
$post_type_name = get_post_type_object($post_type)->label;
$post_type_names[$post_type] = $post_type_name;
}
if ($taxonomy_is_hierarchical) {
add_meta_box(
'rfe_taxonomy_related_meta_box_' . $taxonomy_slug, //ID
$taxonomy_name . ' (' . $post_type_name . ')', //Title
[$this, 'build_hierarchical_taxonomy_meta_box__premium_only'], //Callback
'rfe_taxonomy_related', //Post type to add to
'normal',
'low'
);
} else {
add_meta_box(
'rfe_taxonomy_related_meta_box_' . $taxonomy_slug, //ID
$taxonomy_name . ' (' . $post_type_name . ')', //Title
[$this, 'build_flat_taxonomy_meta_box__premium_only'], //Callback
'rfe_taxonomy_related', //Post type to add to
'normal',
'low'
);
}
}
}
}
public function build_hierarchical_taxonomy_meta_box__premium_only($post, $metabox)
{
$taxonomy_slug = substr($metabox['id'], strlen('rfe_taxonomy_related_meta_box_'));
$box['args']['taxonomy'] = $taxonomy_slug;
post_categories_meta_box($post, $box);
}
public function build_flat_taxonomy_meta_box__premium_only($post, $metabox)
{
$taxonomy_slug = substr($metabox['id'], strlen('rfe_taxonomy_related_meta_box_'));
$box['args']['taxonomy'] = $taxonomy_slug;
post_tags_meta_box($post, $box);
}
This already gives me the meta boxes but the meta boxes for the flat taxonomies do not seem to work. I cannot add new tags or select from the most popular ones.
The second issue is that when I save the post, all changes are lost. I wonder what I am missing or what I am doing wrong.
I have a custom post type which comes with a category taxonomy. This taxonomy shows as a meta box at the side. Pretty basic so far.
Now I want to add additional meta boxes below the content on the "normal" location. I want to display one meta box for each public taxonomy in the system. So far I use this code to add the boxes:
public function add_meta_boxes_rfe_taxonomy_related__premium_only($post)
{
$taxonomies = get_taxonomies(['public' => true], 'objects');
foreach ($taxonomies as $taxonomy) {
if ('rfe_taxonomy_related_category' === $taxonomy->name) {
continue;
}
$taxonomy_name = $taxonomy->labels->name;
$taxonomy_slug = $taxonomy->name;
$taxonomy_is_hierarchical = $taxonomy->hierarchical;
$object_type = $taxonomy->object_type;
$post_type_names = [];
foreach ($object_type as $post_type) {
$post_type_name = isset($post_type_names[$post_type]) ? $post_type_names[$post_type] : false;
if (!$post_type_name) {
$post_type_name = get_post_type_object($post_type)->label;
$post_type_names[$post_type] = $post_type_name;
}
if ($taxonomy_is_hierarchical) {
add_meta_box(
'rfe_taxonomy_related_meta_box_' . $taxonomy_slug, //ID
$taxonomy_name . ' (' . $post_type_name . ')', //Title
[$this, 'build_hierarchical_taxonomy_meta_box__premium_only'], //Callback
'rfe_taxonomy_related', //Post type to add to
'normal',
'low'
);
} else {
add_meta_box(
'rfe_taxonomy_related_meta_box_' . $taxonomy_slug, //ID
$taxonomy_name . ' (' . $post_type_name . ')', //Title
[$this, 'build_flat_taxonomy_meta_box__premium_only'], //Callback
'rfe_taxonomy_related', //Post type to add to
'normal',
'low'
);
}
}
}
}
public function build_hierarchical_taxonomy_meta_box__premium_only($post, $metabox)
{
$taxonomy_slug = substr($metabox['id'], strlen('rfe_taxonomy_related_meta_box_'));
$box['args']['taxonomy'] = $taxonomy_slug;
post_categories_meta_box($post, $box);
}
public function build_flat_taxonomy_meta_box__premium_only($post, $metabox)
{
$taxonomy_slug = substr($metabox['id'], strlen('rfe_taxonomy_related_meta_box_'));
$box['args']['taxonomy'] = $taxonomy_slug;
post_tags_meta_box($post, $box);
}
This already gives me the meta boxes but the meta boxes for the flat taxonomies do not seem to work. I cannot add new tags or select from the most popular ones.
The second issue is that when I save the post, all changes are lost. I wonder what I am missing or what I am doing wrong.
As suggested by LWS-Mo this can work by using register_taxonomy_for_object_type()
to register my custom post type for all taxonomies in the system and then use remove_meta_box()
and add_meta_box
to re-add them to the new location. I'm not sure if I really use the correct hooks - but hey, it works :)
One thing to mention is that all taxonomies appear under my post type as submenus so I had also to remove the submenu entries.
First add the hooks:
add_action('init', [$this, 'create_taxonomy_related_post_type__premium_only']);
add_action('wp_loaded', [$this, 'add_meta_boxes_rfe_taxonomy_related__premium_only']);
add_action('admin_init', [$this, 'rename_taxonomy_meta_boxes_on_rfe_taxonomy_related__premium_only']);
add_action('admin_menu', [$this, 'remove_taxonomy_menu_from_rfe_taxonomy_related__premium_only']);
Then add the custom post type with its own taxonomy:
public function create_taxonomy_related_post_type__premium_only()
{
register_post_type('rfe_taxonomy_related',
array(
'labels' => array(
'name' => 'Taxonomy Related',
'singular_name' => 'Taxonomy Related',
'add_new' => 'Add New',
'add_new_item' => 'Add New Layout',
'edit' => 'Edit',
'edit_item' => 'Edit Layout',
'new_item' => 'New Layout',
'view' => 'View',
'view_item' => 'View Layout',
'search_items' => 'Search Layouts',
'not_found' => 'No Layouts found',
'not_found_in_trash' => 'No Layouts found in Trash',
),
'public' => true,
'exclude_from_search' => true,
'publicly_queryable' => false,
'supports' => array('title', 'editor'),
'taxonomies' => array('rfe_taxonomy_related_category'),
'menu_icon' => 'dashicons-format-aside',
'has_archive' => false,
)
);
register_taxonomy(
'rfe_taxonomy_related_category',
array('rfe_taxonomy_related'),
array(
'hierarchical' => true,
'labels' => array(
'name' => __('Categories', 'jt-revolution-for-elementor'),
'singular_name' => __('Category', 'jt-revolution-for-elementor'),
'search_items' => __('Search Category', 'jt-revolution-for-elementor'),
'all_items' => __('All Categories', 'jt-revolution-for-elementor'),
'parent_item' => __('Parent Category', 'jt-revolution-for-elementor'),
'parent_item_colon' => __('Parent Category:', 'jt-revolution-for-elementor'),
'edit_item' => __('Edit Category', 'jt-revolution-for-elementor'),
'update_item' => __('Update Category', 'jt-revolution-for-elementor'),
'add_new_item' => __('Add New Category', 'jt-revolution-for-elementor'),
'new_item_name' => __('New Category Name', 'jt-revolution-for-elementor'),
'menu_name' => __('Categories', 'jt-revolution-for-elementor'),
),
'show_ui' => true,
'show_admin_column' => true,
'query_var' => true,
)
);
}
Next use register_taxonomy_for_object_type
to add each taxonomy in the system to my post type:
public function add_meta_boxes_rfe_taxonomy_related__premium_only($post)
{
$args = array('public' => true);
$output = 'objects';
$taxonomies = get_taxonomies($args, $output);
foreach ($taxonomies as $taxonomy) {
if ('rfe_taxonomy_related_category' === $taxonomy->name) {
continue;
}
register_taxonomy_for_object_type($taxonomy->name, 'rfe_taxonomy_related');
}
}
Now I can move the meta boxes below the content using remove_meta_box
and add_meta_box
:
public function rename_taxonomy_meta_boxes_on_rfe_taxonomy_related__premium_only()
{
//Stores display names of post types so we can cache them
$post_type_names = [];
$taxonomies = get_taxonomies(['public' => true], 'objects');
foreach ($taxonomies as $taxonomy) {
//Skip our own taxonomy
if ('rfe_taxonomy_related_category' === $taxonomy->name) {
continue;
}
$taxonomy_name = $taxonomy->labels->name;
$taxonomy_slug = $taxonomy->name;
$taxonomy_post_types = [];
$object_type = $taxonomy->object_type;
foreach ($object_type as $post_type) {
//Skip our own post type
if ('rfe_taxonomy_related' === $post_type) {
continue;
}
$post_type_name = isset($post_type_names[$post_type]) ? $post_type_names[$post_type] : false;
if (!$post_type_name) {
$post_type_name = get_post_type_object($post_type)->label;
$post_type_names[$post_type] = $post_type_name;
}
$taxonomy_post_types[] = $post_type_name;
}
if ($taxonomy->hierarchical) {
$meta_box_id = $taxonomy_slug . 'div';
$meta_box_callback = 'post_categories_meta_box';
} else {
$meta_box_id = 'tagsdiv-' . $taxonomy_slug;
$meta_box_callback = 'post_tags_meta_box';
}
remove_meta_box($meta_box_id, 'rfe_taxonomy_related', 'side');
add_meta_box(
$meta_box_id,
$taxonomy_name . ' (' . implode(', ', $taxonomy_post_types) . ')',
$meta_box_callback,
'rfe_taxonomy_related',
'normal',
'low',
['taxonomy' => $taxonomy_slug]
);
}
}
And finally hide the submenu pages for the taxonomies except for the custom one I added to my post type myself:
public function remove_taxonomy_menu_from_rfe_taxonomy_related__premium_only()
{
global $submenu;
//Get all the taxonomies of which we need to remove the submenu
$taxonomies = [];
foreach (get_taxonomies(['public' => true], 'objects') as $taxonomy) {
if ('rfe_taxonomy_related_category' === $taxonomy->name) {
continue;
}
$taxonomies[] = $taxonomy->name;
}
$post_type = 'rfe_taxonomy_related';
if (isset($submenu['edit.php?post_type=' . $post_type])) {
foreach ($submenu['edit.php?post_type=' . $post_type] as $k => $sub) {
$should_remove = false;
foreach ($taxonomies as $taxonomy) {
if (strpos($sub[2], 'taxonomy=' . $taxonomy)) {
$should_remove = true;
break;
}
}
if ($should_remove) {
unset($submenu['edit.php?post_type=' . $post_type][$k]);
}
}
}
}
If you have suggestions to improve the code, I'd love to hear about them!
register_taxonomy_for_object_type()
function, to add already registered taxonomy to your custom post type. Maybe take a look here: https://pippinsplugins.com/add-already-registered-taxonomy/ or the Codex link – LWS-Mo Commented May 2, 2018 at 12:07register_taxonomy_for_object_type
first but it adds the meta boxes to the side and it can get confusing if you have two taxonomies called "Categories" but on different post types. – xxtesaxx Commented May 2, 2018 at 12:15register_taxonomy_for_object_type
, after thatremove_meta_box
and thanadd_meta_box
again with a custom context/position. But seems like an overhead. – LWS-Mo Commented May 2, 2018 at 13:31