PK     ,]'k( 3   3    CptPostHandler.phpnu         <?php

namespace Rvx\CPT\Shared;

use Rvx\Api\ProductApi;
use Rvx\CPT\CptHelper;
use Rvx\Utilities\Auth\Client;
use Rvx\Utilities\TransactionManager;
use Rvx\WPDrill\Response;
class CptPostHandler
{
    protected $cptHelper;
    public function __construct()
    {
        $this->cptHelper = new CptHelper();
    }
    public function __invoke($post_id, $post, $update)
    {
        // Ignore if called during autosave or automatic draft
        if (\defined('DOING_AUTOSAVE') && DOING_AUTOSAVE || \in_array($post->post_status, ['auto-draft', 'inherit'], \true)) {
            return;
        }
        // Define the target post types
        $enabled_post_types = $this->cptHelper->enabledCPT();
        $post_type = $post->post_type;
        $post_status = $post->post_status;
        if (!isset($enabled_post_types[$post_type])) {
            return;
        }
        if ($post_status === 'trash') {
            return;
        }
        // WP Independent Sync: We execute logic, but SaaS failure MUST NOT roll back WP.
        $is_new_sync = \get_post_meta($post_id, 'rvx_sync_new_status', \true);
        if (!$is_new_sync) {
            // Handle new post/product sync
            $response = $this->createHandler($post_id, $post);
            if ($response->getStatusCode() === Response::HTTP_OK) {
                $this->enableCommentsReviews($post_id);
                \update_post_meta($post_id, 'rvx_sync_new_status', 1, \true);
            } else {
                // If creation failed, try update as a fallback sync
                $response = $this->updateHandler($post_id, $post);
                if ($response->getStatusCode() === Response::HTTP_OK) {
                    $this->enableCommentsReviews($post_id);
                    \update_post_meta($post_id, 'rvx_sync_new_status', 1, \true);
                    \update_post_meta($post_id, 'rvx_sync_edit_status', 1, \true);
                } else {
                    \error_log("CptPostHandler Create/Update Sync Failed for ID {$post_id}: " . $response->getBody());
                }
            }
        } else {
            // Handle existing post/product update sync
            $response = $this->updateHandler($post_id, $post);
            if ($response->getStatusCode() === Response::HTTP_OK) {
                $this->enableCommentsReviews($post_id);
                \update_post_meta($post_id, 'rvx_sync_new_status', 1, \true);
                \update_post_meta($post_id, 'rvx_sync_edit_status', 1, \true);
            } else {
                \error_log("CptPostHandler Update Sync Failed for ID {$post_id}: " . $response->getBody());
            }
        }
    }
    public function createHandler($post_id, $post)
    {
        if ($post->post_type === 'product') {
            $payload = $this->createProductData($post_id, $post);
        } else {
            // Public -> custom post type
            $payload = $this->createPostData($post_id, $post);
        }
        return (new ProductApi())->create($payload);
    }
    public function updateHandler($post_id, $post)
    {
        if ($post->post_type === 'product') {
            $payload = $this->updatedProductData($post_id, $post);
        } else {
            // Public -> custom post type
            $payload = $this->updatedPostData($post_id, $post);
        }
        $uid = Client::getUid() . '-' . $post_id;
        return (new ProductApi())->update($payload, $uid);
    }
    private function createProductData($product_id, $post)
    {
        // Get the product object
        $product = wc_get_product($product_id);
        // Initialize variables
        $product_images = [];
        // Get the main product image
        $image_id = $product->get_image_id();
        // Featured image ID
        if ($image_id) {
            $product_images = wp_get_attachment_image_src($image_id, 'full');
            // Full-size image URL
        }
        if (empty($product_images)) {
            $product_images = '';
        }
        // Get the regular price
        $price = $product->get_regular_price();
        if (empty($price)) {
            $price = 0.0;
        }
        // Get the sale price (if available)
        $discounted_price = $product->get_sale_price();
        // If no sale price exists, the discounted price is the regular price
        if (empty($discounted_price)) {
            $discounted_price = $price;
        }
        return ["wp_id" => $product_id, "title" => isset($post->post_title) ? \htmlspecialchars($post->post_title, \ENT_QUOTES, 'UTF-8') : null, "url" => get_permalink($product_id), "description" => isset($post->short_description) ? \htmlspecialchars($post->short_description, \ENT_QUOTES, 'UTF-8') : null, "price" => $price, "discounted_price" => $discounted_price, "slug" => $post->post_name, "image" => $product_images[0] ?? (string) '', "status" => $this->postStatus($post->post_status), "post_type" => $post->post_type, "total_reviews" => (int) $this->getReviewCount($product_id), "avg_rating" => (float) $this->getAverageRating($product_id), "stars" => $this->getStarCounts($product_id), "category_wp_unique_ids" => $this->getCategoryIds($product_id)];
    }
    private function updatedProductData($product_id, $post)
    {
        // Get the product object
        $product = wc_get_product($product_id);
        // Initialize variables
        $product_images = [];
        // Get the main product image
        $image_id = $product->get_image_id();
        // Featured image ID
        if ($image_id) {
            $product_images = wp_get_attachment_image_src($image_id, 'full');
            // Full-size image URL
        }
        if (empty($product_images)) {
            $product_images = '';
        }
        // Get the regular price
        $price = $product->get_regular_price();
        if (empty($price)) {
            $price = 0.0;
        }
        // Get the sale price (if available)
        $discounted_price = $product->get_sale_price();
        // If no sale price exists, the discounted price is the regular price
        if (empty($discounted_price)) {
            $discounted_price = $price;
        }
        return ["wp_id" => $product_id, "title" => isset($post->post_title) ? \htmlspecialchars($post->post_title, \ENT_QUOTES, 'UTF-8') : null, "url" => get_permalink($product_id), "description" => isset($post->post_excerpt) ? \htmlspecialchars($post->post_excerpt, \ENT_QUOTES, 'UTF-8') : null, "price" => (float) $price, "discounted_price" => (float) $discounted_price, "slug" => $post->post_name, "image" => $product_images[0] ?? (string) '', "status" => $this->postStatus($post->post_status), "post_type" => $post->post_type, "total_reviews" => (int) $this->getReviewCount($product_id), "avg_rating" => (float) $this->getAverageRating($product_id), "category_wp_unique_ids" => $this->getCategoryIds($product_id)];
    }
    private function createPostData($post_id, $post)
    {
        $image_url = get_the_post_thumbnail_url($post->ID, 'full');
        if (empty($image_url)) {
            $image_url = '';
        }
        // $average_rating calculated via helper in return array
        $data = ["wp_id" => $post->ID, "title" => isset($post->post_title) ? \htmlspecialchars($post->post_title, \ENT_QUOTES, 'UTF-8') : null, "url" => get_permalink($post->ID), "description" => isset($post->post_excerpt) ? \htmlspecialchars($post->post_excerpt, \ENT_QUOTES, 'UTF-8') : null, "price" => 0, "discounted_price" => 0, "slug" => $post->post_name, "image" => (string) $image_url, "status" => $this->postStatus($post->post_status), "post_type" => get_post_type($post->ID), "total_reviews" => (int) $this->getReviewCount($post->ID), "avg_rating" => (float) $this->getAverageRating($post->ID), "stars" => $this->getStarCounts($post->ID), "category_wp_unique_ids" => $this->getCategoryIds($post_id)];
        return $data;
    }
    private function updatedPostData($post_id, $post)
    {
        $image_url = get_the_post_thumbnail_url($post->ID, 'full');
        if (empty($image_url)) {
            $image_url = '';
        }
        // $average_rating calculated via helper in return array
        $data = ["wp_id" => $post->ID, "title" => isset($post->post_title) ? \htmlspecialchars($post->post_title, \ENT_QUOTES, 'UTF-8') : null, "url" => get_permalink($post->ID), "description" => isset($post->post_excerpt) ? \htmlspecialchars($post->post_excerpt, \ENT_QUOTES, 'UTF-8') : null, "price" => 0, "discounted_price" => 0, "slug" => $post->post_name, "image" => (string) $image_url, "status" => $this->postStatus($post->post_status), "post_type" => get_post_type($post->ID), "total_reviews" => (int) $this->getReviewCount($post->ID), "avg_rating" => (float) $this->getAverageRating($post->ID), "stars" => $this->getStarCounts($post->ID), "category_wp_unique_ids" => $this->getCategoryIds($post_id)];
        return $data;
    }
    private function postStatus($status)
    {
        switch ($status) {
            case 'publish':
                return 1;
            case 'trash':
                return 2;
            default:
                return 3;
        }
    }
    private function getCategoryIds($post_id)
    {
        // Validate the post ID
        if (empty($post_id)) {
            \error_log("No valid post/product ID found.");
            return [];
        }
        // Get the post type
        $post_type = get_post_type($post_id);
        // Determine the taxonomy: 'product_cat' for products, hierarchical taxonomy for others
        $taxonomy = $post_type === 'product' ? 'product_cat' : null;
        if (!$taxonomy) {
            $taxonomies = get_object_taxonomies($post_type, 'objects');
            foreach ($taxonomies as $key => $taxonomy_obj) {
                if ($taxonomy_obj->hierarchical) {
                    $taxonomy = $key;
                    break;
                }
            }
        }
        // Retrieve category IDs or assign default if none are found
        $category_ids = [];
        if ($taxonomy) {
            $category_ids = wp_get_post_terms($post_id, $taxonomy, ['fields' => 'ids']);
        }
        if (empty($category_ids)) {
            $category_ids = [0];
        }
        // Append the UID prefix to each category ID
        $uid = Client::getUid();
        $parent_category_ids = [];
        foreach ($category_ids as $category_id) {
            $parent_category_ids[] = $uid . '-' . $category_id;
        }
        return $parent_category_ids;
    }
    private function getStarCounts($post_id)
    {
        $check = \get_post_meta($post_id, 'rvx_star_count_1', \true);
        // Backward compatibility: If meta doesn't exist, calculate it now.
        if ($check === '' || $check === \false) {
            \Rvx\CPT\CptAverageRating::update_average_rating($post_id);
        }
        return ["one" => (int) \get_post_meta($post_id, 'rvx_star_count_1', \true), "two" => (int) \get_post_meta($post_id, 'rvx_star_count_2', \true), "three" => (int) \get_post_meta($post_id, 'rvx_star_count_3', \true), "four" => (int) \get_post_meta($post_id, 'rvx_star_count_4', \true), "five" => (int) \get_post_meta($post_id, 'rvx_star_count_5', \true)];
    }
    private function enableCommentsReviews($post_id)
    {
        global $wpdb;
        // Validate post ID
        $post = get_post($post_id);
        if (!$post) {
            return \false;
        }
        // Ensure the post type supports comments
        $post_type = $post->post_type;
        $supports = post_type_supports($post_type, 'comments');
        if (!$supports) {
            // Dynamically add comment support for the post type
            add_post_type_support($post_type, 'comments');
        }
        // Update the comment status in the database
        $updated = $wpdb->update(
            $wpdb->posts,
            ['comment_status' => 'open'],
            // Enable comments
            ['ID' => $post_id],
            // Match post ID
            ['%s'],
            // Data format for `comment_status`
            ['%d']
        );
        if ($updated === \false) {
            return \false;
        }
        // Clear WordPress cache for this post
        clean_post_cache($post_id);
        return \true;
    }
    private function getReviewCount($post_id)
    {
        $count = \get_post_meta($post_id, 'rvx_total_reviews', \true);
        // Backward compatibility: If meta doesn't exist, calculate it now.
        if ($count === '' || $count === \false) {
            \Rvx\CPT\CptAverageRating::update_average_rating($post_id);
            $count = \get_post_meta($post_id, 'rvx_total_reviews', \true);
        }
        return (int) $count;
    }
    private function getAverageRating($post_id)
    {
        $rating = \get_post_meta($post_id, 'rvx_avg_rating', \true);
        // Backward compatibility: If meta doesn't exist, calculate it now.
        if ($rating === '' || $rating === \false) {
            \Rvx\CPT\CptAverageRating::update_average_rating($post_id);
            $rating = \get_post_meta($post_id, 'rvx_avg_rating', \true);
        }
        return (float) ($rating ?: 0.0);
    }
}
PK     ,]
i    #  CommentsReviewsRowActionRemover.phpnu         <?php

namespace Rvx\CPT\Shared;

use Rvx\CPT\CptHelper;
class CommentsReviewsRowActionRemover
{
    protected $cptHelper;
    public function __construct()
    {
        $this->cptHelper = new CptHelper();
    }
    /**
     * Remove specific row actions from comments and reviews based on the post type and comment type.
     *
     * @param array      $actions The array of actions for the comment row.
     * @param WP_Comment $comment The comment object.
     * @return array The modified actions array.
     */
    public function removeCommentsReviewsRowActions($actions, $comment)
    {
        // List of post types to target (include product)
        $enabled_post_types = $this->cptHelper->enabledCPT();
        // Get the post type of the comment
        $post_type = get_post_type($comment->comment_post_ID);
        // Get the comment type (WooCommerce product reviews have a type 'review')
        $comment_type = $comment->comment_type;
        // List of actions to remove
        $actions_to_remove = ['reply', 'quickedit', 'edit'];
        // If the post type matches and the comment type is 'comment' or 'review', remove the specified actions
        if (\in_array($post_type, $enabled_post_types, \true) && \in_array($comment_type, ['comment', 'review'], \true)) {
            foreach ($actions_to_remove as $action) {
                if (isset($actions[$action])) {
                    unset($actions[$action]);
                }
            }
        }
        return $actions;
    }
}
PK     ,][V	  	    CommentsReviewsFilter.phpnu         <?php

namespace Rvx\CPT\Shared;

use Rvx\CPT\CptHelper;
use Rvx\Utilities\Auth\Client;
/**
 * Filters comments/reviews from the WP Comments admin page for post types
 * that are enabled in ReviewX.
 */
class CommentsReviewsFilter
{
    protected $cptHelper;
    public function __construct()
    {
        $this->cptHelper = new CptHelper();
    }
    /**
     * Filter comments query to exclude comments for ReviewX-enabled post types.
     * This hides reviews/comments from the WP Comments admin page.
     *
     * @param WP_Comment_Query $query The comment query object.
     */
    public function filterCommentsForReviewxPostTypes($query)
    {
        // Only execute after sync is completed
        if (!Client::getSync()) {
            return;
        }
        // Only filter on the admin comments page
        if (!is_admin()) {
            return;
        }
        // Check if we're on the comments admin page
        global $pagenow;
        if ($pagenow !== 'edit-comments.php') {
            return;
        }
        // Get enabled post types from ReviewX
        $enabled_post_types = $this->cptHelper->enabledCPT();
        if (empty($enabled_post_types)) {
            return;
        }
        // Get all post IDs that belong to enabled post types
        $post_ids_to_exclude = $this->getPostIdsForPostTypes($enabled_post_types);
        if (empty($post_ids_to_exclude)) {
            return;
        }
        // Get current post__not_in value and merge with our exclusions
        $current_post_not_in = $query->query_vars['post__not_in'] ?? [];
        if (!\is_array($current_post_not_in)) {
            $current_post_not_in = [];
        }
        $query->query_vars['post__not_in'] = \array_merge($current_post_not_in, $post_ids_to_exclude);
    }
    /**
     * Get all post IDs for the given post types.
     *
     * @param array $post_types Array of post type slugs.
     * @return array Array of post IDs.
     */
    protected function getPostIdsForPostTypes($post_types)
    {
        global $wpdb;
        if (empty($post_types)) {
            return [];
        }
        // Build placeholders for IN clause
        $placeholders = \implode(', ', \array_fill(0, \count($post_types), '%s'));
        // Prepare query to get post IDs for the enabled post types
        $query = $wpdb->prepare("SELECT ID FROM {$wpdb->posts} WHERE post_type IN ({$placeholders})", \array_values($post_types));
        $post_ids = $wpdb->get_col($query);
        return \array_map('intval', $post_ids);
    }
}
PK     ,]ڣ      PostsRatingColumn.phpnu         <?php

namespace Rvx\CPT\Shared;

use Rvx\CPT\CptHelper;
class PostsRatingColumn
{
    protected $cptHelper;
    public function __construct()
    {
        $this->cptHelper = new CptHelper();
    }
    public function addColumn()
    {
        $enabled_post_types = $this->cptHelper->enabledCPT();
        // Loop through each post type and hook into the actions/filters dynamically
        foreach ($enabled_post_types as $post_type) {
            // Hook into the columns filter for each post type
            add_filter("manage_edit-{$post_type}_columns", function ($columns) use($post_type) {
                return $this->addRatingColumn($columns, $post_type);
            });
            add_action("manage_{$post_type}_posts_custom_column", [$this, 'populateRatingColumn'], 10, 2);
            // if($post_type !== 'product'){
            //     add_filter("manage_edit-{$post_type}_sortable_columns", [$this, 'makeRatingColumnSortable']);
            //     add_action('pre_get_posts', [$this, 'sortPostsByRating']);
            // }
        }
    }
    /**
     * Add a new column to the post type list for the review rating.
     *
     * @param array $columns The existing post columns.
     * @return array Modified columns array.
     */
    public function addRatingColumn($columns, $post_type)
    {
        // For 'product' post type, add rating column after the title column
        if ($post_type === 'product') {
            // Find the position of the 'author' column
            $price_position = \array_search('price', \array_keys($columns));
            // Insert the 'rating' column after the 'price' column
            if ($price_position !== \false) {
                // Add the 'rating' column after the 'author' column
                $columns = \array_slice($columns, 0, $price_position + 1, \true) + ['rating' => __('ReviewX Rating', 'reviewx')] + \array_slice($columns, $price_position + 1, null, \true);
            }
        } else {
            // For other post types, find the position of the 'author' column
            $author_position = \array_search('author', \array_keys($columns));
            if ($author_position !== \false) {
                $columns = \array_slice($columns, 0, $author_position + 1, \true) + ['rating' => __('ReviewX Rating', 'reviewx')] + \array_slice($columns, $author_position + 1, null, \true);
            }
        }
        return $columns;
    }
    /**
     * Populate the rating column with the post's rating.
     *
     * @param string $column The column name.
     * @param int    $post_id The ID of the post.
     */
    public function populateRatingColumn($column, $post_id)
    {
        if ($column === 'rating') {
            $post_type = get_post_type($post_id);
            $meta_key = 'product' === $post_type ? '_wc_average_rating' : 'rvx_avg_rating';
            $rating = \get_post_meta($post_id, $meta_key, \true);
            echo $this->getStarsHtml($rating ? $rating : 0);
            // Default to 0 if no rating
        }
    }
    /**
     * Generate the HTML for the stars based on the rating value.
     *
     * @param int $rating The rating value (1-5).
     * @return string The HTML output for the stars.
     */
    public function getStarsHtml($rating)
    {
        $rating = \max(0, \min(5, $rating));
        // Ensure the rating is between 0 and 5
        $star_size = '22px';
        // Customize size if needed
        $stars = '';
        for ($i = 1; $i <= 5; $i++) {
            if ($rating >= $i) {
                // Full star
                $star_symbol = '<span class="dashicons dashicons-star-filled"></span>';
            } elseif ($rating >= $i - 0.5) {
                // Half star
                $star_symbol = '<span class="dashicons dashicons-star-half"></span>';
            } else {
                // Empty star
                $star_symbol = '<span class="dashicons dashicons-star-empty"></span>';
            }
            $stars .= $star_symbol;
        }
        return "<span class='rvx-stars' title='{$rating}' style='font-size: {$star_size}; color: #f5a623;'>{$stars}</span>";
    }
    /**
     * Make the rating column sortable.
     *
     * @param array $columns The existing sortable columns.
     * @return array Modified sortable columns array.
     */
    public function makeRatingColumnSortable($columns)
    {
        $columns['rating'] = 'rating';
        return $columns;
    }
    /**
     * Sort posts by the rating column.
     *
     * @param WP_Query $query The WP_Query object.
     */
    public function sortPostsByRating($query)
    {
        if (is_admin() && isset($_GET['orderby']) && 'rating' === $_GET['orderby']) {
            $order = isset($_GET['order']) && $_GET['order'] === 'asc' ? 'ASC' : 'DESC';
            $meta_key = get_post_type() === 'product' ? '_wc_average_rating' : 'rvx_avg_rating';
            $query->set('meta_key', $meta_key);
            $query->set('orderby', 'meta_value_num');
            $query->set('order', $order);
        }
    }
}
PK     ,]vld    !  CommentsReviewsMetaBoxRemover.phpnu         <?php

namespace Rvx\CPT\Shared;

use Rvx\CPT\CptHelper;
class CommentsReviewsMetaBoxRemover
{
    protected $cptHelper;
    public function __construct()
    {
        $this->cptHelper = new CptHelper();
    }
    /**
     * Removes the comments meta box from all custom post types and WooCommerce products.
     */
    public function removeCommentsReviewsMetaBox()
    {
        $enabled_post_types = $this->cptHelper->enabledCPT();
        foreach ($enabled_post_types as $post_type) {
            // Remove the "Allow Comments" meta box
            remove_meta_box('commentstatusdiv', $post_type, 'normal');
            remove_meta_box('commentstatusdiv', $post_type, 'side');
            // Remove the "Comments" meta box displaying existing comments
            remove_meta_box('commentsdiv', $post_type, 'normal');
            remove_meta_box('commentsdiv', $post_type, 'side');
        }
    }
}
PK     ,]~        CommentEditBlockHandler.phpnu         <?php

namespace Rvx\CPT\Shared;

use Rvx\CPT\CptHelper;
use Rvx\Utilities\Auth\Client;
/**
 * Blocks editing of comments/reviews for post types that are managed by ReviewX.
 * This applies to both WP Comment Edit page and WooCommerce Review Edit page.
 */
class CommentEditBlockHandler
{
    protected $cptHelper;
    public function __construct()
    {
        $this->cptHelper = new CptHelper();
    }
    /**
     * Check if we should block comment editing.
     *
     * @return bool
     */
    public function shouldBlockEdit() : bool
    {
        // Get enabled post types from ReviewX
        $enabled_post_types = $this->cptHelper->enabledCPT();
        if (empty($enabled_post_types)) {
            return \false;
        }
        return \true;
    }
    /**
     * Check if we're on the comment edit page.
     *
     * @return bool
     */
    public function isCommentEditPage() : bool
    {
        global $pagenow;
        // WP Comment Edit page: comment.php?action=editcomment&c={id}
        if ($pagenow === 'comment.php') {
            $action = isset($_GET['action']) ? sanitize_text_field($_GET['action']) : '';
            return $action === 'editcomment';
        }
        return \false;
    }
    /**
     * Get the comment being edited.
     *
     * @return \WP_Comment|null
     */
    public function getEditingComment() : ?\WP_Comment
    {
        if (!$this->isCommentEditPage()) {
            return null;
        }
        $comment_id = isset($_GET['c']) ? absint($_GET['c']) : 0;
        if (!$comment_id) {
            return null;
        }
        return get_comment($comment_id);
    }
    /**
     * Check if the comment belongs to a ReviewX-enabled post type.
     *
     * @param \WP_Comment $comment The comment object.
     * @return bool
     */
    public function isReviewxEnabledComment($comment) : bool
    {
        if (!$comment || !$comment->comment_post_ID) {
            return \false;
        }
        $post_type = get_post_type($comment->comment_post_ID);
        $enabled_post_types = $this->cptHelper->enabledCPT();
        return isset($enabled_post_types[$post_type]);
    }
    /**
     * Display a notice on the comment edit page that editing is blocked.
     */
    public function displayEditBlockedNotice() : void
    {
        if (!is_admin()) {
            return;
        }
        if (!$this->shouldBlockEdit()) {
            return;
        }
        if (!$this->isCommentEditPage()) {
            return;
        }
        $comment = $this->getEditingComment();
        if (!$comment || !$this->isReviewxEnabledComment($comment)) {
            return;
        }
        $reviewx_reviews_url = admin_url('admin.php?page=reviewx_reviews');
        $post_type = get_post_type($comment->comment_post_ID);
        $post_type_label = \ucfirst($post_type);
        // Use admin_footer to inject HTML that won't be affected by page load scripts
        add_action('admin_footer', function () use($reviewx_reviews_url, $post_type_label) {
            ?>
            <style>
                /* Position the content area as relative for absolute positioning */
                #wpbody-content {
                    position: relative !important;
                }
                /* Overlay covers only the content area */
                #rvx-edit-blocked-overlay {
                    position: absolute !important;
                    top: 0 !important;
                    left: 0 !important;
                    right: 0 !important;
                    bottom: 0 !important;
                    min-height: 100vh;
                    background: rgba(255,255,255,0.98) !important;
                    z-index: 99 !important;
                    display: flex !important;
                    align-items: center !important;
                    justify-content: center !important;
                    visibility: visible !important;
                    opacity: 1 !important;
                }
            </style>
            <script>
                document.addEventListener('DOMContentLoaded', function() {
                    var container = document.getElementById('wpbody-content');
                    if (!container) return;
                    
                    var overlay = document.createElement('div');
                    overlay.id = 'rvx-edit-blocked-overlay';
                    overlay.innerHTML = `
                        <div style="
                            background: #fff;
                            border: 1px solid #c3c4c7;
                            border-left: 4px solid #f59e0b;
                            padding: 30px 40px;
                            max-width: 500px;
                            box-shadow: 0 4px 20px rgba(0,0,0,0.15);
                            border-radius: 4px;
                            text-align: center;
                        ">
                            <span class="dashicons dashicons-lock" style="font-size: 48px; color: #f59e0b; margin-bottom: 15px; display: block;"></span>
                            <h2 style="margin: 0 0 15px 0; color: #1e293b; font-size: 20px;">
                                <?php 
            esc_html_e('Review Editing Disabled', 'reviewx');
            ?>
                            </h2>
                            <p style="font-size: 14px; color: #475569; margin: 0 0 20px 0; line-height: 1.6;">
                                <?php 
            \printf(esc_html__('This %s review is managed by ReviewX. To edit this review, please use the ReviewX Reviews page.', 'reviewx'), esc_html($post_type_label));
            ?>
                            </p>
                            <a href="<?php 
            echo esc_url($reviewx_reviews_url);
            ?>" class="button button-primary button-hero" style="background-color: #6366f1; border-color: #6366f1; font-size: 14px;">
                                <?php 
            esc_html_e('Go to ReviewX Reviews', 'reviewx');
            ?>
                            </a>
                            <br><br>
                            <a href="<?php 
            echo esc_url(admin_url('edit-comments.php'));
            ?>" style="color: #666; font-size: 13px; text-decoration: none;">
                                <?php 
            esc_html_e('← Back to Comments', 'reviewx');
            ?>
                            </a>
                        </div>
                    `;
                    container.appendChild(overlay);
                });
            </script>
            <?php 
        });
    }
    /**
     * Redirect to ReviewX reviews page if trying to edit a ReviewX-managed comment.
     * This is an alternative approach using JavaScript for better UX.
     */
    public function maybeRedirectFromEditPage() : void
    {
        if (!is_admin()) {
            return;
        }
        if (!$this->shouldBlockEdit()) {
            return;
        }
        if (!$this->isCommentEditPage()) {
            return;
        }
        $comment = $this->getEditingComment();
        if (!$comment || !$this->isReviewxEnabledComment($comment)) {
            return;
        }
        // Add inline script to disable form submission
        add_action('admin_footer', function () {
            ?>
            <script>
                document.addEventListener('DOMContentLoaded', function() {
                    // Disable all form submissions on this page
                    var forms = document.querySelectorAll('form');
                    forms.forEach(function(form) {
                        form.addEventListener('submit', function(e) {
                            e.preventDefault();
                            alert('<?php 
            esc_html_e('This review is managed by ReviewX. Please edit it from the ReviewX Reviews page.', 'reviewx');
            ?>');
                            return false;
                        });
                    });
                    
                    // Disable submit buttons
                    var submitButtons = document.querySelectorAll('input[type="submit"], button[type="submit"]');
                    submitButtons.forEach(function(btn) {
                        btn.disabled = true;
                        btn.style.opacity = '0.5';
                        btn.style.cursor = 'not-allowed';
                    });
                });
            </script>
            <?php 
        });
    }
}
PK     ,]S  S    WooReviewsRedirectHandler.phpnu         <?php

namespace Rvx\CPT\Shared;

use Rvx\CPT\CptHelper;
use Rvx\Utilities\Auth\Client;
/**
 * Handles WooCommerce Reviews page redirection notice and hides reviews
 * when product post type is managed by ReviewX.
 */
class WooReviewsRedirectHandler
{
    protected $cptHelper;
    public function __construct()
    {
        $this->cptHelper = new CptHelper();
    }
    /**
     * Check if WooCommerce product reviews should be hidden.
     *
     * @return bool
     */
    public function shouldHideWooReviews() : bool
    {
        // Check if WooCommerce is active
        if (!\class_exists('WooCommerce')) {
            return \false;
        }
        // Check if sync is completed
        if (!Client::getSync()) {
            return \false;
        }
        // Check if product post type is enabled in ReviewX
        $enabled_post_types = $this->cptHelper->enabledCPT();
        return isset($enabled_post_types['product']);
    }
    /**
     * Check if we're on the WooCommerce Reviews page.
     * WooCommerce Reviews page: edit.php?post_type=product&page=product-reviews
     * Legacy Comments page: edit-comments.php?post_type=product or edit-comments.php?comment_type=review
     *
     * @return bool
     */
    public function isWooReviewsPage() : bool
    {
        global $pagenow;
        // Check for WooCommerce product-reviews page (Products -> Reviews)
        // URL: edit.php?post_type=product&page=product-reviews
        if ($pagenow === 'edit.php') {
            $post_type = isset($_GET['post_type']) ? sanitize_text_field($_GET['post_type']) : '';
            $page = isset($_GET['page']) ? sanitize_text_field($_GET['page']) : '';
            if ($post_type === 'product' && $page === 'product-reviews') {
                return \true;
            }
        }
        // Also check legacy edit-comments.php page
        if ($pagenow === 'edit-comments.php') {
            $post_type = isset($_GET['post_type']) ? sanitize_text_field($_GET['post_type']) : '';
            $comment_type = isset($_GET['comment_type']) ? sanitize_text_field($_GET['comment_type']) : '';
            if ($post_type === 'product' || $comment_type === 'review') {
                return \true;
            }
        }
        return \false;
    }
    /**
     * Display a notice on the WooCommerce Reviews page redirecting users to ReviewX.
     */
    public function displayRedirectNotice() : void
    {
        if (!is_admin()) {
            return;
        }
        if (!$this->shouldHideWooReviews()) {
            return;
        }
        if (!$this->isWooReviewsPage()) {
            return;
        }
        $reviewx_reviews_url = admin_url('admin.php?page=reviewx_reviews');
        ?>
        <div class="notice notice-info" style="padding: 15px; margin: 20px 0; border-left-color: #6366f1;">
            <h3 style="margin: 0 0 10px 0; color: #1e293b;">
                <span class="dashicons dashicons-star-filled" style="color: #6366f1; margin-right: 5px;"></span>
                <?php 
        esc_html_e('Reviews Managed by ReviewX', 'reviewx');
        ?>
            </h3>
            <p style="font-size: 14px; color: #475569; margin: 0 0 15px 0;">
                <?php 
        esc_html_e('Product reviews are now managed by ReviewX. You can view, manage, and respond to all product reviews from the ReviewX Reviews page.', 'reviewx');
        ?>
            </p>
            <a href="<?php 
        echo esc_url($reviewx_reviews_url);
        ?>" class="button button-primary" style="background-color: #6366f1; border-color: #6366f1;">
                <span class="dashicons dashicons-arrow-right-alt" style="margin-top: 4px;"></span>
                <?php 
        esc_html_e('Go to ReviewX Reviews', 'reviewx');
        ?>
            </a>
        </div>
        <style>
            /* Hide the reviews table when ReviewX is managing reviews */
            .wp-list-table.comments,
            .wp-list-table.reviews,
            .tablenav,
            .subsubsub,
            .search-box,
            #comments-form > p:first-child,
            .woocommerce-reviews-table,
            .wc-admin-review-activity-card,
            #the-comment-list,
            .comment-ays,
            form#comments-form {
                display: none !important;
            }
        </style>
        <?php 
    }
    /**
     * Filter WooCommerce product reviews from the comments query using comments_clauses.
     * This is the proper WordPress filter for modifying comment queries.
     *
     * @param array             $clauses       A compacted array of comment query clauses.
     * @param \WP_Comment_Query $comment_query The WP_Comment_Query instance.
     * @return array Modified clauses array.
     */
    public function filterWooReviewsClauses($clauses, $comment_query) : array
    {
        if (!is_admin()) {
            return $clauses;
        }
        if (!$this->shouldHideWooReviews()) {
            return $clauses;
        }
        if (!$this->isWooReviewsPage()) {
            return $clauses;
        }
        // Return no results by adding an impossible WHERE condition
        $clauses['where'] .= ' AND 1=0 ';
        return $clauses;
    }
}
PK       ,]'k( 3   3                  CptPostHandler.phpnu         PK       ,]
i    #            b3  CommentsReviewsRowActionRemover.phpnu         PK       ,][V	  	              9  CommentsReviewsFilter.phpnu         PK       ,]ڣ                C  PostsRatingColumn.phpnu         PK       ,]vld    !            W  CommentsReviewsMetaBoxRemover.phpnu         PK       ,]~                  [  CommentEditBlockHandler.phpnu         PK       ,]S  S              |  WooReviewsRedirectHandler.phpnu         PK      |  _ 