Задать вопрос
@veroni1337

Как ускорить фильтр записей по мета полям acf wordpress?

Здравствуйте. Есть тип записи у которого почти пол миллиона постов. Раньше когда постов было меньше 2000 фильтрация по meta_query работала быстро. Но сейчас когда постов больше 400к загрузка длится от 5 минут. Судя по информации в различных форумах дело именно в фильтрации по метаполям. Но у меня много полей которые участвуют в фильтрации и менять 400к записей под таксономии будет проблематично. Есть ли какой то способ ускорить фильтр постов в wp_query используя meta_query? На страницу вывожу по 5 штук. Ведь выборка не должна отобрать первые 5 записей подходящих и выдать результат, просто почему так долго?

Пример кода(урезанный вариант):
// $template = $_POST["template"];
  $args['post_type'] = 'objects';
  $args['post_status'] = 'publish';
  $args['posts_per_page'] = 10;

  // СОРТИРОВКА
  // по цене
  if (!empty($_POST["sortByPrice"])) {
    $args['meta_key'] = 'price';
    $args['orderby'] = 'meta_value_num';
    $args['order'] = $_POST["sortByPrice"];
    $args['ignore_custom_sort'] = true;
  }

  $args['meta_query'] = array(
    'relation'    => 'AND'
  );

  // Страница
  if (!empty($_POST["page"])) {
    $args['paged'] = $_POST["page"];
  }

  // META

  // Цена ОТ
  if (!empty($_POST["priceFrom"])) {
    $args['meta_query'][] = array(
      'key'    => 'price',
      'value'    => $_POST["priceFrom"],
      'type'    => 'NUMERIC',
      'compare'  => '>'
    );
  }
  // Цена ДО
  if (!empty($_POST["priceTo"])) {
    $args['meta_query'][] = array(
      'key'    => 'price',
      'value'    => $_POST["priceTo"],
      'type'    => 'NUMERIC',
      'compare'  => '<'
    );
  }

  // Площадь ОТ
  if (!empty($_POST["squareFrom"])) {
    $args['meta_query'][] = array(
      'key'    => 'square',
      'value'    => $_POST["squareFrom"],
      'type'    => 'NUMERIC',
      'compare'  => '>'
    );
  }
  // Площадь ДО
  if (!empty($_POST["squareTo"])) {
    $args['meta_query'][] = array(
      'key'    => 'square',
      'value'    => $_POST["squareTo"],
      'type'    => 'NUMERIC',
      'compare'  => '<'
    );
  }

  // Тип сделки
  if(!empty($_POST["dealType"])) {
    $objCategories[] = $_POST["dealType"];
  }

  // вторичное
  if($_POST["street"] == 'вторичное') {
    $objCategories[] = 'real-estate-apartments-sale-secondary';
  }

  if(!empty($_POST["dealType"]) or $_POST["street"] == 'вторичное') {
    $args['tax_query'][] = array(
      'taxonomy'    => 'obj_categories',
      'field' => 'slug',
      'terms' => $objCategories,
    );
  }

  // Только с фото
  if (!empty($_POST["withPhotos"])) {
    $args['meta_query'][] = array(
      array(
        'key' => 'gallery',
        'value' => array('', 0),
        'compare' => 'NOT IN'
      )
    );
  }

  // Только с газом
  if (!empty($_POST["gas_type"])) {
    $args['meta_query'][] = array(
      array(
        'key' => 'gas_type_name',
        'value' => array('', 0),
        'compare' => 'NOT IN'
      )
    );
  }

  // Кол-во комнат
  // TODO: Нужно найти все совпадения

  if (!empty($_POST["rooms"])) {
    $args_for_rooms = array(
      'relation' => 'OR'
    );
    $arrayRooms = explode(",", $_POST["rooms"]);
    foreach ($arrayRooms as $key => $value) {


      // $value = 0,1,2,3,4+
      switch ($value) {
        case '4+':
          $array_for_four = [
            'relation' => 'AND'
          ];
          $array_for_four[] = array(
            'key'    => 'rooms',
            'value'    => 3,
            'compare'  => '>'
          );
          // исключаю студии, так студия = 6 символов и они присутствуют в выдаче
          if (!in_array('studia', $arrayRooms)) {
            $array_for_four[] = array(
              'key'    => 'rooms',
              'value'    => array('студия', '', '-'),
              'compare'  => 'NOT IN'
            );
          }
          $args_for_rooms[] = $array_for_four;
          break;
        case 3:
        case 2:
        case 1:
          $args_for_rooms[] = array(
            'key'    => 'rooms',
            'value'    => $value,
            'compare'  => 'IN'
          );
          break;
        case 'studia':
          $args_for_rooms[] = array(
            'key'    => 'rooms',
            'value'    => array('студия'),
            'compare'  => 'IN'
          );
          break;
      }
    }

    $args['meta_query'][] = $args_for_rooms;
  }

  // Поиск в названии (улица и тд)
  if (!empty($_POST["street"])) {
    //$args['obj_title'] = $_POST["street"]; // добавялю в массив args
    $args['s_meta_keys'] = array('title', 'tags');
    $args['s'] = $_POST["street"];
  }

  function title_filter($where, &$wp_query)
  {
    global $wpdb;

    // check if $_POST['novostroi'] exists
    if (!empty($_POST['novostroi'])) {
      // exclude posts with "участок" in their title
      $where .= ' AND ' . $wpdb->posts . '.post_title NOT LIKE \'%участок%\'';
      $where .= ' AND ' . $wpdb->posts . '.post_title NOT LIKE \'%коммерч%\'';
      $where .= ' AND ' . $wpdb->posts . '.post_title NOT LIKE \'%дом%\'';
    }

    if ($search_term = $wp_query->get('obj_title')) {
      $where .= ' AND ' . $wpdb->posts . '.post_title LIKE \'%' . esc_sql(like_escape($search_term)) . '%\'';
    }
    return $where;
  }

  add_filter('posts_where', 'title_filter', 10, 2);

  add_filter('posts_where', 'yanco_posts_where');
  function yanco_posts_where( $where ) {
    $where = str_replace( "meta_key = 'metro_station_$", "meta_key LIKE 'metro_station_%", $where );
    return $where;
  }

  $args['no_found_rows'] = true;


  $posts = new WP_Query($args);
  $response_array = array();
  remove_filter('posts_where', 'title_filter', 10, 2);
  if ($posts->have_posts()) {
    $response_array['success'] = true;
    while ($posts->have_posts()) {
      $posts->the_post();
      ob_start();
      get_template_part("template-parts/loop/object-item-new");
      $response_array['html'] .= ob_get_contents();
      ob_end_clean();
    }
  } else {
    $response_array['success'] = false;
  }
  $response_array['args'] = $args;
  $response_array['$_POST'] = $_POST;
  wp_send_json($response_array);
  wp_die();
  • Вопрос задан
  • 101 просмотр
Подписаться 1 Сложный Комментировать
Пригласить эксперта
Ответы на вопрос 2
YBB
@YBB
Почему медленно? Посмотрите какие SQL-запросы порождает wordpress. Там все довольно наглядно. Увы, при такой архитектуре хранения метаданных тормоза - неизбежное зло.

Можно ли ускорить? Можно попробовать в таблице wp_postmeta создать индекс по полю meta_value. В некоторых случаях немного помогает.

А чтобы радикально улучшить, то только менять способ хранения метаданных.
Ответ написан
Комментировать
sputnickk
@sputnickk
3) Use Local JSON (or Export to PHP). Local JSON is a new feature added in version 5 which saves field group and field settings as .json files within your theme. The idea is similar to caching, and both dramatically speeds up ACF and allows for version control over your field settings! - https://help.filandor.com/pamyatka-po-proizvolnym-...

У меня такое было с магазином вукомерц, надо индексы добавлять, летает просто:

Index WP MySQL For Speed
SQLite Object Cache (For Ubuntu: sudo apt update / sudo apt install php7.4-sqlite3 / sudo phpenmod pdo_sqlite / sudo systemctl restart apache2)

ну и естессно мемкеш
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы