Intereting Posts
Связать изображения, чтобы опубликовать постоянную ссылку – настраиваемые типы сообщений Как добавить пользовательский виджет выше admin_footer Как я могу отображать пользовательские столбцы пользовательского столбца и его содержимое в виджетах панели мониторинга? Пункт главного меню для нескольких плагинов? Hang Up Followed Не удается выбрать базу данных Неопределенное смещение & Неопределенное свойство | Не удалось правильно настроить мои колпачки Любые советы по настройке этого твиттера? Вставить избранное изображение из фида Как вы можете обернуть add_filter с помощью инструкции if_home ()? Можно ли получить все сообщения с определенным значением для метаданных? Ограничить поиск латинскими символами Есть ли сверху вниз документация для WordPress? Показать предыдущие и следующие сообщения для родительского сообщения текущего изображения на странице вложений? Count foreach и отображение в меню php Скрыть часть шаблона, когда страница защищена паролем?

Как создать гибкую абстракцию для WP_Query?

Мой вопрос касается php, но он включает wordpress, поскольку я создаю плагин. Дело в том, что у меня есть 5 вопросов, каждый вопрос имеет 6 вариантов и один выбор для выбора. Теперь человек выбирает любой выбор от каждого или только от нескольких. Я создал условие if, которое сейчас делает меня сумасшедшим, поскольку оно зашло слишком долго и будет делать дальше, например, будет сделано почти 100 комбинаций. Я бы этого не хотел, я знаю, что существует способ многомерного массива, но я не являюсь плагином или экспертом php для wordpress. поэтому, если кто-то может сортировать его для меня.

$qs = $_POST['q1']; $q2 = $_POST['q2']; $q3 = $_POST['q3']; $q4 = $_POST['q4']; $q5 = $_POST['q5']; $q6 = $_POST['q6']; $args = array( 'post_type' => 'product', 'posts_per_page' => -1, 'tax_query' => array( 'relation' => 'AND', array( 'taxonomy' => 'product_cat', 'field' => 'slug', 'terms' => 'fashion-follower' ), // array( // 'taxonomy' => 'product_cat', // 'field' => 'slug', // 'terms' => 'cheap-and-cheerful' // ) ) ); //The Fashionsia if (($qs ==='party') && ($q2 === 'clothes') && ($q3 === 'shopping') && ($q5 === 'Sunbathing') && ($q6 === 'mini')){ $query = new WP_Query( $args ); if( $query->have_posts()) : while( $query->have_posts() ) : $query->the_post(); the_post_thumbnail('thumbnail'); endwhile; endif; } //second question loop $args2 = array( 'post_type' => 'product', 'posts_per_page' => -1, 'tax_query' => array( 'relation' => 'AND', array( 'taxonomy' => 'product_cat', 'field' => 'slug', 'terms' => 'the-homemaker' ), // array( // 'taxonomy' => 'product_cat', // 'field' => 'slug', // 'terms' => 'cheap-and-cheerful' // ) ) ); //The homemaker if (($qs ==='drink') && ($q2 === 'candles') && ($q3 === 'house') && ($q4 === 'diy')){ $query = new WP_Query( $args2 ); if( $query->have_posts()) : while( $query->have_posts() ) : $query->the_post(); the_post_thumbnail('thumbnail'); endwhile; endif; } //third loop $args3 = array( 'post_type' => 'product', 'posts_per_page' => -1, 'tax_query' => array( 'relation' => 'AND', array( 'taxonomy' => 'product_cat', 'field' => 'slug', 'terms' => 'entertainment' ), // array( // 'taxonomy' => 'product_cat', // 'field' => 'slug', // 'terms' => 'cheap-and-cheerful' // ) ) ); //The Entertainer if (($qs ==='party-babe') && ($q2 === 'winer')&& ($q4 === 'storm') && ($q6 === 'limo')){ $query = new WP_Query( $args3 ); if( $query->have_posts()) : while( $query->have_posts() ) : $query->the_post(); the_post_thumbnail('thumbnail'); endwhile; endif; } //fourth loop $args4 = array( 'post_type' => 'product', 'posts_per_page' => -1, 'tax_query' => array( 'relation' => 'AND', array( 'taxonomy' => 'product_cat', 'field' => 'slug', 'terms' => 'family-fanatic' ), // array( // 'taxonomy' => 'product_cat', // 'field' => 'slug', // 'terms' => 'cheap-and-cheerful' // ) ) ); //The family-fanatic if (($qs ==='movie') && ($q2 === 'kids')&& ($q6 === 'volvo')){ $query = new WP_Query( $args4 ); if( $query->have_posts()) : while( $query->have_posts() ) : $query->the_post(); the_post_thumbnail('thumbnail'); endwhile; endif; } //fifth loop //fourth loop $args4 = array( 'post_type' => 'product', 'posts_per_page' => -1, 'tax_query' => array( 'relation' => 'AND', array( 'taxonomy' => 'product_cat', 'field' => 'slug', 'terms' => 'family-fanatic' ), // array( // 'taxonomy' => 'product_cat', // 'field' => 'slug', // 'terms' => 'cheap-and-cheerful' // ) ) ); //The romantic if (($qs ==='Dinner-show') && ($q5 === 'cruiser')){ $query = new WP_Query( $args4 ); if( $query->have_posts()) : while( $query->have_posts() ) : $query->the_post(); the_post_thumbnail('thumbnail'); endwhile; endif; } 

Solutions Collecting From Web of "Как создать гибкую абстракцию для WP_Query?"

Ваш вопрос не о WordPress, это больше о PHP и рефакторинге. Но мы видим здесь очень плохой код, и шаблон, который я объясню ниже (MVC), может помочь многим другим разработчикам, поэтому я решил написать небольшой ответ. Имейте в виду, в нашей сети есть специальный сайт для таких вопросов: обзор кода . К сожалению, очень немногие разработчики WordPress там активны.


Как реорганизовать код

  1. Удалите ненужный код. Украсьте все остальное.
  2. Найдите все повторяющиеся выражения и создайте подпрограммы (функции или классы), чтобы их абстрагировать и инкапсулировать.
  3. Отдельная обработка данных, модель (сохранение, выборка, преобразование, интерпретация), выход, представление (HTML, CSV, что угодно).

1. Удалите ненужный код. Украсьте все остальное.

Выход

У вас есть этот повторяющийся фрагмент:

 if( $query->have_posts()) : while( $query->have_posts() ) : $query->the_post(); the_post_thumbnail('thumbnail'); endwhile; endif; 

Вы запускаете довольно дорогой the_post() каждый раз, чтобы получить миниатюру сообщения. Но это не нужно, вы можете просто позвонить:

 echo get_the_post_thumbnail( $post_id, 'post-thumbnail' ); 

Запрос

Итак, все, что вам нужно, это идентификатор сообщения, и это доступно без вызова the_post() . Еще лучше: вы можете ограничить запрос для получения только идентификаторов.

Простой пример:

 $post_ids = array(); $args = array( 'post_type' => 'post', 'posts_per_page' => 10, 'fields' => 'ids' ); $query = new WP_Query( $args ); if ( ! empty ( $query->posts ) ) $post_ids = $query->posts; // just the post IDs 

Теперь у вас есть идентификаторы, и вы можете написать:

 foreach ( $post_ids as $post_id ) echo get_the_post_thumbnail( $post_id, 'post-thumbnail' ); 

Нет накладных расходов, ваш код уже быстрее и легче читать.

Синтаксис

Обратите внимание, как я выровнял = ? Это помогает понять код, потому что человеческий ум специализируется на распознавании образов. Поддержите это, и мы можем сделать потрясающие вещи. Создайте беспорядок, и мы застряли очень быстро.

Это также причина, по которой я удалял endwhile и endif . Альтернативный синтаксис грязный и трудно читаемый. Кроме того, это делает работу в среде IDE намного сложнее: сгибание и прыжки с самого начала до конца выражения легче с помощью фигурных скобок.

Значения по умолчанию

В вашем массиве $args есть поля, которые вы используете везде. Создайте массив по умолчанию и напишите эти поля только один раз :

 $args = array( 'post_type' => 'product', 'posts_per_page' => 100, 'fields' => 'ids', 'tax_query' => array( array( 'taxonomy' => 'product_cat', 'field' => 'slug', ) ) ); 

Опять же, обратите внимание на выравнивание. Также обратите внимание, как я изменил значение posts_per_page . Никогда не спрашивайте -1 . Что происходит, когда есть один миллион подходящих сообщений? Вы не хотите убивать соединение с базой данных каждый раз, когда этот запрос запускается, не так ли? И кто должен читать все эти посты? Всегда устанавливайте разумный предел.

Теперь все, что вам нужно изменить, это поле $args[ 'tax_query' ][ 'terms' ] . Мы рассмотрим это через мгновение.

2. Найдите все повторяющиеся выражения и создайте подпрограммы

Мы уже очистили некоторый повторяющийся код, теперь сложная часть: оценка параметров POST. Очевидно, что вы сделали некоторые ярлыки в результате некоторых параметров. Я предлагаю переименовать их в нечто более понятное, но пока мы будем работать с вашей схемой именования.

Отделите эти группы от остальных, создайте массив, который вы можете управлять позже отдельно:

 $groups = array( 'fashion-follower' => array( 'q1' => 'party', 'q2' => 'clothes', 'q3' => 'shopping', 'q4' => FALSE, 'q5' => 'sunbathing', 'q6' => 'mini', ), 'the-homemaker' => array( 'q1' => 'drink', 'q2' => 'candles', 'q3' => 'house', 'q4' => 'diy', 'q5' => FALSE, 'q6' => FALSE, ) ); 

Чтобы заполнить поле отсутствующих terms в вашем массиве по умолчанию, вы запускаете массив $groups пока не найдете совпадение:

 function get_query_term( $groups ) { foreach ( $groups as $term => $values ) { if ( compare_group_values( $values ) ) return $term; } return FALSE; } function compare_group_values( $values ) { foreach ( $values as $key => $value ) { // Key not sent, but required if ( empty ( $_POST[ $key ] ) and ! empty ( $value ) ) return FALSE; // Key sent, but wrong value if ( ! empty ( $_POST[ $key ] ) and $_POST[ $key ] !== $value ) return FALSE; } // all keys matched the required values return TRUE; } 

Я разделил даже пробег через список терминов и сравнение значений, потому что это разные операции. Каждая часть вашего кода должна делать только одно, и вы должны поддерживать уровень отступов для лучшей читаемости.

Теперь у нас есть все части, давайте придерживаться их вместе.

3. Организация: отделите модель от вида

Когда я писал модель и представление , у меня было что-то в виду: подход MVC. Это означает Model View Controller , хорошо известный шаблон для организации программных компонентов. До сих пор отсутствующей частью был контроллер, мы увидим, как мы его используем позже.

Вы сказали, что вы мало знаете о PHP, поэтому я надеюсь, что вы знаете больше о выходе. 🙂 Начнем с того, что:

 class Thumbnail_List { protected $source; public function set_source( Post_Collector_Interface $source ) { $this->source = $source; } public function render() { $post_ids = $this->source->get_post_ids(); if ( empty ( $post_ids ) or ! is_array( $post_ids ) ) return print 'Nothing found'; foreach ( $post_ids as $post_id ) echo get_the_post_thumbnail( $post_id, 'post-thumbnail' ); } } 

Приятно и просто: у нас есть два метода: один для установки источника для наших идентификаторов сообщений, один для рендеринга эскизов.

Вы можете задаться вопросом, что такое Post_Collector_Interface . Мы добираемся до этого через мгновение.

Теперь источник нашего взгляда, модель.

 class Post_Collector implements Post_Collector_Interface { protected $groups = array(); public function set_groups( Array $groups ) { $this->groups = $groups; } public function get_post_ids() { $term = $this->get_query_term(); if ( ! $term ) return array(); return $this->query( $term ); } protected function query( $term ) { $args = array( 'post_type' => 'product', 'posts_per_page' => 100, 'fields' => 'ids', 'tax_query' => array( array( 'taxonomy' => 'product_cat', 'field' => 'slug', 'terms' => $term ) ) ); $query = new WP_Query( $args ); if ( empty ( $query->posts ) ) return array(); return $query->posts; } protected function get_query_term() { foreach ( $this->groups as $term => $values ) { if ( compare_group_values( $values ) ) return $term; } return FALSE; } protected function compare_group_values( $values ) { foreach ( $values as $key => $value ) { // Key not sent, but required if ( empty ( $_POST[ $key ] ) and ! empty ( $value ) ) return FALSE; // Kent sent, but wrong value if ( ! empty ( $_POST[ $key ] ) and $_POST[ $key ] !== $value ) return FALSE; } // all keys matched the required values return TRUE; } } 

Это уже не так тривиально, но у нас было больше всего частей. protected методы (функции) недоступны извне, потому что они нужны только для внутренней логики.

public методы просты: первый получает наш массив $group сверху, второй возвращает массив идентификаторов сообщений. И снова мы встретим этот сомнительный Post_Collector_Interface .

Интерфейс – это контракт . Он может быть подписан (реализован) по классам. Требование к интерфейсу, например, нашему классу Thumbnail_List , означает: класс ожидает какой-либо другой класс с этими общедоступными методами.

Давайте построим этот интерфейс. Это очень просто:

 interface Post_Collector_Interface { public function set_groups( Array $groups ); public function get_post_ids(); } 

Да, это все. Простой код, не так ли?

Что мы здесь сделали: мы сделали свое представление Thumbnail_List независимым от конкретного класса, в то время как мы все еще можем полагаться на методы класса, который мы получили как $source . Если позже вы передумаете, вы можете написать новый класс для получения идентификаторов сообщений или использовать один с фиксированными значениями. Пока вы реализуете интерфейс, представление будет выполнено. Вы можете даже проверить представление теперь с помощью макетного объекта:

 class Mock_Post_Collector implements Post_Collector_Interface { public function set_groups( Array $groups ) {} public function get_post_ids() { return array ( 1 ); } } 

Это очень полезно, если вы хотите протестировать представление. Вы не хотите тестировать оба конкретных класса вместе, потому что вы не увидите, откуда исходит ошибка. Макет объекта слишком прост для ошибок, идеально подходит для модульных тестов.

Теперь нам нужно как-то совместить наши классы. Здесь контроллер входит в стадию.

 class Thumbnail_Controller { protected $groups = array( 'fashion-follower' => array( 'q1' => 'party', 'q2' => 'clothes', 'q3' => 'shopping', 'q4' => FALSE, 'q5' => 'sunbathing', 'q6' => 'mini', ), 'the-homemaker' => array( 'q1' => 'drink', 'q2' => 'candles', 'q3' => 'house', 'q4' => 'diy', 'q5' => FALSE, 'q6' => FALSE, ) ); public function __construct() { // not a post request if ( 'POST' !== $_SERVER[ 'REQUEST_METHOD' ] ) return; // set up the model $model = new Post_Collector; $model->set_groups( $this->groups ); // prepare the view $view = new Thumbnail_List; $view->set_source( $model ); // finally render the tumbnails $view->render(); } } 

Контроллер является единственной настоящей уникальной частью приложения; модель и вид могут быть повторно использованы здесь и там даже в совершенно разных частях. Но контроллер существует только для этой единственной цели, поэтому мы помещаем здесь $group .

И теперь вам нужно сделать только одно:

 // Let the dogs out! new Thumbnail_Controller; 

Вызывайте эту строку везде, где вам нужен выход.

Вы можете найти весь код из этого ответа в этом вопросе на GitHub .