post_type = $post_type; $this->init_hooks(); } /** * Initialize public hooks. */ private function init_hooks() { add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_styles' ) ); add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); add_filter( 'template_include', array( $this, 'template_loader' ) ); add_shortcode( 'changelog', array( $this, 'shortcode_changelog' ) ); add_action( 'widgets_init', array( $this, 'register_widgets' ) ); add_action( 'wp_ajax_pc_clm_upvote', array( $this, 'handle_upvote' ) ); add_action( 'wp_ajax_nopriv_pc_clm_upvote', array( $this, 'handle_upvote' ) ); } /** * Enqueue public styles. */ public function enqueue_styles() { // Check if we're on the changelog page or if shortcode is used. if ( ! $this->is_changelog_page() && ! $this->is_changelog_single() && ! $this->has_shortcode() ) { return; } $min_suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; if ( file_exists( PC_CLM_PLUGIN_DIR . 'public/css/public-style.css' ) ) { // Enqueue main stylesheet. if ( ! wp_style_is( 'pc-clm-public-style', 'enqueued' ) ) { wp_enqueue_style( 'pc-clm-public-style', PC_CLM_PLUGIN_URL . 'public/css/public-style.css', array(), PC_CLM_VERSION ); } } } /** * Check if we're on the changelog page. * * @return bool */ private function is_changelog_page() { return is_post_type_archive( $this->post_type->get_post_type_slug() ); } private function is_changelog_single() { return is_singular( $this->post_type->get_post_type_slug() ); } /** * Check if the page has the changelog shortcode. * * @return bool */ private function has_shortcode() { if ( ! is_singular() ) { return false; } $post = get_post(); if ( ! $post ) { return false; } return has_shortcode( $post->post_content, 'changelog' ); } public function template_loader( $template ) { if ( is_singular( $this->post_type->get_post_type_slug() ) ) { $custom_template = PC_CLM_PLUGIN_DIR . 'public/templates/single-pc_changelog.php'; if ( file_exists( $custom_template ) ) { return $custom_template; } } return $template; } /** * Changelog shortcode. * * @param array $atts Shortcode attributes. * @return string */ public function shortcode_changelog( $atts ) { $atts = shortcode_atts( array( 'limit' => 10, 'category' => '', 'show_date' => 'yes', 'show_title' => 'yes', 'order' => 'DESC', ), $atts, 'changelog' ); // Enqueue styles for the shortcode output. if ( file_exists( PC_CLM_PLUGIN_DIR . 'public/css/public-style.css' ) ) { wp_enqueue_style( 'pc-clm-public-style', PC_CLM_PLUGIN_URL . 'public/css/public-style.css', array(), PC_CLM_VERSION ); } // Build query args. $query_args = array( 'post_type' => $this->post_type->get_post_type_slug(), 'post_status' => 'publish', 'posts_per_page' => intval( $atts['limit'] ), 'orderby' => 'date', 'order' => 'DESC' === $atts['order'] ? 'DESC' : 'ASC', ); // Filter by category if specified. if ( ! empty( $atts['category'] ) ) { $query_args['meta_query'] = array( array( 'key' => '_pc_clm_category', 'value' => sanitize_text_field( $atts['category'] ), ), ); } $query = new WP_Query( $query_args ); ob_start(); if ( $query->have_posts() ) { ?>

have_posts() ) : $query->the_post(); $this->render_entry( get_the_ID(), $atts ); endwhile; ?>

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(); $category_name = isset( $categories[ $category ] ) ? $categories[ $category ] : $category; $upvote_count = $this->get_upvote_count( $post_id ); $has_voted = $this->has_user_voted( $post_id ); $entry_classes = array( 'pc-clm-entry' ); if ( $category ) { $entry_classes[] = 'pc-clm-category-' . $category; } ?>

is_changelog_page() && ! $this->is_changelog_single() && ! $this->has_shortcode() ) { return; } $min_suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; if ( file_exists( PC_CLM_PLUGIN_DIR . 'public/js/public-script.js' ) ) { wp_enqueue_script( 'pc-clm-public-script', PC_CLM_PLUGIN_URL . 'public/js/public-script.js', array( 'jquery' ), PC_CLM_VERSION, true ); wp_localize_script( 'pc-clm-public-script', 'pc_clm_ajax', array( 'ajax_url' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'pc_clm_upvote_nonce' ), ) ); } } /** * Handle upvote AJAX request. */ public function handle_upvote() { check_ajax_referer( 'pc_clm_upvote_nonce', 'nonce' ); if ( ! isset( $_POST['post_id'] ) ) { wp_die( 'Invalid request' ); } $post_id = intval( $_POST['post_id'] ); $ip_address = $_SERVER['REMOTE_ADDR']; $user_id = get_current_user_id(); // Check if user has already voted (by IP or user ID if logged in) $voted_key = $user_id ? "pc_clm_voted_user_{$user_id}" : "pc_clm_voted_ip_{$ip_address}"; $voted_posts = get_transient( $voted_key ); if ( ! $voted_posts ) { $voted_posts = array(); } if ( in_array( $post_id, $voted_posts ) ) { wp_send_json_error( array( 'message' => __( 'You have already voted for this entry.', 'pc-changelog-manager-abc123' ) ) ); return; } // Get current vote count $vote_count = get_post_meta( $post_id, '_pc_clm_upvotes', true ) ?: 0; $new_vote_count = intval( $vote_count ) + 1; // Update vote count update_post_meta( $post_id, '_pc_clm_upvotes', $new_vote_count ); // Mark as voted (expires after 30 days) $voted_posts[] = $post_id; set_transient( $voted_key, $voted_posts, 30 * DAY_IN_SECONDS ); wp_send_json_success( array( 'vote_count' => $new_vote_count, 'message' => __( 'Thank you for voting!', 'pc-changelog-manager-abc123' ), ) ); } /** * Get upvote count for a post. * * @param int $post_id Post ID. * @return int */ public function get_upvote_count( $post_id ) { $vote_count = get_post_meta( $post_id, '_pc_clm_upvotes', true ); return intval( $vote_count ); } /** * Check if current user has voted for a post. * * @param int $post_id Post ID. * @return bool */ public function has_user_voted( $post_id ) { $ip_address = $_SERVER['REMOTE_ADDR']; $user_id = get_current_user_id(); $voted_key = $user_id ? "pc_clm_voted_user_{$user_id}" : "pc_clm_voted_ip_{$ip_address}"; $voted_posts = get_transient( $voted_key ); if ( ! $voted_posts ) { return false; } return in_array( $post_id, $voted_posts ); } /** * Register widgets. */ public function register_widgets() { require_once PC_CLM_PLUGIN_DIR . 'public/widgets/class-changelog-widget.php'; register_widget( 'PC_CLM_Widget' ); } } /** * Template function to display changelog entries. * * @param array $args Query arguments. */ function pc_clm_display_changelog( $args = array() ) { $post_type = new PC_CLM_Post_Type(); $query = $post_type->get_entries( $args ); if ( $query->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; $entry_classes = array( 'pc-clm-entry' ); if ( $category ) { $entry_classes[] = 'pc-clm-category-' . $category; } ?>
>