在循环/自定义查询中每隔n个位置插入小部件

时间:2015-11-30 作者:physalis

基本挑战:我有一个“正常”的自定义查询,例如来自某个类别的新闻帖子,并希望在每个第n个位置添加几个元素(一般来说是cta),而当存在的新闻帖子超过cta\\U元素所能填充的数量时,cta\\U元素的循环(见下文)会重复。下面的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\\U元素元素可以在每第n个位置填充,这些元素就会重复(参见上面的示例)。

理想情况下,cta\\U元素将是来自自定义小部件区域的小部件,因此用户可以添加a)向要插入的cta\\U元素列表中添加不同类型的预定义“小部件”,b)根据他们的意愿通过简单的拖放对它们进行排序,c)可以为不同的循环使用不同的小部件区域,例如首页cta、存档页cta、作者存档页cta。

或者,您也可以发布复杂的小部件,这些小部件可能引入并使用自定义的帖子类型(并使用类别以便在不同的归档页面上有不同的循环)。

有没有简单的方法来解决这个问题?如果这个问题本身太复杂,应该细分为几个问题,请原谅。我仍然想找到最方便和有效的方法来解决这个问题。

4 个回复
最合适的回答,由SO网友:physalis 整理而成

对于任何对类似事物感兴趣的人来说,这就是一位职业选手的想法,它是1。为我的小部件插入注册一个特定的侧栏,2。以HTML字符串和3的形式从侧栏获取DOM节点。将其放在一起,同时循环使用可用的小部件。

把这个放进你的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, e.g. "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小部件时,我遇到了一些小问题,但除此之外,它似乎工作得很好。

SO网友:jgraup

如果你能得到你文章的索引,那么利用% 对于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

SO网友:Michelle

我会选择自定义帖子类型/自定义分类法路线。然后,您可以使用for/each循环设置归档文件,以统计帖子的数量,并从相关的CPT/分类查询中插入CTA。

我找到了插件Intuitive Custom Post Order 对这种事情很有效;您可以告诉用户按照他们想要组织的CTA组分类法过滤CTA,然后按照他们想要的顺序拖放CTA。只需确保您的CPT查询是按menu\\u order和voila排序的。

SO网友:Carlos Faria

像这样的东西怎么样?

<?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);

相关推荐

如何读取WordPress$Query关联数组(散列)键的值

WordPress编程新手(来自更为传统的环境),并试图了解其一些“独特”特性。我们的网站上有一个目录页,此代码驻留在functions.php, 如果条件为true,则调整结果。if( $query->is_post_type_archive( \'directory\' ) ){ ...//do stuff } 我想知道如何获取is_post_type_archive 这就是“目录”当我对值使用测试时。。。var_dumb($query->is_post