Вопрос или проблема
У меня есть форма, где я перечисляю связанный пользовательский тип постов по ID родительского пользовательского типа постов в виде списка чекбоксов, как на картинке.
Когда я отмечаю вариант из 4-х опций, я хочу получить список терминов, которые имеют пользовательские посты, которые я отметил в выпадающем списке.
Форма построена с помощью Elementor Pro, но чтобы получить список постов и терминов таксономии, я делаю это с помощью кода (я создаю свою функцию и подключаю её с помощью шорткода в functions.php).
/*
* Отображение списка поля отношений
*
*/
function list_formation_caces(){
echo "<div class="golistgo">";
$args = array(
'post_type' => 'categories',
'posts_per_page' => 20,
);
$loop = new WP_Query( $args );
while ( $loop->have_posts() ) : $loop->the_post();
$formations = get_posts(array(
'post_type' => 'formations',
'post__in' => array(16061),
'meta_query' => array(
array(
'key' => 'categories', // имя пользовательского поля
'value' => '"' . get_the_ID() . '"', // совпадает точно "123", а не просто 123. Это предотвращает совпадение для "1234"
'compare' => 'LIKE'
)
)
));
if($formations){
foreach ($formations as $categorie){
$image = get_field('image_form');
if($image){
// Переменные изображения.
$url = $image['url'];
$title = $image['title'];
$alt = $image['alt'];
$caption = $image['caption'];
// Атрибуты размера миниатюры.
$size="thumbnail";
$thumb = $image['sizes'][ $size ];
$width = $image['sizes'][ $size . '-width' ];
$height = $image['sizes'][ $size . '-height' ];
}
echo "<input type=\"checkbox\" class=\"btn-check\" name=\"Description\" value =\"". get_the_title() .
"\" id=\"". get_the_ID() ."\">";
echo "<label class=\"options-form\" for="". get_the_ID() ."">";
echo "<div class=\"image-cat\">";
echo get_the_post_thumbnail();
echo"</div>";
echo "<div class=\"body-cat\">";
echo "<div class=\"title-formation\">" ;
echo "</div>";
echo "<div class=\"title-cat\">" ;
echo the_title() . ":" . " <span class=\"describe-cat\">" . get_field('type_machine') . "</span>";
echo "</div>";
echo "</div>";
echo "</label>";
}
}
endwhile;
wp_reset_postdata();
echo "</div>";
}
function shortcode_list_categ_caces(){
return (list_formation_caces()) ;
}
add_shortcode('list_formation_caces', 'shortcode_list_categ_caces');
function shortcode_total_count_checked(){
return ("<div class="count-checkboxes-wrapper">" . "<h2 class="title-count">" . "Вы выбрали" .
"<span id='count-checked-checkboxes'> " . " 0" ."</span> категорию(и)."." </h2>" .
"</div>");
}
add_shortcode('count_checked', 'shortcode_total_count_checked');
function list_sessions_caces()
{
$terms = get_terms( array(
'taxonomy' => 'sessions',
'hide_empty' => false,
) );
echo'<label for="form-field-centre" class="elementor-field-label">Где пройдет обучение?</label>';
echo '<div class="elementor-field elementor-select-wrapper ">';
echo '<select name="CENTRE" id="form-field-field_centre" class="elementor-field-textual elementor-size-sm">';
echo '<option value="">Выберите сессию обучения </option> ';
foreach ($terms as $term) {
echo '<option value="' . $term->name . '">' . $term->name . '</option>';
}
echo '</select>';
echo'</div>';
}
function shortcode_list_sessions(){
return (list_sessions_caces()) ;
}
add_shortcode('list_sessions_caces', 'shortcode_list_sessions');
Вы можете пойти двумя путями:
- Скорее всего, данных для таксономий обоих пользовательских типов постов не так много, поэтому вы могли бы отобразить эти два массива в javascript из php в вашем шаблоне, а затем переключать данные выпадающего списка по клику на чекбокс. Вы могли бы назвать массивы по id пользовательских типов постов, например
cpt-134
, а затем при клике на CPT установить данные выпадающего списка на массив с именемcpt-[id-пользовательского-типа-постов]
. Один из способов получить эти данные в ваш javascript – это, если у вас, например, естьgeneral.js
:
wp_register_script('general', get_template_directory_uri() . '/js/general.js');
wp_localize_script('general', 'myVars', array(
'site_url' => site_url(),
'dropdownData' => get_CPT_Dropdown_Data(),
));
wp_enqueue_script('general');
Вам, конечно, придется написать эту функцию get_CPT_Dropdown_Data()
, которая возвращает массивы с данными таксономий на основе id пользовательских типов постов.
- При клике на CPT вызовите ajax функцию, которую вы создали, чтобы получить таксономии для этого CPT. Затем обновите выпадающий список этими данными.
Второй вариант – это более надежный метод (если все расширится) и не наполняет ваш код данными, которые могут не понадобиться. Но это добавит дополнительные запросы к серверу, поэтому вы можете захотеть включить обратную связь для ваших пользователей, когда загрузка начнется.
Ответ или решение
На основании вашего запроса о динамическом изменении значений выпадающего списка в форме, мы можем рассмотреть два подхода, которые помогут вам реализовать эту функциональность.
Подход 1: Использование JavaScript и PHP для передачи данных
Первый подход подразумевает передачу данных с помощью JavaScript. Вы можете получить все необходимые данные из ваших пользовательских типов записей (CPT) при загрузке страницы и хранить их в JavaScript-объекте. Затем, когда пользователь выберет определенные опции, вы сможете изменять значения выпадающего списка на основе этих данных.
-
Создание функции для получения данных о таксономиях:
Напишите функцию, которая будет возвращать данные о соответствующих таксономиях для каждого из CPT. Эта функция должна возвращать ассоциативный массив, где ключ — это идентификатор CPT, а значение — массив соответствующих терминов.
function get_CPT_Dropdown_Data() { $data = []; // Получите все ваши CPT и их таксономии здесь // Пример: $cpts = get_posts(array('post_type' => 'formations', 'numberposts' => -1)); foreach ($cpts as $cpt) { $terms = get_the_terms($cpt->ID, 'sessions'); if ($terms) { foreach ($terms as $term) { $data[$cpt->ID][] = $term->name; } } } return $data; }
-
Локализация скриптов:
Теперь нужно зарегистрировать и локализовать ваш JavaScript файл, чтобы передать данные на клиентскую сторону.
function enqueue_my_scripts() { wp_register_script('general', get_template_directory_uri() . '/js/general.js'); wp_localize_script('general', 'myVars', array( 'dropdownData' => get_CPT_Dropdown_Data(), 'site_url' => site_url(), )); wp_enqueue_script('general'); } add_action('wp_enqueue_scripts', 'enqueue_my_scripts');
-
Изменение выпадающего списка с помощью JavaScript:
После того как данные будут переданы на клиентскую сторону, вы можете написать код, который будет отслеживать изменения чекбоксов и обновлять выпадающий список.
document.addEventListener('DOMContentLoaded', function() { const checkboxes = document.querySelectorAll('.btn-check'); const dropdown = document.getElementById('form-field-field_centre'); checkboxes.forEach(checkbox => { checkbox.addEventListener('change', function() { const selectedIds = Array.from(checkboxes) .filter(i => i.checked) .map(i => i.id); const terms = new Set(); selectedIds.forEach(id => { const termArray = myVars.dropdownData[id] || []; termArray.forEach(term => terms.add(term)); }); dropdown.innerHTML = '<option value="">Выберите сессию обучения</option>'; terms.forEach(term => { const option = document.createElement('option'); option.value = term; option.innerText = term; dropdown.appendChild(option); }); }); }); });
Подход 2: Использование AJAX
Этот подход более масштабируемый и позволяет вам получать данные только тогда, когда они действительно нужны, что особенно полезно, если ваш сайт имеет большой объем данных.
-
Создание AJAX-хука в WordPress:
Напишите функцию, которая будет обрабатывать AJAX-запросы и возвращать данные о таксономиях. Пример:
add_action('wp_ajax_get_terms_by_cpt', 'get_terms_by_cpt'); add_action('wp_ajax_nopriv_get_terms_by_cpt', 'get_terms_by_cpt'); function get_terms_by_cpt() { $cpt_id = intval($_POST['cpt_id']); // Получите ID CPT из запроса $terms = get_the_terms($cpt_id, 'sessions'); if (!empty($terms) && !is_wp_error($terms)) { $responsedata = []; foreach ($terms as $term) { $responsedata[] = $term->name; } wp_send_json_success($responsedata); } else { wp_send_json_error(); } }
-
Обновление JavaScript для обработки AJAX-запросов:
Вместо использования данных, заранее загруженных на страницу, ваш JavaScript будет делать AJAX-запросы при каждом изменении чекбокса.
document.addEventListener('DOMContentLoaded', function() { const checkboxes = document.querySelectorAll('.btn-check'); const dropdown = document.getElementById('form-field-field_centre'); checkboxes.forEach(checkbox => { checkbox.addEventListener('change', function() { const selectedIds = Array.from(checkboxes) .filter(i => i.checked) .map(i => i.id); // Очистка выпадающего списка dropdown.innerHTML = '<option value="">Выберите сессию обучения</option>'; // Выполнение AJAX-запроса для каждого выбранного чекбокса selectedIds.forEach(id => { jQuery.ajax({ url: myVars.site_url + '/wp-admin/admin-ajax.php', type: 'POST', data: { action: 'get_terms_by_cpt', cpt_id: id }, success: function(response) { if (response.success) { response.data.forEach(term => { const option = document.createElement('option'); option.value = term; option.innerText = term; dropdown.appendChild(option); }); } }, error: function(jqXHR, textStatus, errorThrown) { console.log('Ошибка на сервере:', errorThrown); } }); }); }); }); });
Заключение
Оба подхода имеют свои преимущества и недостатки. Если у вас небольшое количество данных и вы хотите упростить код, выберите первый подход. Для более крупных проектов и игнорирования избыточных данных рекомендуется использовать AJAX. Удачи в разработке вашего проекта!