Задать вопрос
  • Как использовать ACF на страницах архива записей?

    @Ctr99ru
    ACF отвечали на подобный вопрос у себя https://support.advancedcustomfields.com/forums/to...

    Мы это реализовали для одного из наших клиентов.

    Вот полное решение:
    1. В functions.php добавляем подключение страницы опций для конкретного типа записи
    // Разделы настроек для кастомных типов записей
    if( function_exists('acf_add_options_page') ) {
    
    // ВАЖНО! Если подключаете для нескольких типов записей, menu_title должен быть уникальным, используется в урле!	
      acf_add_options_sub_page(array(
        'page_title'     => 'Тара / Настройки',
        'menu_title'    => 'Настройки (тара)',
        'parent_slug'    => 'edit.php?post_type=package',
      ));	
    }


    2. Сохраните, обновите страницу, проверьте, добавилась ли страница опций к нужному типу записи. Если все ок, то создайте группу нужных полей в ACF, в настройках, где показывать, укажите "Страница с опциями - равно - [выберите вашу новую страницу]".

    3. На странице archive.php получить значение из нужного поля можно, добавив параметр 'options' в get_field(). Пример:
    $test = get_field('your_field_name', 'options');
    Ответ написан
    Комментировать
  • Как задать свою директорию для шаблонов CPT?

    add_filter( 'template_include', 'wpb_template' );

    function wpb_template( $template ) {
    if ( is_post_type_archive('books') ) {
    return get_stylesheet_directory_uri() . 'templates/archive-books.php';}
    return $template;
    }
    Ответ написан
    Комментировать
  • SEO продвижение сайта WordPress?

    лови алгоритм действий:
    1) выкидывай all in one, ставь rank math, он лучше и в бесплатной версии больше возможностей чем в платной aio.
    2) включи чпу, поставь плагин типа этого, чтобы автоматически всё менялось в чпу и транслит (ссылки, картинки и т.п.), заодно уберешь мусор из ссылок.
    3) сделай структуру сайта, подумай какие люди должны приходить из поиска на какие страницы.
    самый геморный этап, без опыта обычно 99% людей косячат именно на этом этапе, причем страшно и переделать потом бардак в структуре очень затруднительно. Тут хорошо пригодится анализ конкурентов.
    4) начинай сбор ключей под структуру (под каждую важную страницу) - их обычно тысячи, поэтому нужен какой-то инструмент автоматизации. На сегодня есть только Keycollector, который с каждым днем работает все хуже и хуже, так что торопись, может еще успеешь собрать им что-то.
    5) затем проанализируй слова и выброси мусор, а также сверхконкурентные запросы, по каким никогда не продвинешься - формула kei в помощь.
    6) зафиксируй текущее положение ключей в поиске - чтобы потом динамику позиций смотреть.
    7) составляй метатеги под собранные и зафиксированные ключи, самое жирное в тайтл, лишнего туда поменьше.
    8) затем пиши сам сео тексты под страницы, ну если совсем туго, заказывай на бирже, в статье ссылки есть на самые норм, где мне писали хоть что-то похожее на вменяемый текст.
    9) затем открывай сайт для посетителей. Именно так, а не сразу открыл полупустые страницы, а потом думаешь, почему сайт не индексируется. Открывать надо когда готовы предыдущие пункты. И отправляешь все это на индексацию - карта сайта, robots, редиректы, ssl, панели вебмастеров, справочники, фавикон, счетчики и т.п. тут уже все идет в ход. Надо заявить о своем сайта везде, на всех поисковиках, причем правильно всё настроить и убедиться, что сайт и индексируется. Хорошо если проиндексируется за пару недель в яндексе и google, значит повезло.
    10) через 2-3 месяца анализируй динамику запросов - что ползёт вверх помогай, что не ползет - выясняй причину.

    Вот хотя бы так.

    p.s. это примерно 5% от всех работ по сео, так сказать самые необходимые и простые, которые может владелец сайта сам сделать, а там еще до кучи: улучшение скорости page speed, webp, микроразметка, перелинковка, анализ упущеных запросов, вечные ссылки, турбо страницы и т.п. короче там есть чем заняться надолго ))
    Ответ написан
    Комментировать
  • Самый правильный цикл WP? Что и когда использовать?

    HeadOnFire
    @HeadOnFire
    PHP, Laravel & WordPress Evangelist
    Вы немножко запутались, have_posts() это не цикл, а метод объекта WP_Query, проверка если ли посты в текущем экземпляре WP_Query, независимо от того как данный экземпляр был вызван/создан - это основной запрос или произвольный. Что касается запросов, то все просто:

    1. Есть основной запрос, который по умолчанию в WP всегда выполняется. Всегда в первую очередь смотрим, можно ли добиться нужного результата путем его модификации через хук pre_get_posts. В большинстве случаев именно этим путем решается задача. Например, изменить количество постов на страницу на главной или в рубриках.

    2. Если кроме основного запроса нужен дополнительный, например у вас на главной есть уже стандартный запрос, который выводит последние записи, а вы хотите еще отдельно вывести записи произвольного типа (например, вопросы из FAQ), то используете WP_Query. В принципе, в большинстве случае если нужен отдельный от основного цикл / набор постов - используйте WP_Query. Но важно помнить, что в зависимости от задачи вы можете передать несколько важных параметров, которые повлияют на скорость. Например, по умолчанию WP_Query выполняет CALC_FOUND_ROWS (подсчет всего найденных строк), который нужен для пагинации. Если вам нужно всего лишь получить X постов, используйте параметр 'no_found_rows' => true в комбинации с указанием четкого количества постов в параметре posts_per_page - в этом случае общее количество не будет считаться. Также, по умолчанию WP_Query запрашивает таксономии и метаданные ко всем постам, и кеширует их. Это тоже можно отключать. Также, при выполнении WP_Query может быть затронут плагинами через фильтры - например posts_where (WHERE clause в MySQL). Еще важно понимать, что вызов new WP_Query возвращает новый объект WP_Query, по которому можно выполнить Loop с помощью while ( have_posts() ) : the_post() - в этом случае посты в итерации цикла будут попадать в глобальный scope.

    3. get_posts - это как шорткат на WP_Query с определенными предустановленными параметрами. Если нужно просто получить несколько постов по каким-то параметрам - используйте эту функцию. Первое, и основное - эта функция внутри вызывает именно new WP_Query. Второе - эта функция возвращает массив постов (объектов WP_Post). Третье - эта функция вызывает WP_Query c предустановленными параметрами no_found_rows (не считать общее количество постов, соответствующих параметрам) и suppress_filters (что отключает все фильтры над запросом кроме pre_get_posts). Вот и вся разница.

    4. query_posts - никогда, НИКОГДА, ни при каких обстоятельствах не использовать данную функцию. Считайте, что ее не существует. Точка.
    Ответ написан
    Комментировать
  • Как реализовать такое?

    @wadowad
    Можно реализовать через padding. Например, padding-top: 30% - это верхний внутренний отступ 30% от ширины родителя. Обратное поведение можно задать через calc:

    padding-top: calc(100px - 10%);

    Тогда при уменьшении ширины родителя, верхний отступ будет увеличиваться.
    Ответ написан
    1 комментарий
  • Как сделать, чтобы при выборе значения в одном select'е оно пропадало в других?

    0xD34F
    @0xD34F Куратор тега JavaScript
    const selects = [...document.querySelectorAll('select')];
    const onChange = () =>
      selects.forEach(function({ value, options: [...n] }) {
        n.forEach(m => m.hidden = this(m.value) && value !== m.value);
      }, Set.prototype.has.bind(new Set(selects.map(n => n.value))));
    
    selects.forEach(n => n.addEventListener('change', onChange));
    Ответ написан
    1 комментарий
  • Как сверстать такой треугольник с градиентом у border?

    RAX7
    @RAX7
    Первый вариант svg mask.
    плюсы: не требует js
    минусы: нельзя применить backdrop-filter


    Второй вариант svg clip-path.
    плюсы: можно применить backdrop-filter
    минусы: требует js и желательно ResizeObserver
    Ответ написан
    Комментировать
  • Как в WooCommerce добавить кнопку "Купить в 1 клик" рядом с кнопкой "Добавить в корзину"?

    1. Добавьте кнопку и в атрибуте (можно data-id) передайте id товара
    global $product;
    $id = $product->id;


    2. Повесьте обработчик на клик кнопки
    jQuery('.one-click-button').click(function(e) {
     	e.preventDefault();
     	jQuery(this).addClass('adding-cart');
     	var product_id = jQuery(this).data('id');
    
     	var ajax_url = "/wp-admin/admin-ajax.php"
    
     	jQuery.ajax ({
     		url: ajax_url,  
     		type:'POST',
     		data:'action=oneclick&product_id=' + product_id + '&quantity=1',
    
     		success:function(results) {
    		// Показываем окно успешного добавления
    		$('.form_popup').hide();
    		$('#modal').css('display','inline-block');
    		$('.good_cart').css('display','inline-block');
    		document.location.href = 'http://domain.ru/oformlenie-zakaza/'; //Переход на оформление заказа
    	}
    });
     });


    3. Обработчик в functions.php
    function oneclick() {
    			$product_id = $_POST['product_id'];
    			$variation_id = $_POST['variation_id'];
    			$quantity = $_POST['quantity'];
    
    			if ($variation_id) {
    				WC()->cart->add_to_cart( $product_id, $quantity, $variation_id );
    			} else {
    				WC()->cart->add_to_cart( $product_id, $quantity);
    			}
    
    			$items = WC()->cart->get_cart();
    			global $woocommerce;
    			$item_count = $woocommerce->cart->cart_contents_count; ?>
    
    			<?php die();
    		}
    
    add_action('wp_ajax_oneclick', 'oneclick');
    add_action('wp_ajax_nopriv_oneclick', 'oneclick');
    Ответ написан
    7 комментариев
  • Как грамотно верстать несколько страниц веб-сайта?

    delphinpro
    @delphinpro Куратор тега Вёрстка
    frontend developer
    Берёте и верстаете как обычно.
    Любые из озвученных инструментов актуальны. Выбирайте по душе.

    Лично я предпочитаю верстку делать, используя mix. Потому что его практически не нужно конфигурировать. Сразу начинаешь работать. Плюс, есть куча готовых расширений https://laravel-mix.com/extensions

    Примерный конфиг
    const mix = require('laravel-mix');
    require('laravel-mix-twig');
    
    mix.setPublicPath('dist');
    mix.browserSync({
        server      : {
          baseDir  : 'dist',
          directory: true,
        },
        files       : ['./dist'],
      });
    }
    
    mix.sass('src/scss/main.scss', 'css');
    
    mix.js('src/js/main.js', 'js')
      .sourceMaps(true)
      .extract();
    
    mix.alias({
      '@': path.join(__dirname, 'src'),
    });
    
    mix.twig({
      root    : './src/templates',
      entries : [
        '*.twig',
      ],
      output  : './',
    });

    package.json
    {
      "private": true,
      "scripts": {
        "dev": "mix",
        "watch": "mix watch",
        "watch-poll": "mix watch -- --watch-options-poll=1000",
        "hot": "mix watch --hot",
        "prod": "mix --production"
      },
      "devDependencies": {
        "laravel-mix": "^6.0.43",
        "laravel-mix-twig": "^2.0.1"
      }
    }
    Ответ написан
    Комментировать
  • Как передать содержимое в переменную PHP?

    @easycode
    не боюсь задавать глупые вопросы ))
    ну типа:
    <div id="list"></div>
    
    <script type="text/javascript">
      jQuery(document).ready(function($) {
        jQuery.post('index.php', 'list': jQuery('#list').html(), function(data, textStatus, xhr) {
          /*optional stuff to do after success */
        });
      });
    </script>


    на стороне сервера:
    <?php
    #index.php
    echo $_POST['list']; // содержимое div-а с id = list
    Ответ написан
    Комментировать
  • Какие lazy load-плагины для изображений лучше?

    @SergeiB
    После появления Intersection Observer API надобность в плагинах отпала. Всё решается парой десятков строк кода.
    Пример.

    const options = {
      root: null,
      rootMargin: '0px',
      threshold: 0.05
    };
    
    const lazyload = function(entries, observer) {
      entries.forEach(function(entry) {
        const target = entry.target;
        const dataset = target.dataset;
    
        if (entry.isIntersecting) {
          try {
            if ('src' in dataset) {
              target.src = dataset.src;
            }
    
            if ('bg' in dataset) {
              target.style.backgroundImage = `url(${dataset.bg})`;
            }
    
            target.classList.add('lazyloaded');
            observer.unobserve(target);
          } catch (error) {
            console.error(error);
          }
        }
      });
    };
    
    const observer = new IntersectionObserver(lazyload, options);
    
    document.querySelectorAll('.js-lazyload').forEach(elem => observer.observe(elem));

    <!-- Изображение без плейсхолдера -->
    <img class="js-lazyload" data-src="path/to/image/elephant.jpg" alt="The pink elephant">
    
    <!-- Изображение с плейсхолдером -->
    <img class="js-lazyload" data-src="path/to/image/elephant.jpg" src="path/to/placeholder.jpg" alt="The pink elephant">
    
    <!-- Ситуация, когда изображение надо задать как фон -->
    <div class="js-lazyload" data-bg="path/to/image/elephant.jpg"></div>

    Ответ написан
    3 комментария
  • Как минимизировать риски атак и взлома сайта?

    pro100taa
    @pro100taa
    Реализуйте из пункта "Что делать чтобы обезопасить сайт" что получится.

    https://ru.wordpress.org/support/article/faq-hacked/
    Ответ написан
    Комментировать
  • Как создать на wp кастомную роль с просмотром post_type?

    V_A_B
    @V_A_B
    ¯\_(ツ)_/¯
    интересный вопрос.....Спасибо!
    Пройдя по ссылке Анатолия и поковырявшись вот такой вариант у меня вышел)):
    создаем новую роль
    add_role('newvabuser',
    		__('Новый пользователь','VAB'),
    		array(
    		'read'=>true,
    		'edit_posts'=>false,
    		'delete_posts'=>false,
    		'publish_posts'=>false,
    		'upload_files'=>true,
    	 )
    	);

    насколько я понял данный код можно удалить после того как роль с массивом попадет в базу....
    если что не так, используйте
    remove_role('newvabuser');
    далее создаем новый пост тип
    add_action('init','create_custom_post_types');
    function create_custom_post_types(){
    	register_post_type('vabs',
    		array(
    			'labels'=>array(
    					'name'=>__('Новый тип записи','VAB'),
    					'singular_name'=>__('Новый тип записи','VAB'),
    					'menu_name'=>__('Новый тип записи','VAB'),
    					'add_new'=>__('Добавить новую','VAB'),
    					'add_new_item'=>__('Добавить новую','VAB'),
    					'edit_item'=>__('Редактировать','VAB'),
    					'new_item'=>__('Новая','VAB'),
    					'all_items'=>__('Все записи','VAB'),
    					'view_item'=>__('Просмотр','VAB'),
    					'search_items'=>__('Искать','VAB'),
    					'not_found'=>__('Записи не найдены','VAB'),
    					'not_found_in_trash'=>__('В корзине записи не найдены','VAB'),
    					'parent_item_colon'=>''
    			),
    			'public'=>true,
    			'has_archive'=>true,
    			'rewrite'=>array('slug'=>'vab'),
    			'capability_type'=>'vab',
    			'capabilities'=>array(
    				'publish_posts'=>'publish_vabs',
    				'edit_posts'=>'edit_vabs',
    				'edit_others_posts'=>'edit_others_vabs',
    				'delete_posts'=>'delete_vabs',
    				'delete_others_posts'=>'delete_others_vabs',
    				'read_private_posts'=>'read_private_vabs',
    				'edit_post'=>'edit_vabs',
    				'delete_post'=>'delete_vabs',
    				'read_post'=>'read_vabs',
    				'assign_terms' =>'edit_taxo',
    				'manage_terms'=>'manage_vab_terms',
    				'edit_terms'=>'manage_vab_terms',
    				'delete_terms'=>'delete_vab_terms',
    				'assign_terms'=>'edit_vab-type'
    			),
    			'supports'=>array('title','editor','thumbnail')
    		)
    	);
    }

    важно обратить внимание на массив с параметрами capabilities. его мы дальше передадим нашей роли:
    add_action('admin_init','add_vabs_caps');
    function add_vabs_caps(){
    	$admins=get_role('newvabuser');
    	$admins->add_cap('edit_vabs');
    	$admins->add_cap('publish_vabs');
    	$admins->add_cap('read_vabs');
    	$admins->add_cap('read_private_vabs');
    	$admins->add_cap('delete_vabs');
    	$admins->add_cap('edit_taxo');
    	$admins->remove_cap('edit_others_vabs');
    	$admins->remove_cap('delete_others_vabs');
    	$admins->add_cap('manage_vab_terms');
    	$admins->add_cap('delete_vab_terms');
    	$admins->add_cap('edit_vab-type');
    	$admins->add_cap('manage_categories');
    	$admins->add_cap('edit_categories');
    	$admins->add_cap('delete_categories');
    	$admins->add_cap('assign_categoriess');
    }

    В итогах данную запись смогут редактировать только админ и пользователь с данной ролью больше никто:
    5d5c421fb2511245944305.jpeg
    5d5c422ca4152143576315.jpeg
    Вам нужно все это только под себя переделать
    Ответ написан
    1 комментарий
  • Как добавить поле поиска записи или таксономии в админке Wordpress или Woocommerce?

    DrZhmurge
    @DrZhmurge Автор вопроса
    переопределяем функцию которую дата указана в "data-action", на любую кастомную.
    У меня: data-action="search_posts".
    Далее создаем функцию search_posts:

    add_action('wp_ajax_search_posts', 'search_posts');
    function search_posts()
    {
    	$s = $_GET['term']; //получает данные введенного текста для поиска
    	$args = array(
    		'post_type' => 'collection',  //ваш тип поста
    		's' => $s, //поисковый запрос
    	);
    	$data = [];
    	$loop = new WP_Query($args);
    	if ($loop->have_posts()) {
    		while ($loop->have_posts()) {
    			$loop->the_post();
    			$post_id = get_the_id(); //получаем id записи
    			$post_name = get_the_title(); //получаем title записи
    			$data[$post_id] = $post_name; // добавляем в массив data
    		}
    	}
    	echo json_encode($data); //кодируем в json и выводим
    	wp_die(); //иначе 0 в конце всегда лишний в выводе
    }


    Далее меняем вывод нужных нам данных уже в самом поле select. Приведу в пример полный код select, чтобы не запутаться:
    <select id="product_field_type" name="product_field_type[]" class="wc-product-search" multiple="multiple" style="width: 50%;" data-placeholder="<?php esc_attr_e('Поиск по названию коллекции', 'woocommerce'); ?>" data-action="search_posts">
    					<?php
    					$product_ids            = [];
    					$product_field_type_ids = get_post_meta(get_the_ID(), '_product_field_type_ids', true);  //сменил $post->ID на get_the_ID()
    					
    					if (!empty($product_field_type_ids)) {
    						$product_ids = array_map('absint', $product_field_type_ids);
    					}
    
    					if ($product_ids) {
    						foreach ($product_ids as $product_id) {
    							//$product = new WP_Query($product_id);  больше не нужен
    							
    							echo sprintf(
    								'<option value="%s" %s>%s</option>',
    								esc_attr($product_id),
    								selected(true, true, false),
    								esc_html(get_the_title($product_id)) //получаем нужный нам title по id записи
    							);
    						}
    					}
    					?>
    				</select>
    Ответ написан
    Комментировать
  • Принцип, по которому можно такое реализовать?

    artzolin
    @artzolin Куратор тега WordPress
    php, WordPress разработка сайтов artzolin.ru
    Комментировать
  • Как добавить несколько файлов в поле acf(galery) при отправке формы с сайта?

    wppanda5
    @wppanda5 Куратор тега WordPress
    WordPress Mедведь
    Вы на каждой итерации обновляете id картинки

    Надо как-то так
    $files = $_FILES[ "photo" ];
    	$_ids  = $_errors = [];
    	foreach ( $files[ 'name' ] as $key => $value ) {
    		if ( $files[ 'name' ][ $key ] ) {
    			$file   = array (
    				'name'     => $files[ 'name' ][ $key ],
    				'type'     => $files[ 'type' ][ $key ],
    				'tmp_name' => $files[ 'tmp_name' ][ $key ],
    				'error'    => $files[ 'error' ][ $key ],
    				'size'     => $files[ 'size' ][ $key ]
    			);
    			$_FILES = array ( "rev_foto" => $file );
    
    			$attachment_id2 = media_handle_upload( "rev_foto", 0 );
    
    
    			if ( is_wp_error( $attachment_id2 ) ) {
    				$_errors[] = $attachment_id2->get_error_message();
    			} else {
    				$_ids[] = $attachment_id2;
    			}
    		}
    	}
    
    	if ( ! empty( $_ids ) ) {
    		update_field( 'rev_foto', $_ids, $post_id );
    	}
    
    	if ( ! empty( $_errors ) ) {
    		sprintf( 'А вот, что пошло не так: %s', implode( ' ,', $_errors ) );
    	}


    И пользуйтесь уже нормальными функциями из движка а не всяким get_field, update_field и иже с ним
    Ответ написан
    1 комментарий
  • Gutenberg Как задать css класс по умолчанию блокам?

    @Flying
    Есть несколько вариантов решения:

    1. Патчинг HTML отрендеренного блока

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

    add_filter('render_block_core/video', function (string $content, array $block) {
        // Здесь вам нужно изменить содержимое переменной $content
        // она содержит уже отрендеренный HTML код блока.
        return $content;
    }, 10, 2);


    Для корректной работы с HTML лучше использовать расширение DOM.

    2. Переопределить рендер блока целиком

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

    3. Сделать свой блок

    Также, через register_block_type определяете свой собственный блок и пишете свой рендер для него.
    Ответ написан
    Комментировать
  • Изменить порядок вывода атрибутов в шаблоне?

    wppanda5
    @wppanda5 Куратор тега WordPress
    WordPress Mедведь
    Как сказал Антон Литвиненко до цикла изменить порядок элементов.

    Но можно тупо в лоб.

    $out = '';
    $html = <<<HTML
    	<tr class="woocommerce-product-attributes-item woocommerce-product-attributes-item--%s">
    		<th class="woocommerce-product-attributes-item__label">%s</th>
    		<td class="woocommerce-product-attributes-item__value">%s</td>
    	</tr>
    HTML;
    
    $i = 1;
    foreach ( $product_attributes as $attribute ):
    	$attribute_data = $attribute->get_data();
    
    	if ( $i !== 3 ) {
    		$out .= sprintf( $html, esc_attr( $attribute_data['name'] ), wc_attribute_label( $attribute_data['name'], $product->get_attribute( $attribute_data['name'] ) ) );
    	} else {
    		printf( $html, esc_attr( $attribute_data['name'] ), wc_attribute_label( $attribute_data['name'], $product->get_attribute( $attribute_data['name'] ) ) );
    	}
    
    	$i ++;
    endforeach;
    echo $out;
    Ответ написан
    4 комментария
  • Как обновить блок с помощью ajax?

    zkrvndm
    @zkrvndm
    Архитектор решений
    Пример функции для выборочного обновления контента:
    async function elementUpdate(selector) {
    	try {
    		var html = await (await fetch(location.href)).text();
    		var newdoc = new DOMParser().parseFromString(html, 'text/html');
    		document.querySelector(selector).outerHTML = newdoc.querySelector(selector).outerHTML;
    		console.log('Элемент '+selector+' был успешно обновлен');
    		return true;
    	} catch(err) {
    		console.log('При обновлении элемента '+selector+' произошла ошибка:');
    		console.dir(err);
    		return false;
    	}
    }

    Вызывайте функцию elementUpdate() передав внутрь него CSS-селектор того элемента, который вы хотите обновить. Например, если взять блок, который имеет id равный block, то достаточно выполнить:
    elementUpdate('div#block');

    Если хотите делать это циклически, каждую секунду, то можно использовать while:
    // Запуск асинхронного кода:
    
    (async function() {
    	
    	// Бесконечный цикл:
    	
    	while (true) {
    		
    		await elementUpdate('div#block'); // Обновляем блок
    		
    		// Выжидаем 1000 миллисекунд, а потом код внутри while выполняется вновь:
    		await new Promise(function(success) { setTimeout(success, 1000); });
    		
    	}
    
    })();


    P. S. Но так обычно не делают, но если вам прям сильно надо, можно использовать этот лобовой метод.
    Ответ написан
    Комментировать
  • Форма подбора wordpress?

    artzolin
    @artzolin Куратор тега WordPress
    php, WordPress разработка сайтов artzolin.ru
    1. Регистрируете гет-переменные

    add_filter( 'query_vars', 'add_query_vars' );
    function add_query_vars( $qvars ) {
    
    	$qvars[] = 'brand';
    	$qvars[] = 'model';
    	$qvars[] = 'price';
    	$qvars[] = 'location';
    
    	return $qvars;
    }


    2. Собираете и выводите html-форму
    <form method="get" class="block obj-filter">
    	<div class="row d-flex align-items-center">
    		<div class="col-12 col-md-6 col-lg-3 col-margin-bottom-small col-lg-margin-bottom-none">
    			<select name="brand" id="brand" class="obj-select">
    				<option value="audi">Audi</option>
    				<option value="volkswagen">Volkswagen</option>
    				<option value="mercedes">Mercedes</option>
    				<option value="bmw">BMW</option>
    			</select>
    		</div>
    		<div class="col-12 col-md-6 col-lg-3 col-margin-bottom-small col-lg-margin-bottom-none">
    			<select name="price" id="price" class="obj-select">
    				<option value="20">$20 000</option>
    				<option value="50">$50 000</option>
    				<option value="75">$75 000</option>
    				<option value="100">$100 000</option>
    			</select>
    		</div>
    		<div class="col-12 col-md-6 col-lg-3 col-margin-bottom-small col-lg-margin-bottom-none">
    			<input type="text" name="location" id="location" class="obj-filter-input" value="">
    		</div>
    		<div class="col-12 col-md-6 col-lg-3 col-margin-bottom-small col-lg-margin-bottom-none">
    			<input id="obj-filter-submit" type="submit" class="button" value="Фильтровать">
    		</div>
    	</div>
    </form>


    3. При нажатии кнопки Фильтровать страница перезагружается, вы получаете ссылку вида https://example.loc/?brand=audi&price=50. На хуке pre_get_postsможно поправить основной запрос вытянув данные из гет-параметров. Вам нужно установить новые tax_query или meta_query в зависимости от логики сайта

    add_action( 'pre_get_posts', 'custom_pre_get_posts', 1 );
    function custom_pre_get_posts( $query ) {
    	// Выходим, если это админ-панель или не основной запрос
    	if( is_admin() || ! $query->is_main_query() )
    		return;
    
    	// предположим, что это таксономия с машинами
    	if ( $query->is_tax( 'cars' ) ) {
    		
    		$meta = array();
    		$meta['meta_query']['relation'] = 'AND';
    
    		// выбираем записи с GET запросами
    		$query_vars = ['brand', 'model', 'price', 'location'];
    		foreach ( $query_vars as $key => $query_var ) {
    			if ( $var = get_query_var( $query_var, false ) ) {
    				// тут пишем логику по которой собирается переменная meta_query и/или tax_query
    			}
    		}
    		$query->set( 'meta_query', $meta );
    
    	}
    }
    Ответ написан
    Комментировать