439 lines
12 KiB
PHP
439 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* Public Handler
|
|
*
|
|
* @package PCChangelogManager
|
|
*/
|
|
|
|
// Prevent direct access to the file.
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Handles all public-facing functionality for the changelog manager.
|
|
*/
|
|
class PC_CLM_Public {
|
|
|
|
/**
|
|
* Instance of the post type class.
|
|
*
|
|
* @var PC_CLM_Post_Type
|
|
*/
|
|
private $post_type;
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param PC_CLM_Post_Type $post_type Post type instance.
|
|
*/
|
|
public function __construct( $post_type ) {
|
|
$this->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() ) {
|
|
?>
|
|
<div class="pc-clm-shortcode-wrapper">
|
|
<?php if ( 'yes' === $atts['show_title'] ) : ?>
|
|
<h2 class="pc-clm-shortcode-title"><?php esc_html_e( 'Changelog', 'pc-changelog-manager-abc123' ); ?></h2>
|
|
<?php endif; ?>
|
|
|
|
<div class="pc-clm-entries-list">
|
|
<?php
|
|
while ( $query->have_posts() ) :
|
|
$query->the_post();
|
|
$this->render_entry( get_the_ID(), $atts );
|
|
endwhile;
|
|
?>
|
|
</div>
|
|
</div>
|
|
<?php
|
|
wp_reset_postdata();
|
|
} else {
|
|
?>
|
|
<div class="pc-clm-no-entries">
|
|
<p><?php esc_html_e( 'No changelog entries found.', 'pc-changelog-manager-abc123' ); ?></p>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
return ob_get_clean();
|
|
}
|
|
|
|
/**
|
|
* Render a single changelog entry.
|
|
*
|
|
* @param int $post_id Post ID.
|
|
* @param array $atts Shortcode attributes.
|
|
*/
|
|
private function render_entry( $post_id, $atts ) {
|
|
$version = $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();
|
|
$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;
|
|
}
|
|
|
|
?>
|
|
<article class="<?php echo esc_attr( implode( ' ', $entry_classes ) ); ?>" id="pc-clm-entry-<?php echo esc_attr( $post_id ); ?>">
|
|
<div class="pc-clm-entry-inner">
|
|
<div class="pc-clm-entry-header">
|
|
<div class="pc-clm-entry-meta">
|
|
<?php if ( $version ) : ?>
|
|
<span class="pc-clm-version-badge"><?php echo esc_html( $version ); ?></span>
|
|
<?php endif; ?>
|
|
|
|
<?php if ( 'yes' === $atts['show_date'] && $release_date ) : ?>
|
|
<span class="pc-clm-release-date"><?php echo esc_html( date_i18n( get_option( 'date_format' ), strtotime( $release_date ) ) ); ?></span>
|
|
<?php endif; ?>
|
|
|
|
<?php if ( $category ) : ?>
|
|
<span class="pc-clm-category-badge pc-clm-category-<?php echo esc_attr( $category ); ?>"><?php echo esc_html( $category_name ); ?></span>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="pc-clm-upvote-section">
|
|
<button class="pc-clm-upvote-btn <?php echo $has_voted ? 'voted' : ''; ?>"
|
|
data-post-id="<?php echo esc_attr( $post_id ); ?>"
|
|
<?php echo $has_voted ? 'disabled' : ''; ?>>
|
|
<span class="pc-clm-upvote-icon">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
|
|
<path d="M12 2l2.4 7.4h7.6l-6 4.6 2.3 7.4-6.3-4.6-6.3 4.6 2.3-7.4-6-4.6h7.6z"/>
|
|
</svg>
|
|
</span>
|
|
<span class="pc-clm-upvote-count"><?php echo esc_html( $upvote_count ); ?></span>
|
|
</button>
|
|
<span class="pc-clm-upvote-label"><?php echo esc_html( _n( 'upvote', 'upvotes', $upvote_count, 'pc-changelog-manager-abc123' ) ); ?></span>
|
|
</div>
|
|
</div>
|
|
|
|
<h3 class="pc-clm-entry-title">
|
|
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
|
|
</h3>
|
|
|
|
<div class="pc-clm-entry-content">
|
|
<?php the_excerpt(); ?>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* Enqueue public scripts.
|
|
*/
|
|
public function enqueue_scripts() {
|
|
// 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/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() ) {
|
|
?>
|
|
<div class="pc-clm-entries-list">
|
|
<?php
|
|
while ( $query->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;
|
|
}
|
|
?>
|
|
<article id="post-<?php the_ID(); ?>" <?php post_class( $entry_classes ); ?>>
|
|
<div class="pc-clm-entry-inner">
|
|
<div class="pc-clm-entry-meta">
|
|
<?php if ( $version ) : ?>
|
|
<span class="pc-clm-version-badge"><?php echo esc_html( $version ); ?></span>
|
|
<?php endif; ?>
|
|
|
|
<?php if ( $release_date ) : ?>
|
|
<span class="pc-clm-release-date"><?php echo esc_html( date_i18n( get_option( 'date_format' ), strtotime( $release_date ) ) ); ?></span>
|
|
<?php endif; ?>
|
|
|
|
<?php if ( $category ) : ?>
|
|
<span class="pc-clm-category-badge pc-clm-category-<?php echo esc_attr( $category ); ?>"><?php echo esc_html( $category_name ); ?></span>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<h3 class="pc-clm-entry-title">
|
|
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
|
|
</h3>
|
|
|
|
<div class="pc-clm-entry-content">
|
|
<?php the_excerpt(); ?>
|
|
</div>
|
|
</div>
|
|
</article>
|
|
<?php
|
|
endwhile;
|
|
?>
|
|
</div>
|
|
<?php
|
|
} else {
|
|
?>
|
|
<div class="pc-clm-no-entries">
|
|
<p><?php esc_html_e( 'No changelog entries found.', 'pc-changelog-manager-abc123' ); ?></p>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
wp_reset_postdata();
|
|
}
|