Как переопределить класс в WP?

Ссылка скопирована
1 ответ

У меня есть класс плагина WooCommerce : AutomatticWooCommerceInternalAdminProductReviewsReviewsListTable
wp-content/plugins/woocommerce/src/Internal/Admin/ProductReviews/ReviewsListTable.php

У него есть 2 метода
prepare_items - отображает в админке айтемы ревью
get_review_count - и возвращает их количество

Для метода prepare_items я написал функцию которая добавляет фильтр по моему кастомному мета-полю

add_filter( 'woocommerce_product_reviews_list_table_prepare_items_args', 'structured_data_modify_product_reviews_query' );  function structured_data_modify_product_reviews_query($args) {     return wp_parse_args(get_filter_api_review_id_arguments(), $args); }  function get_filter_api_review_id_arguments() {     $args = [];     $args['meta_query'] = [         [             'key' => 'custom_field',             'compare' => 'NOT EXISTS',         ],     ];     return $args; }

add_filter( 'woocommerce_product_reviews_list_table_prepare_items_args', 'structured_data_modify_product_reviews_query' ); function structured_data_modify_product_reviews_query($args) { return wp_parse_args(get_filter_api_review_id_arguments(), $args); } function get_filter_api_review_id_arguments() { $args = []; $args['meta_query'] = [ [ 'key' => 'custom_field', 'compare' => 'NOT EXISTS', ], ]; return $args; }

Теперь мне надо добавить этот фильтр и для метода get_review_count (чтобы возвращало правильное количество ревью), но сложность в том что у этого метода нет хука, и не совсем понимаю как можно изменить поведение этого метода не меня core файлы плагина

Дополнительные вопросы

nikitoshq @nikitoshq Автор вопроса Если кому-то интересно, то пофиксил так, не самый хороший подход, но все же:

class Structured_Data_List_Table extends ReviewsListTable {      protected function get_review_count(string $status, int $product_id): int     {         $args = [             'type__in' => ['review', 'comment'],             'status' => $this->convert_status_to_query_value($status),             'post_type' => 'product',             'post_id' => $product_id,             'count' => true,         ];          $args['meta_query'] = [             [                 'key' => 'custom_field',                 'compare' => 'NOT EXISTS',             ],         ];         return (int)get_comments($args);     } }  add_filter( 'woocommerce_product_reviews_list_table', 'replace_reviews_list_table_class', 10, 2 );  function replace_reviews_list_table_class( $output, $reviews_list_table ) {     $structured_data_list_table = new Structured_Data_List_Table();     $structured_data_list_table->prepare_items();     ob_start();     ?>     <div class="wrap">         <h2><?php echo esc_html( get_admin_page_title() ); ?></h2>         <?php $structured_data_list_table->views(); ?>         <form id="reviews-filter" method="get">             <?php $page = isset( $_REQUEST['page'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ) : 'product-reviews'; ?>             <input type="hidden" name="page" value="<?php echo esc_attr( $page ); ?>" />             <input type="hidden" name="post_type" value="product" />             <input type="hidden" name="pagegen_timestamp" value="<?php echo esc_attr( current_time( 'mysql', true ) ); ?>" />             <?php $structured_data_list_table->search_box( __( 'Search Reviews', 'woocommerce' ), 'reviews' ); ?>             <?php $structured_data_list_table->display(); ?>         </form>     </div>     <?php     return ob_get_clean(); }

class Structured_Data_List_Table extends ReviewsListTable { protected function get_review_count(string $status, int $product_id): int { $args = [ 'type__in' => ['review', 'comment'], 'status' => $this->convert_status_to_query_value($status), 'post_type' => 'product', 'post_id' => $product_id, 'count' => true, ]; $args['meta_query'] = [ [ 'key' => 'custom_field', 'compare' => 'NOT EXISTS', ], ]; return (int)get_comments($args); } } add_filter( 'woocommerce_product_reviews_list_table', 'replace_reviews_list_table_class', 10, 2 ); function replace_reviews_list_table_class( $output, $reviews_list_table ) { $structured_data_list_table = new Structured_Data_List_Table(); $structured_data_list_table->prepare_items(); ob_start(); ?> <div class="wrap"> <h2><?php echo esc_html( get_admin_page_title() ); ?></h2> <?php $structured_data_list_table->views(); ?> <form id="reviews-filter" method="get"> <?php $page = isset( $_REQUEST['page'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ) : 'product-reviews'; ?> <input type="hidden" name="page" value="<?php echo esc_attr( $page ); ?>" /> <input type="hidden" name="post_type" value="product" /> <input type="hidden" name="pagegen_timestamp" value="<?php echo esc_attr( current_time( 'mysql', true ) ); ?>" /> <?php $structured_data_list_table->search_box( __( 'Search Reviews', 'woocommerce' ), 'reviews' ); ?> <?php $structured_data_list_table->display(); ?> </form> </div> <?php return ob_get_clean(); }

Ответы:

Наследованием и переопределением?

class My_ReviewsListTable extends AutomatticWooCommerceInternalAdminProductReviewsReviewsListTable {     public function get_review_count($product_id) {         $args = [             'post_type' => 'product_review',             'post_status' => 'publish',             'meta_query' => [                 [                     'key' => 'custom_field',                     'compare' => 'NOT EXISTS',                 ],             ],             'fields' => 'ids',         ];           if($product_id) {             $args['meta_query'][] = [                 'key' => '_product_id',                 'value' => $product_id,                 'compare' => '=',             ];         }          $query = new WP_Query($args);         return $query->found_posts;     } }

class My_ReviewsListTable extends AutomatticWooCommerceInternalAdminProductReviewsReviewsListTable { public function get_review_count($product_id) { $args = [ 'post_type' => 'product_review', 'post_status' => 'publish', 'meta_query' => [ [ 'key' => 'custom_field', 'compare' => 'NOT EXISTS', ], ], 'fields' => 'ids', ]; if($product_id) { $args['meta_query'][] = [ 'key' => '_product_id', 'value' => $product_id, 'compare' => '=', ]; } $query = new WP_Query($args); return $query->found_posts; } }

  • Как отнаследоваться я понимаю) Я не понимаю как потом подменить core класс на свой
    Для мадженты есть di.xml файл для этих целей, там пишешь какой на какой класс подменяется, а как в WP я не понимаю :(
Нужно решить такую задачу?

Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.

Заказать помощь
Лучший ответ
1
Дмитрий К. Ответ

Переопределять внутренний класс WooCommerce напрямую нельзя нормальным способом: если вы объявите класс с тем же именем, PHP получит конфликт, а если измените файл плагина, правка пропадёт при обновлении. В вашем случае класс AutomatticWooCommerceInternalAdminProductReviewsReviewsListTable относится к внутренней админской части WooCommerce, поэтому самый безопасный путь — искать hook/filter вокруг нужного запроса или подменять поведение на уровне доступных фильтров.

Для задачи «добавить фильтр по кастомному meta-полю в список отзывов» я бы действовал так:

  1. Сначала найти, каким запросом WooCommerce получает reviews.
  2. Проверить, есть ли фильтры в методе prepare_items или около него.
  3. Если фильтра нет, проверить, можно ли повлиять на WP_Comment_Query через pre_get_comments.
  4. Если это экран админки, ограничить код только нужной страницей, чтобы не ломать комментарии по всему сайту.

Пример общей идеи через pre_get_comments:

add_action('pre_get_comments', function ($query) {
    if (! is_admin()) {
        return;
    }
 
    $screen = function_exists('get_current_screen') ? get_current_screen() : null;
    if (! $screen || strpos($screen->id, 'product') === false) {
        return;
    }
 
    if (empty($_GET['my_review_filter'])) {
        return;
    }
 
    $meta_query = (array) $query->query_vars['meta_query'];
    $meta_query[] = [
        'key'   => 'my_custom_meta',
        'value' => sanitize_text_field(wp_unslash($_GET['my_review_filter'])),
    ];
 
    $query->query_vars['meta_query'] = $meta_query;
});

add_action('pre_get_comments', function ($query) { if (! is_admin()) { return; } $screen = function_exists('get_current_screen') ? get_current_screen() : null; if (! $screen || strpos($screen->id, 'product') === false) { return; } if (empty($_GET['my_review_filter'])) { return; } $meta_query = (array) $query->query_vars['meta_query']; $meta_query[] = [ 'key' => 'my_custom_meta', 'value' => sanitize_text_field(wp_unslash($_GET['my_review_filter'])), ]; $query->query_vars['meta_query'] = $meta_query; });

Это не универсальный готовый код под ваш экран, а направление: не наследовать внутренний класс, а вмешаться в запрос там, где WordPress ещё позволяет это сделать без форка WooCommerce.

Если всё-таки нужно полностью изменить таблицу, нормальный вариант — сделать собственную админскую страницу со своей WP_List_Table, а не пытаться заменить внутренний класс WooCommerce. Внутренние классы WooCommerce могут меняться между версиями, поэтому жёсткая подмена быстро станет нестабильной.

Другие ответы (0)

Пока нет других ответов. Будьте первым, кто поможет автору.

Ответить на вопрос

комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Вам также может быть интересно