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' );
?>
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/' );
}