Разработка поискового плагина Wordpress - Лучшие практики


В течение примерно двух дней, пытаясь найти ответ на свой вопрос, я, наконец, зарегистрировался на этом обмене стеками. :)

Мой вопрос непростой, поэтому мне нужно начать с самого начала. Но чтобы дать вам представление о том, о чем этот пост: Тем временем мой плагин работает, но мне не нравится код. Я думаю, что есть лучшие способы решить эту проблему, и поэтому я ищу ниндзя wordpress, которые могут помочь мне с хорошими советами и лучшими практиками. Я действительно пытаюсь проникнуть в глубины wordpress, но это довольно сложно. Заранее благодарю вас!


Что должен делать мой плагин

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

Типы записей создаются на странице настроек плагина. Каждое сообщение этого типа имеет заголовок, содержание и несколько настраиваемых полей из плагина acf. Для каждого типа сообщения существует один шорткод. Форма поиска содержит одно поле для поиска по всем полям записей указанного типа. Два других можно использовать для ограничения результатов двумя ключевыми словами (например, местоположение, которое является полем acf).

Результаты загружаются через ajax и отображаются под формой поиска.


То, что я уже сделал

Я стараюсь, чтобы этот вопрос не был слишком большим. Поэтому я не уточняю каждый отдельный аспект. Следующее должно работать нормально:

  • Создать по типу сообщения в php-файле плагин. На данный момент достаточно одного статического типа поста.
  • Создайте короткий код, который печатает форму поиска и пустой контейнер для результатов.
  • Запрос Ajax работает через javascript и дает ожидаемые результаты.

Поиск по пользовательским полям

Это было довольно сложно, но я нашел рабочий фрагмент кода и понимаю, что он делает. Проблема здесь в том, что я просто хочу выполнить поиск в полях acf с помощью моей конкретной формы поиска. Я делаю не хочу трогать поиск по существующему сайту.

Сначала я попытался проверить, на каком сайте находится пользователь, и использовать оператор if с is_page(), прежде чем изменять поисковый запрос. Но поскольку я использую ajax, это, похоже, не работает для меня здесь...

Мой обходной путь - установить глобальную переменную в начале каждого поискового запроса ajax. Теперь я проверяю, установлена ли эта переменная, прежде чем изменять поисковый запрос. В конце моей функции ajax я вернул этой переменной значение false. Да, я думаю, что есть лучший способ решить эту проблему, но я не знаю, как...

Функции, которые изменяют мой поисковый запрос, следующие:

/**
 * Extend WordPress search to include custom fields
 *
 * http://adambalee.com
 */

/**
 * Join posts and postmeta tables
 *
 * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_join
 */
function cf_search_join( $join ) {
    global $wpdb;
    //$cwlistpage=(is_page('list'));

    global $testcheck;
    $cwlistpage=$testcheck;

    if ( $cwlistpage ) {    
        $join .=' LEFT JOIN '.$wpdb->postmeta. ' ON '. $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id ';
    }

    return $join;
}
add_filter('posts_join', 'cf_search_join' );

/**
 * Modify the search query with posts_where
 *
 * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_where
 */
function cf_search_where( $where ) {
    global $pagenow, $wpdb;
    //$cwlistpage=(is_page('list'));

    global $testcheck;
    $cwlistpage=$testcheck;

    if ( $cwlistpage ) {
        $where = preg_replace(
            "/\(\s*".$wpdb->posts.".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
            "(".$wpdb->posts.".post_title LIKE $1) OR (".$wpdb->postmeta.".meta_value LIKE $1)", $where );
    }

    return $where;
}
add_filter( 'posts_where', 'cf_search_where' );

/**
 * Prevent duplicates
 *
 * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_distinct
 */
function cf_search_distinct( $where ) {
    global $wpdb;
    //$cwlistpage=(is_page('list'));

    global $testcheck;
    $cwlistpage=$testcheck;

    if ( $cwlistpage ) {
        return "DISTINCT";
    }

    return $where;
}
add_filter( 'posts_distinct', 'cf_search_distinct' );

Ограничьте результаты пользовательскими полями

Все поля формы являются необязательными. Пустая форма вернет все записи этого типа. В первом поле следует искать ключевое слово в каждом поле сообщений. Второе и третье поля должны ограничивать результаты тем, которое содержит это ключевое слово. Я решил эту проблему с помощью if-утверждений и я знайте, что должно быть лучшее решение.

/**
* Search with AJAX
*/
function cwlist_click_search() {
global $testcheck;
$testcheck = true;

$searchterm = $_POST['query'];
$searchlocation = $_POST['location'];
$searchdegree = $_POST['degree'];

// WP_Query arguments
$args = array (
    'post_type' => 'offers',
    'post_status' => 'publish',
    's' => $searchterm
);

$query = new WP_Query( $args );

ob_start();

// The Loop
if ( $query->have_posts() ) : ?>
  <br><br><p>
   <?php while ( $query->have_posts() ) : $query->the_post();
        if( ($searchlocation == NULL) || in_array(trim(strtolower($searchlocation)), array_map('strtolower', get_field('offer_location')))):
            if( ($searchdegree == NULL) || (trim(strtolower($searchdegree)) === strtolower(get_field('offer_degree')))):?>

     Titel: <?php the_title(); ?> <br>
     Abschluss: <?php the_field('offer_degree'); ?> <br>
     Ort: <?php the_field('offer_location'); ?> <br>
     Anbieter: <?php the_field('offer_provider'); ?> <br>
     <?php if(get_field('offer_subtitle')): ?>
     - <?php the_field('offer_subtitle'); ?> <br>
     <?php endif; ?>
     <br>

    <?php endif; endif; endwhile; ?>
    </p>
<?php else: ?>
    <!-- no posts found -->
    Keine Angebote gefunden
<?php endif;

// Restore original Post Data
wp_reset_postdata();

$content = ob_get_clean();

echo $content;
die();

$testcheck = false;
}
add_action( 'wp_ajax_nopriv_cwlist_click_search', 'cwlist_click_search' );
add_action( 'wp_ajax_cwlist_click_search', 'cwlist_click_search' );

Отладка WP

Когда я активирую плагин, на главной странице появляется много строк, подобных следующим:

Примечание: Попытка получить свойство не-объекта в C:\Users\CWalt\Documents\gitlab\steuerazubi\wordpress\wp-includes\query.php на линии 4520 Обратите внимание: Попытка получить свойство не-объекта в C:\Users\CWalt\Documents\gitlab\steuerazubi\wordpress\wp-includes\query.php на линии 4522 Обратите внимание: Пытаясь получить свойство не-объекта в C:\Users\CWalt\Documents\gitlab\steuerazubi\wordpress\wp-includes\query.php на линии 4524 ...

Я активировал отладку, чтобы создать хороший плагин. Что я мог сделать не так?


Больше Типов Сообщений

Знаете ли вы хороший подход, позволяющий пользователю указывать больше типов сообщений через серверную часть wordpress? Пользователь должен иметь возможность создавать разные страницы поиска для разных типов сообщений с помощью коротких кодов.


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

Author: Christoph, 2016-05-05

1 answers

Я прочитал ваш пост полностью, я, конечно, не вижу в нем ничего особенно плохого, но мне кажется, что вы больше разочарованы тем, как он был изложен.

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

Плагин Wordpress Boiler Plate - это то, что я от всей души рекомендую. Обычно я начинаю с того, что направляюсь к wwpb.me чтобы сгенерировать для себя скелет плагина, функциональный вне ворот, просто заполните форму, загрузите и извлеките в каталог плагинов вашей установки wordpress.

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

Ускорьте разработку с помощью шаблона плагина WordPress pt1

Шаблон плагина WordPress Часть 2: Разработка плагина

Шаблон Плагина WordPress Часть 3: Последние шаги

После того, как вы быстро прочитаете это, мне обычно нравится создавать класс данных, в котором хранятся все мои пользовательские запросы к базе данных, такие как:

<?php 

class example_Events_Data {
  private $wpdb;

  public function __construct() {
    global $wpdb;
    $this->wpdb = $wpdb;
  }

  public function get_events($start_date = null, $end_date = null) {
    $query = "SELECT wp_example_event.id, wp_example_event.name, wp_example_event.description, wp_example_event.date, wp_example_event.end_date, wp_example_event_type.id as event_type_id, wp_example_event_type.type as event_type
              FROM wp_example_event
              JOIN wp_example_event_type on wp_example_event.type_id = wp_example_event_type.id
              ORDER BY wp_example_event.name ASC";
    $events = $this->wpdb->get_results($query, ARRAY_A);
    return $events;
  }

Затем, чтобы использовать это внутри ваших контроллеров администратора/общественности, это как просто, как сделать:

    <?php

class Example_Events_Admin {

/**
 * The ID of this plugin.
 *
 * @since    1.0.0
 * @access   private
 * @var      string    $plugin_name    The ID of this plugin.
 */
private $plugin_name;

/**
 * The version of this plugin.
 *
 * @since    1.0.0
 * @access   private
 * @var      string    $version    The current version of this plugin.
 */
private $version;

private $data;
private $utils;

/**
 * Initialize the class and set its properties.
 *
 * @since    1.0.0
 * @param      string    $plugin_name       The name of this plugin.
 * @param      string    $version    The version of this plugin.
 */
public function __construct( $plugin_name, $version ) {

    $this->plugin_name = $plugin_name;
    $this->version = $version;
    $this->data = new example_Events_Data();

}

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

Вы просто включаете их в свой основной файл плагина с помощью require_once и создаете экземпляр там, где это необходимо.

Использование класса данных позволяет мне централизовать все мои вызовы данных в одном месте и использовать их на протяжении всей разработки плагина.

Использование этих методов имеет значительно сократил время разработки и значительно упростил обслуживание моих плагинов.

Надеюсь, вы найдете этот ответ полезным!

 1
Author: Ryan Fletcher, 2016-06-02 02:07:47