post_type = $post_type; $this->init_hooks(); } /** * Initialize admin hooks. */ private function init_hooks() { add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_styles' ) ); add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) ); add_action( 'save_post_' . $this->post_type->get_post_type_slug(), array( $this, 'save_meta' ), 10, 2 ); add_filter( 'manage_' . $this->post_type->get_post_type_slug() . '_posts_columns', array( $this, 'set_custom_columns' ) ); add_action( 'manage_' . $this->post_type->get_post_type_slug() . '_posts_custom_column', array( $this, 'render_custom_columns' ), 10, 2 ); add_filter( 'post_row_actions', array( $this, 'modify_row_actions' ), 10, 2 ); add_action( 'admin_menu', array( $this, 'add_admin_menu' ) ); add_action( 'parent_file', array( $this, 'highlight_menu' ) ); add_action( 'admin_init', array( $this, 'handle_add_new_form' ) ); } /** * Enqueue admin styles. */ public function enqueue_styles() { $screen = get_current_screen(); if ( ! $screen ) { return; } // Only enqueue on changelog post type screens. if ( $this->post_type->get_post_type_slug() !== $screen->post_type ) { return; } // Enqueue admin stylesheet. if ( file_exists( PC_CLM_PLUGIN_DIR . 'admin/css/admin-style.css' ) ) { wp_enqueue_style( 'pc-clm-admin-style', PC_CLM_PLUGIN_URL . 'admin/css/admin-style.css', array(), PC_CLM_VERSION ); } } /** * Add admin menu items. */ public function add_admin_menu() { add_menu_page( __( 'Changelog', 'pc-changelog-manager-abc123' ), __( 'Changelog', 'pc-changelog-manager-abc123' ), 'manage_options', 'pc-clm-view-changelog', array( $this, 'render_view_changelog_page' ), 'dashicons-backup', 30 ); add_submenu_page( 'pc-clm-view-changelog', __( 'Add New Changelog Entry', 'pc-changelog-manager-abc123' ), __( 'Add New', 'pc-changelog-manager-abc123' ), 'manage_options', 'pc-clm-add-new', array( $this, 'render_add_new_page' ) ); } /** * Render the main menu page (no-op). * The top-level menu now links directly to the post list to avoid redirects * that may run after headers/styles have already been sent. */ public function render_main_menu_page() { // Intentionally left blank to avoid header() calls after output. } /** * Render the view changelog page - displays changelog entries in admin. */ public function render_view_changelog_page() { $post_type = new PC_CLM_Post_Type(); $query = $post_type->get_entries(); ?>


have_posts() ) : ?>
have_posts() ) : $query->the_post(); $post_id = get_the_ID(); $version = $post_type->get_meta( $post_id, 'version_number' ); $release_date = $post_type->get_meta( $post_id, 'release_date' ); $category = $post_type->get_meta( $post_id, 'category' ); $categories = $post_type->get_categories(); $category_name = isset( $categories[ $category ] ) ? $categories[ $category ] : $category; ?>

$title, 'post_content' => $content, 'post_status' => 'publish', 'post_type' => $this->post_type->get_post_type_slug(), ) ); if ( ! is_wp_error( $post_id ) ) { $this->post_type->update_meta( $post_id, 'version_number', $version ); $this->post_type->update_meta( $post_id, 'release_date', $release_date ); $this->post_type->update_meta( $post_id, 'category', $category ); add_action( 'admin_notices', function() { echo '

' . esc_html__( 'Changelog entry added successfully!', 'pc-changelog-manager-abc123' ) . '

'; } ); } } /** * Render the add new changelog page. */ public function render_add_new_page() { $categories = $this->post_type->get_categories(); $default_version = '1.0.0'; $default_date = current_time( 'Y-m-d' ); ?>


true, 'textarea_rows' => 10, 'teeny' => false, ) ); ?>

base ) && 'pc-clm-view-changelog' === $current_screen->base ) { $parent_file = 'pc-clm-view-changelog'; $submenu_file = 'pc-clm-view-changelog'; } // Handle our custom add new page. if ( isset( $current_screen->base ) && 'pc-clm-add-new' === $current_screen->base ) { $parent_file = 'pc-clm-view-changelog'; $submenu_file = 'pc-clm-add-new'; } return $parent_file; } /** * Add meta boxes to the changelog entry editor. */ public function add_meta_boxes() { add_meta_box( 'pc_clm_entry_details', __( 'Entry Details', 'pc-changelog-manager-abc123' ), array( $this, 'render_entry_details_meta_box' ), $this->post_type->get_post_type_slug(), 'normal', 'high' ); add_meta_box( 'pc_clm_preview', __( 'Preview', 'pc-changelog-manager-abc123' ), array( $this, 'render_preview_meta_box' ), $this->post_type->get_post_type_slug(), 'side', 'low' ); } /** * Render the entry details meta box. * * @param WP_Post $post Current post object. */ public function render_entry_details_meta_box( $post ) { // Add nonce field. wp_nonce_field( 'pc_clm_save_meta', 'pc_clm_meta_nonce' ); // Get current values. $version_number = $this->post_type->get_meta( $post->ID, 'version_number' ); $release_date = $this->post_type->get_meta( $post->ID, 'release_date' ); $category = $this->post_type->get_meta( $post->ID, 'category' ); $categories = $this->post_type->get_categories(); // Set default values for new posts. if ( empty( $version_number ) ) { $version_number = '1.0.0'; } if ( empty( $release_date ) ) { $release_date = current_time( 'Y-m-d' ); } ?>

post_type->update_meta( $post_id, 'version_number', sanitize_text_field( wp_unslash( $_POST['pc_clm_version_number'] ) ) ); } // Save release date. if ( isset( $_POST['pc_clm_release_date'] ) ) { $this->post_type->update_meta( $post_id, 'release_date', sanitize_text_field( wp_unslash( $_POST['pc_clm_release_date'] ) ) ); } // Save category. if ( isset( $_POST['pc_clm_category'] ) ) { $allowed_categories = array_keys( $this->post_type->get_categories() ); $category = sanitize_text_field( wp_unslash( $_POST['pc_clm_category'] ) ); if ( in_array( $category, $allowed_categories, true ) ) { $this->post_type->update_meta( $post_id, 'category', $category ); } } } /** * Set custom columns for the admin list view. * * @param array $columns Existing columns. * @return array */ public function set_custom_columns( $columns ) { unset( $columns['date'] ); $new_columns = array( 'version' => __( 'Version', 'pc-changelog-manager-abc123' ), 'release_date' => __( 'Release Date', 'pc-changelog-manager-abc123' ), 'category' => __( 'Category', 'pc-changelog-manager-abc123' ), 'date' => __( 'Date', 'pc-changelog-manager-abc123' ), ); return array_merge( $columns, $new_columns ); } /** * Render custom column content. * * @param string $column Column name. * @param int $post_id Post ID. */ public function render_custom_columns( $column, $post_id ) { switch ( $column ) { case 'version': $version = $this->post_type->get_meta( $post_id, 'version_number' ); echo esc_html( $version ); break; case 'release_date': $release_date = $this->post_type->get_meta( $post_id, 'release_date' ); if ( $release_date ) { echo esc_html( date_i18n( get_option( 'date_format' ), strtotime( $release_date ) ) ); } else { echo '—'; } break; case 'category': $category = $this->post_type->get_meta( $post_id, 'category' ); $categories = $this->post_type->get_categories(); $category_name = isset( $categories[ $category ] ) ? $categories[ $category ] : $category; $category_class = 'pc-clm-category-' . esc_attr( $category ); echo ''; echo esc_html( $category_name ); echo ''; break; } } /** * Modify row actions in the admin list. * * @param array $actions Existing actions. * @param WP_Post $post Post object. * @return array */ public function modify_row_actions( $actions, $post ) { if ( $this->post_type->get_post_type_slug() !== $post->post_type ) { return $actions; } // Remove quick edit as it doesn't work well with custom meta. if ( isset( $actions['inline hide-if-no-js'] ) ) { unset( $actions['inline hide-if-no-js'] ); } return $actions; } } /** * Get the changelog page URL. * * @return string */ function pc_clm_get_changelog_page_url() { // First try to get the custom changelog page. $changelog_page = get_page_by_path( 'changelog' ); if ( $changelog_page && 'publish' === $changelog_page->post_status ) { return get_permalink( $changelog_page ); } // Fall back to the post type archive URL. $post_type = get_post_type_object( 'pc_changelog' ); if ( $post_type && $post_type->has_archive ) { return get_post_type_archive_link( 'pc_changelog' ); } // Final fallback to home URL with changelog slug. return home_url( '/changelog/' ); }