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;
}
?>
>