Ваш вопрос на самом деле не о WordPress, а о PHP и рефакторинге. Но мы видим здесь очень много плохого кода, и шаблон, который я объясню ниже (MVC), может помочь многим другим разработчикам, поэтому я решил написать небольшой ответ. Имейте в виду, что в нашей сети есть специальный сайт для таких вопросов: Code Review . К сожалению, очень немногие разработчики WordPress работают там.
Как изменить код
- Удалить бесполезный код. Украсить остальное.
- Найдите все повторяющиеся выражения и создайте процедуры (функции или классы) для их абстрагирования и инкапсуляции.
- Отдельная обработка данных, модель (хранение, выборка, преобразование, интерпретация), вывод, представление (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;
Называйте эту линию там, где вам нужен выход.
Вы можете найти весь код из этого ответа в GistHub .