0

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.

enter image description here

6
  • Its not 100% clear what you are trying to do from your question. Do you want, already registered taxonomies, to show in your custom post type and they should act / work like the normal/default taxonomy boxes? Than you should look at the 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:07
  • I want one meta box for each public taxonomy but it should be displayed below the content. I want to be able to select the terms as if it was a normal taxonomy meta box and later be able to query my custom post type to find out which terms of which taxonomy were selected. My custom post type will not be shown on the frontend. Maybe I can use the default taxonomy functionality if there is a possibility to add the post type of the term as name to the meta box title (so "Categories" become "Categories (Post)" and if the box can be displayed below the content instead of the side
    – xxtesaxx
    Commented May 2, 2018 at 12:12
  • I was thiking about register_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:15
  • Ah OK, I understand what you mean. However the way you tried to add these boxes, there will be no default behaviour, and you will also need save functions and stuff. Just an idea, maybe its possible to use register_taxonomy_for_object_type, after that remove_meta_box and than add_meta_box again with a custom context/position. But seems like an overhead.
    – LWS-Mo
    Commented May 2, 2018 at 13:31
  • OMG that actually works!
    – xxtesaxx
    Commented May 2, 2018 at 13:41

1 Answer 1

0

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!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.