__( 'Book Pages', 'adventurebook' ), 'singular_name' => __( 'Book Page', 'adventurebook' ), 'menu_name' => __( 'Book Pages', 'adventurebook' ), 'name_admin_bar' => __( 'Book Page', 'adventurebook' ), 'add_new' => __( 'Add New Page', 'adventurebook' ), 'add_new_item' => __( 'Add New Book Page', 'adventurebook' ), 'new_item' => __( 'New Book Page', 'adventurebook' ), 'edit_item' => __( 'Edit Book Page', 'adventurebook' ), 'view_item' => __( 'View Book Page', 'adventurebook' ), 'all_items' => __( 'Book Pages', 'adventurebook' ), 'search_items' => __( 'Search Book Pages', 'adventurebook' ), 'not_found' => __( 'No book pages found.', 'adventurebook' ), 'not_found_in_trash' => __( 'No book pages found in Trash.', 'adventurebook' ) ); $args = array( 'labels' => $labels, 'public' => false, 'publicly_queryable' => false, 'exclude_from_search' => true, 'show_ui' => true, 'show_in_menu' => 'adventurebook_main', 'query_var' => true, 'rewrite' => false, 'capability_type' => 'post', 'has_archive' => true, 'hierarchical' => true, // Allows pages to be a "child" of a book 'menu_position' => 6, 'menu_icon' => 'dashicons-admin-page', 'supports' => array( 'title', 'editor' ), 'show_in_rest' => true, ); register_post_type( 'adventurebook_page', $args ); } /** * Add parent filter dropdown in the admin list with nonce field */ add_action( 'restrict_manage_posts', 'adventurebook_page_parent_filter' ); function adventurebook_page_parent_filter() { global $typenow; if ( $typenow !== 'adventurebook_page' ) { return; } $parents = get_posts( array( 'post_type' => 'adventurebook', 'posts_per_page' => - 1, 'orderby' => 'title', 'order' => 'ASC' ) ); // Security-Check: check for nonce if ( isset( $_GET['adventurebook_filter_nonce'] ) && ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['adventurebook_filter_nonce'] ) ), 'adventurebook_filter_action' ) ) { return; } $user_id = get_current_user_id(); $persisted_parent = get_user_meta( $user_id, 'adventurebook_last_parent', true ); $selected = isset( $_GET['adventurebook_parent'] ) ? sanitize_text_field( wp_unslash( $_GET['adventurebook_parent'] ) ) : $persisted_parent; echo ''; // Output nonce field for the filter wp_nonce_field( 'adventurebook_filter_action', 'adventurebook_filter_nonce' ); } /** * Apply filter to the list and save user meta only if nonce is valid */ add_action( 'pre_get_posts', 'adventurebook_page_filter_by_parent' ); function adventurebook_page_filter_by_parent( $query ) { global $pagenow; if ( $pagenow !== 'edit.php' ) { return; } if ( $query->get( 'post_type' ) !== 'adventurebook_page' ) { return; } $user_id = get_current_user_id(); if ( isset( $_GET['adventurebook_parent'] ) ) { // Verify nonce before persisting if ( ! isset( $_GET['adventurebook_filter_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['adventurebook_filter_nonce'] ) ), 'adventurebook_filter_action' ) ) { return; } $parent_id = intval( $_GET['adventurebook_parent'] ); if ( $parent_id > 0 ) { update_user_meta( $user_id, 'adventurebook_last_parent', $parent_id ); $query->set( 'post_parent', $parent_id ); } else { delete_user_meta( $user_id, 'adventurebook_last_parent' ); } } else { $last_parent = get_user_meta( $user_id, 'adventurebook_last_parent', true ); if ( $last_parent ) { $query->set( 'post_parent', intval( $last_parent ) ); } } } /** * Keep filter persistent on redirects */ add_filter( 'redirect_post_location', 'adventurebook_persist_parent_filter_redirect', 10, 2 ); function adventurebook_persist_parent_filter_redirect( $location, $post_id ) { if ( get_post_type( $post_id ) !== 'adventurebook_page' ) { return $location; } // Security-Check: check for nonce if ( isset( $_GET['adventurebook_filter_nonce'] ) && ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['adventurebook_filter_nonce'] ) ), 'adventurebook_filter_action' ) ) { return $location; } $user_id = get_current_user_id(); $last_parent = get_user_meta( $user_id, 'adventurebook_last_parent', true ); if ( $last_parent ) { $location = add_query_arg( 'adventurebook_parent', intval( $last_parent ), $location ); } return $location; } /** * Hide the default Add New button */ add_action( 'admin_head', 'adventurebook_hide_default_add_new_button' ); function adventurebook_hide_default_add_new_button() { global $typenow; if ( $typenow !== 'adventurebook_page' ) { return; } echo ''; } /** * Add custom Add New Book Page button next to the post type title */ add_action( 'admin_notices', 'adventurebook_add_new_button_standard_position' ); function adventurebook_add_new_button_standard_position() { global $pagenow, $typenow; if ( $pagenow !== 'edit.php' || $typenow !== 'adventurebook_page' ) { return; } $user_id = get_current_user_id(); $last_parent = get_user_meta( $user_id, 'adventurebook_last_parent', true ); if ( empty( $last_parent ) ) { $first_parent = get_posts( array( 'post_type' => 'adventurebook', 'posts_per_page' => 1, 'orderby' => 'title', 'order' => 'ASC' ) ); if ( $first_parent ) { $last_parent = $first_parent[0]->ID; } } $link = add_query_arg( array( 'post_type' => 'adventurebook_page', 'parent_adventurebook' => intval( $last_parent ), '_adventurebook_nonce' => wp_create_nonce( 'adventurebook_set_parent_action' ) ), admin_url( 'post-new.php' ) ); echo ''; } /** * Automatically set parent when creating a new adventurebook_page * (already uses nonce verification via _adventurebook_nonce) */ add_action( 'load-post-new.php', 'adventurebook_set_new_page_parent' ); function adventurebook_set_new_page_parent() { if ( ! isset( $_GET['parent_adventurebook'] ) ) { return; } if ( ! isset( $_GET['_adventurebook_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_adventurebook_nonce'] ) ), 'adventurebook_set_parent_action' ) ) { return; } $parent_id = intval( $_GET['parent_adventurebook'] ); add_action( 'save_post_adventurebook_page', function ( $post_id, $post, $update ) use ( $parent_id ) { if ( ! $update ) { wp_update_post( array( 'ID' => $post_id, 'post_parent' => $parent_id ) ); } }, 10, 3 ); } /** * Get the adventurebook type of the parent adventurebook of the given post type * returns "storybook", "game" or null if not applicable * * @param $post_type * @param null $post * * @return string|null */ function adventurebook_get_type( $post_type, $post = null ): ?string { if ( $post_type !== 'adventurebook_page' ) { return null; } // context check if ( ! $post instanceof WP_Post ) { $post = get_post(); } if ( ! $post ) { return null; } // nonce check if ( isset( $_REQUEST['_wpnonce'] ) && ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'adventurebook_edit_page' ) ) { return null; } // check if the adventurebook (parent of this page) is "game"-type // get the parent $parent_id = wp_get_post_parent_id( $post->ID ); if ( ! $parent_id ) { return null; } $parent_post = get_post( $parent_id ); if ( ! $parent_post || $parent_post->post_type !== 'adventurebook' ) { return null; } return get_post_meta( $parent_id, '_adventurebook_type', true ); } // 1. Add a new column to the CPT admin table add_filter( 'manage_adventurebook_page_posts_columns', function ( $columns ) { // Insert new column after the Title column $new = []; foreach ( $columns as $key => $value ) { $new[ $key ] = $value; if ( 'title' === $key ) { $new['page_id'] = __( 'ID', 'adventurebook' ); } } return $new; } ); // 2. Render the column content add_action( 'manage_adventurebook_page_posts_custom_column', function ( $column_name, $post_id ) { if ( 'page_id' === $column_name ) { echo intval( $post_id ); } }, 10, 2 ); // 3. (Optional) Make it sortable add_filter( 'manage_edit-adventurebook_page_sortable_columns', function ( $columns ) { $columns['page_id'] = 'ID'; return $columns; } ); // add custom columns to the admin list function adventurebook_page_add_custom_columns( $columns ) { $columns['decisions'] = __( 'Decisions', 'adventurebook' ); $columns['item_spawns'] = __( 'Item Spawns', 'adventurebook' ); $columns['enemy_spawns'] = __( 'Enemy Spawns', 'adventurebook' ); $columns['resources'] = __( 'Resources', 'adventurebook' ); return $columns; } // fill the custom columns with content add_filter( 'manage_adventurebook_page_posts_columns', 'adventurebook_page_add_custom_columns' ); add_action( 'manage_adventurebook_page_posts_custom_column', 'adventurebook_page_custom_column_content', 10, 2 ); function adventurebook_page_custom_column_content( $column, $post_id ) { if ( $column === 'decisions' ) { // list the decisions for this page // they are stored as post meta with key "_adventurebook_decisions" as an array of arrays $decisions = get_post_meta( $post_id, '_adventurebook_decision_options', true ); if ( is_array( $decisions ) && count( $decisions ) > 0 ) { echo '