Make/create a category for every page

Here’s how you do it… It’s quite extensive. I have no idea if this is the best way or not, – but this is how I solved it. There might be a couple of errors in the code. But it works for me.

This is a quite specific wish for a functionality. Another way to go about it would be to just make the category.php-page do the same thing (since it basically does the same thing.

Generate a list of the pages that should be emitted from getting a category created

function generate_the_excluded_array() {

    global $excluded_pages;
    $excluded_pages = array(); // Add all pages with the search-template
    $search_pages = get_pages(array(
        'meta_key' => '_wp_page_template',
        'meta_value' => 'page-search.php'
    ));

    $excluded_pages[] = get_option( 'page_on_front' ); // Add home page
    foreach($search_pages as $page){
        // Add all pages that has the search-page-template activated
        $excluded_pages[] = $page->ID;
    }
}
add_action( 'after_setup_theme', 'generate_the_excluded_array' );

Upon save, – then get a list of all pages and iterate through them

function custom_set_category_on_cpt() {

    global $page_category_mapping;
    global $excluded_pages;
    $local_excluded_pages = implode(', ', $excluded_pages );

    $pages_args = array(
        'sort_order' => 'asc',
        'sort_column' => 'post_title',
        'hierarchical' => 1,
        'exclude' => $local_excluded_pages,
        'include' => '',
        'meta_key' => '',
        'meta_value' => '',
        'authors' => '',
        'child_of' => 0,
        'parent' => 0,
        'exclude_tree' => '',
        'number' => '',
        'offset' => 0,
        'post_type' => 'page',
        'post_status' => 'publish'
    );
    $pages = get_pages( $pages_args );
    foreach( $pages as $page ){
        custom_create_category_and_check_for_page_children( $page, 0 );
    }
    purge_categories(); // A function for deleting categories that don't have a corresponding page.

}
add_action( 'save_post', 'custom_set_category_on_cpt' );

A function for purging the categories

function purge_categories( $page_category_mapping_) {

    global $page_category_mapping;

    $category_args = array(
        'hide_empty' => 0,
        'exclude' => array(1),
    );
    $categories = get_categories( $category_args );
    foreach($categories as $category){

        $category_args = array(
            'name' => $category->name,
            'hide_empty' => false,
            'parent' => $category->category_parent
        );
        $category_array = get_terms( 'category', $category_args );
        $page_ID_with_corresponding_name="";

        foreach ( $page_category_mapping as $key => $val ) {
            if( $category_array[0]->term_id === $val[ 'category_ID' ] ){
                $page_ID_with_corresponding_name = $key;
            }
        }
        if( empty( $page_ID_with_corresponding_name ) ) {
            wp_delete_category( $category_array[0]->term_id );
        }
    }
}

A function for determining if a page has children or not

function custom_page_has_children( $post_ID ) {
    $children = get_pages( array( 'child_of' => $post_ID ) );
    if( count( $children ) == 0 ) {
        return false;
    } else {
        return true;
    }
}

A (recursive) function for creating the category and check if that page has any children

function custom_create_category_and_check_for_page_children( $page, $page_parent ){

    custom_create_category_for_page( $page );
    if( custom_page_has_children( $page->ID ) ){
        $list_childpages_arg = array(
            'sort_order'   => 'asc',
            'sort_column'  => 'post_title',
            'hierarchical' => 1,
            'exclude'      => '',
            'include'      => '',
            'meta_key'     => '',
            'meta_value'   => '',
            'authors'      => '',
            'child_of'     => 0,
            'parent'       => $page->ID,
            'exclude_tree' => '',
            'number'       => '',
            'offset'       => 0,
            'post_type'    => 'page',
            'post_status'  => 'publish',
        );
        $childpages = get_pages( $list_childpages_arg);
        foreach( $childpages as $childpage ){
            custome_create_category_and_check_for_page_children( $childpage, $page->ID );
            custom_create_category_for_page( $childpage );
        }
    }
}

And this function has this as a part of it:

function custom_create_category_for_page( $page ){

    global $page_category_mapping;
    if( $page->post_parent == 0 ){
        $categorys_parents_ID = 0;
    } else {
        $categorys_parents_ID = $page_category_mapping[ $page->post_parent ]['category_ID'];
    }

    $category_args = array(
        'name' => $page->post_title,
        'hide_empty' => false,
        'parent' => $categorys_parents_ID
    );
    $category_array = get_terms( 'category', $category_args );
    $category_ID = $category_array[0]->term_id;

    if( empty( $category_array) ) {
        $category_ID = wp_create_category( $page->post_title, $categorys_parents_ID );
    }

    if ( ! array_key_exists( $page->ID, $page_category_mapping ) ){
        $page_category_mapping[ $page->ID ] = array(
            'category_ID' => $category_ID,
            'category_parent_ID' => $categorys_parents_ID
        );
    }
}

Creating a page-to-category-mapping, to be utilized other places

function build_page_category_mapping() {

    global $excluded_pages;
    $local_excluded_pages = implode(', ', $excluded_pages );
    // Initializing empty array
    $page_category_mapping = array();

    $pages_args = array(
        'sort_order'   => 'asc',
        'sort_column'  => 'post_title',
        'hierarchical' => 1,
        'exclude'      => $local_excluded_pages,
        'include'      => '',
        'meta_key'     => '',
        'meta_value'   => '',
        'authors'      => '',
        'child_of'     => 0,
        'parent'       => - 1,
        'exclude_tree' => '',
        'number'       => '',
        'offset'       => 0,
        'post_type'    => 'page',
        'post_status'  => 'publish'
    );

    $all_pages = get_pages( $pages_args );
    foreach ( $all_pages as $page ) {
        $page_ancestors_array = get_ancestors( $page->ID, 'page', 'post_type' );
        $page_depth = count( $page_ancestors_array );
// GOOD FOR DEBUGGING
//      echo '<br /><br /><br /><br /><br />';
//      echo $page->post_title . ' is the post title<br />';
//      echo 'Depth: ' . $page_depth . '<br />';
        if ( $page_depth == 0 ) {
            $page_parent_ID = 0;
            $page_parent_name = null;
            $categorys_parents_ID = 0;
        } elseif ( $page_depth == 1 ){
            $page_parent_ID = $page_ancestors_array[0];
            $page_parent_name = get_post( $page_parent_ID )->post_title;

            $parent_category_args = array(
                'name' => $page_parent_name,
                'hide_empty' => false,
                'parent' => 0
            );
            $categorys_parents= get_terms( 'category', $parent_category_args );
            $categorys_parents_ID = $categorys_parents[0]->term_id;

        }   else {
            // Depth > 1
            $page_ancestors_array = array_reverse( $page_ancestors_array );

            // Two variables to determine how deep in the tree 'we've gotten'.
            $pages_temp_topmost = -1;
            $pages_temp_nextonedown = -1;
            $page_parent_name="";

            $i = 0; // Iteration counter

            $find_the_right_category_array = array(); // Array for the output (category ancestry).
            foreach ( $page_ancestors_array as $ancestor ) {
                if( $pages_temp_topmost === -1 && $pages_temp_nextonedown === -1 ){
                    $pages_temp_topmost = $ancestor;

                    $ancestor_category_args = array(
                        'name' => get_post( $ancestor )->post_title,
                        'hide_empty' => false,
                        'parent' => 0
                    );
                    $ancestor_category_array = get_terms( 'category', $ancestor_category_args );

                    if( count( $ancestor_category_array ) == 1){
                        $find_the_right_category_array[ $i ] = $ancestor_category_array[0];
                    } else {
                        throw new Exception("Exception code: 1 - This shouldn't be possible, -     but several categories was found with that parent and name");
                    }
                } elseif ( $pages_temp_topmost != -1 && $pages_temp_nextonedown === -1 ) {
                    $pages_temp_nextonedown = $ancestor;
                    $temp_var = (int) ($i - 1);
                    $ancestor_category_args = array(
                        'name' => get_post( $ancestor )->post_title,
                        'hide_empty' => false,
                        'parent' => $find_the_right_category_array[ $temp_var ]->term_id
                    );
                    $ancestor_category_array = get_terms( 'category', $ancestor_category_args );

                    if( count( $ancestor_category_array ) == 1){
                        $find_the_right_category_array[ $i ] = $ancestor_category_array[0];
                    } else {
                        throw new Exception("Exception code: 2 - This shouldn't be possible, -     but several categories was found with that parent and name");
                    }
                } else {
                    $temp_var = (int) ($i - 1);
                    $ancestor_category_args = array(
                        'name' => get_post( $ancestor )->post_title,
                        'hide_empty' => false,
                        'parent' => $find_the_right_category_array[ $temp_var ]->term_id
                    );
                    $ancestor_category_array = get_terms( 'category', $ancestor_category_args );
                    if( count( $ancestor_category_array ) == 1){
                        $find_the_right_category_array[ $i ] = $ancestor_category_array[0];
                    } else {
                        throw new Exception("Exception code: 3 - This shouldn't be possible, -     but several categories was found with that parent and name");
                    }
                }
                $i += 1;
            }
        end($find_the_right_category_array);
        $key = key( $find_the_right_category_array );
        $categorys_parents_ID = $find_the_right_category_array[ $key ]->term_id;
        }

        $category_args = array(
            'name' => $page->post_title,
            'hide_empty' => false,
            'parent' => $categorys_parents_ID
        );

        $category_array = get_terms( 'category', $category_args );
        // Since that can only return one category, then we can do the following:

        $category_ID = $category_array[0]->term_id;
// GOOD FOR DEBUGGING       
//      echo '<pre>';
//      echo 'Page: ' . $page->ID . ' - with the name: ' . $page->post_title . ' <br />';
//      echo 'Pages parent ' . $page_parent_ID . ' - with the name: ' . $page_parent_name . ' <br     />';
//      echo 'Category: ' . $category_ID . ' - with the name: ' . $page->post_title . ' <br />';
//      echo 'Categorys parent: ' . $categorys_parents_ID;
//      echo '</pre>';

        if ( ! array_key_exists( $page->ID, $page_category_mapping ) ){
            $page_category_mapping[ $page->ID ] = array(
                'category_ID' => $category_ID,
                'category_parent_ID' => $categorys_parents_ID
            );
        }
    }

    return $page_category_mapping;
}
add_action( 'init', 'build_page_category_mapping' );


// This might be redundant, but I'm not sure. 
global $page_category_mapping;
$page_category_mapping = build_page_category_mapping();

I know this is a huge mess… But it was the best (only) way I could make it happen.