Вставка виджетов в цикл / пользовательский запрос на каждой n-й позиции

Основная задача: у меня есть «обычный» пользовательский запрос, например, сообщения новостей из определенной категории и вы хотите добавить несколько элементов (CTA, вообще говоря) на каждой n-й позиции, в то время как цикл cta_elements (см. Ниже) повторяется, когда существует больше сообщений новостей, чем может заполнить cta_elements. Пример HTML ниже, с элементом CTA после каждого четвертого (новостного) сообщения:

<div class="news_list"> <div class="news_item"></div> <div class="news_item"></div> <div class="news_item"></div> <div class="news_item"></div> <div class="cta_element" id="cta_1">Some different content</div> <div class="news_item"></div> <div class="news_item"></div> <div class="news_item"></div> <div class="news_item"></div> <div class="cta_element" id="cta_2">Some different content</div> <div class="news_item"></div> <div class="news_item"></div> <div class="news_item"></div> <div class="news_item"></div> <div class="cta_element" id="cta_3">Some different content</div> <div class="news_item"></div> <div class="news_item"></div> <div class="news_item"></div> <div class="news_item"></div> <!-- 1st CTA again, since there are only 3 CTAs, but more posts in news query. --> <div class="cta_element" id="cta_1">Some different content</div> ... </div> 

Это означает, что запрос должен быть «приостановлен», чтобы вставлять отдельные элементы другого типа / цикла (вообще говоря), которые сами повторяются, когда не хватает элементов cta_elements, которые могут заполняться на каждой последующей n-й позиции ( см. пример выше).

В идеале, cta_elements будут виджетами из пользовательской области виджетов, поэтому пользователь может добавить: a) добавить различные виды предопределенных «виджетов» в список вставленных cta_elements и b) упорядочить их в соответствии с их пожеланиями с помощью простого перетаскивания ' n'drop и c) могут иметь разные области виджетов для разных циклов, например, CTA на первой странице, CTA страниц архива, CAST-страницы архива авторов.

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

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

Если вы можете получить индекс своего сообщения, тогда используйте % для разрывов CTA.

 <?php // Your CTA Content $cta_array = array( "Some different content 1", "Some different content ABC", "Some different content XYZ", ); $cta_inx = 0; // index $cta_len = count($cta_array); // max $cta_interval = 5; // breaks every x posts // Query $args = array( 'posts_per_page' => 25, 'post_type' => 'post', 'post_status' => 'publish', 'suppress_filters' => true ); $posts_array = get_posts( $args ); // LOOP ?><div class="news_list"><?php // news_list START foreach ($posts_array as $inx => $post ){ // News Item ?><div class="news_item"><?php echo $post->post_title; ?></div><?php // CTA if( $inx && ! ( $inx % $cta_interval )) { if( $cta_inx == $cta_len) $cta_inx = 0; // reset the index ?><div class="cta_element" id="cta_<?php echo $cta_inx; ?>"><?php echo $cta_array[$cta_inx]; ?></div><?php $cta_inx ++; // advance the cta } } ?></div><?php // news_list END 

Это должно выводить:

 > Post Title > Post Title > Post Title > Post Title > Post Title Some different content 1 > Post Title > Post Title > Post Title > Post Title > Post Title Some different content ABC > Post Title > Post Title > Post Title > Post Title > Post Title Some different content XYZ > Post Title > Post Title > Post Title > Post Title > Post Title Some different content 1 > Post Title > Post Title > Post Title > Post Title > Post Title Some different content ABC > Post Title > Post Title > Post Title > Post Title > Post Title Some different content XYZ 

Я бы пошел по типу пользовательских сообщений / пользовательской таксономии. Затем вы можете настроить свои архивы с помощью цикла for / each, чтобы подсчитать количество сообщений и вставить CTA из соответствующего запроса CPT / таксономии.

Я нашел плагин Интуитивный пользовательский почтовый заказ хорошо работает для такого рода вещей; вы можете сообщить своим пользователям о фильтрации CTA по таксономии CTA-группы, которую они хотят организовать, а затем перетащить CTA в желаемый порядок. Просто убедитесь, что ваш запрос CPT упорядочен по menu_order и voila.

А как насчет этого?

 <?php $max_posts = get_option('posts_per_page '); ?> <?php global $paged; ?> //Get $paged to have a good pagination index <?php if ( get_query_var('paged') ) { $paged = get_query_var('paged'); } elseif ( get_query_var('page') ) { $paged = get_query_var('page'); } else { $paged = 1; } ?> //Max news per block <?php $num_news = 4; ?> //First 4 news <section class="news"> <?php $args = array('posts_per_page' => $max_posts, 'paged' => $paged ); ?> <?php $cont = 0; ?> <?php $query = new WP_Query( $args ); ?> <?php if ( $query->have_posts() ) : ?> <?php while ( $query->have_posts() ) : $query->the_post(); ?> <article class="news_item"> Your code here </article> <?php if($cont++ >= $num_news) break; //Only 4 posts/news in this block ?> <?php endwhile ?> <?php endif; ?> </section> //After break I show the first widget area <div class="cta_element" id="cta_1">Your widget area 1</div> //Second loop, another 4 items... <?php if ( $query->have_posts() ) : ?> <?php $cont = 0; ?> <section class="news"> <?php while ( $query->have_posts() ) : $query->the_post(); ?> <article class="news_item"> Your code here </article> <?php if($cont++ >= $num_news) break; //Only 4 posts/news in this block ?> <?php endwhile ?> </section> <?php endif; ?> //Second widget area <div class="cta_element" id="cta_1">Your widget area 1</div> 

Изменить: для получения определенного виджета на боковой панели. Не слишком чистый, но я думаю, что он должен работать.

 <?php function get_widget_from_sidebar($sidebar,$widget_index){ ob_start(); $widgets = dynamic_sidebar($sidebar); if($widgets){ $html = ob_get_contents(); $widgets_array = explode("<li",$html); ob_end_clean(); return $widgets_array[$widget_index]; } return ""; } //Call the function like this echo get_widget_from_sidebar('id_of_sidebar', $cont); 

Для всех, кто интересуется чем-то подобным, это то, что сделал парень-профессионал, это 1. регистрация конкретной боковой панели для моей вставки виджета, 2. получение узла DOM с боковой панели в виде строки HTML и 3. объединение ее во время цикла через доступные виджеты.

Поместите это в свои functions.php :

 // Register sidebar for repeated widgets function register_custom_sidebar() { register_sidebar(array( 'name' => "CTAs — Home", 'id' => 'widgets_home', 'description' => "Widgets will be displayed after every 3rd post", 'before_widget' => '<li id="%1$s" class="widget %2$s">', 'after_widget' => '</li>', 'before_title' => '<h2 class="widgettitle">', 'after_title' => '</h2>', )); } add_action('widgets_init', 'register_custom_sidebar'); // Return dom node from other document as html string function return_dom_node_as_html($element) { $newdoc = new DOMDocument(); $newdoc->appendChild($newdoc->importNode($element, TRUE)); return $newdoc->saveHTML(); } 

Затем создайте или адаптируйте шаблон (например, шаблон страницы, как в этом примере, независимо от того, что работает для вас) со следующим:

 <?php /* Template Name: My CTA loop page * */ get_header(); ?> <div id="primary" class="content-area"> <main id="main" class="site-main" role="main"> <?php while (have_posts()) : the_post(); ?> <?php // Your custom query $args = [ "post_type" => "post", "posts_per_page" => "-1" ]; $custom_posts = new WP_Query($args); // Catch output of sidebar in string ob_start(); dynamic_sidebar("widgets_home"); $sidebar_output = ob_get_clean(); // Create DOMDocument with string (and set encoding to utf-8) $dom = new DOMDocument; $dom->loadHTML('<?xml encoding="utf-8" ?>' . $sidebar_output); // Get IDs of the elements in your sidebar, eg "text-2" global $_wp_sidebars_widgets; $sidebar_element_ids = $_wp_sidebars_widgets["widgets_home"]; // Use ID of your sidebar // Save single widgets as html string in array $sidebar_elements = []; foreach ($sidebar_element_ids as $sidebar_element_id): // Get widget by ID $element = $dom->getElementById($sidebar_element_id); // Convert it to string (function return_dom_node_as_html() must be in functions.php) $sidebar_elements[] = return_dom_node_as_html($element); endforeach; $widget_intervall = 3; // After how many post a widget appears $post_count = 0; $element_count = 0; while ($custom_posts->have_posts()): $custom_posts->the_post(); echo "<p>" . the_title() . "</p>"; // Whatever you want to display from your news posts (= main loop) $post_count++; if (!empty($sidebar_elements) && $post_count % $widget_intervall === 0): // Echo the widget echo $sidebar_elements[$element_count]; $element_count++; // Restart after the last widget if ($element_count == count($sidebar_elements)): $element_count = 0; endif; endif; endwhile; wp_reset_postdata(); ?> <?php // If comments are open or we have at least one comment, load up the comment template if (comments_open() || get_comments_number()) : comments_template(); endif; ?> <?php endwhile; // end of the loop. ?> </main><!-- #main --> </div><!-- #primary --> <?php get_sidebar(); ?> <?php get_footer(); ?> 

У меня были некоторые незначительные проблемы с RSS-виджетами, когда я вставлял его без данных, но, кроме того, он работает нормально.