如何从WP_QUERY重新排序(弹出和推送)项目?

时间:2015-12-02 作者:ReynierPM

我有一段代码:

$normal_args  = array(
    \'order\'               => \'desc\',
    \'ignore_sticky_posts\' => 1,
    \'meta_query\'          => array(
        array(
            \'key\'     => \'rw_show_at_position\',
            \'value\'   => \'1\',
            \'compare\' => \'=\'
        )
    ),
    \'post__not_in\'        => $prev_post_ids,
    \'post_status\'         => \'publish\',
    \'posts_per_page\'      => get_option( \'column_right\' ),
    \'post_type\'           => array(
        \'opinion\',
        \'especiales\',
        \'clasificados\',
        \'portadadeldia\',
        \'anunciantes\',
        \'post\',
        \'pages\',
        \'esp-publicitarios\'
    )
);

$normal_query = new WP_Query( $normal_args );

$i = 0;
if ( $normal_query->have_posts() ) {
    while ( $normal_query->have_posts() ) {
        $normal_query->the_post(); ?>

        <?php
        echo $i . \' ==> \';
        ?>

        <?php
        if ( get_post_type( $post->ID ) == \'esp-publicitarios\' ) {
            $adv_pos = rwmb_meta( \'rw_adversiting_position\', \'type=select\', $post->ID );
            echo $adv_pos . EOL;
        } else {
        ?>
            // do something here
        <?php
        }
        $i ++;
    }
}
我想根据post_type 和一个元键rw_adversiting_position 然后正常显示。现在我得到了这个结果:

0 ==> 183034 ==> 9
1 ==> 183033 ==> 6
2 ==> 183032 ==> 3
3 ==> 183002 ==>
4 ==> 182973 ==>
5 ==> 182971 ==>
6 ==> 182969 ==>
7 ==> 182999 ==>
8 ==> 182997 ==>
9 ==> 182995 ==>
10 ==> 182962 ==>
11 ==> 182948 ==>
那是因为只有0、1和2是esp-publicitarios 职位类型。右边9、6和3的数字是我应该推动项目的位置,因此有了这些信息,结果应该是这样的:

0 ==> 183002 ==>
1 ==> 182973 ==>
2 ==> 182971 ==>
2 ==> 183032 ==> 3
4 ==> 182969 ==>
5 ==> 182999 ==>
6 ==> 183033 ==> 6
7 ==> 182997 ==>
8 ==> 182995 ==>
9 ==> 183034 ==> 9
10 ==> 182962 ==>
11 ==> 182948 ==>
有谁能给我一些实现这一目标的想法吗?

UPDATE 1

我确实找到了this 但我不知道如何应用它。

UPDATE 2

这是实现排序的PHP代码,sort_position 可能是rw_adversiting_position:

$arr           = [
    \'183034\' => [ \'sort_position\' => 9 ],
    \'183033\' => [ \'sort_position\' => 5 ],
    \'183032\' => [ \'sort_position\' => 3 ],
    \'183002\' => [ ],
    \'182973\' => [ ],
    \'182971\' => [ ],
    \'182969\' => [ ],
    \'182999\' => [ ],
    \'182997\' => [ ],
    \'182995\' => [ ],
    \'182962\' => [ ],
    \'182948\' => [ ]
];

$count         = count( $arr );
$has_sortorder = [ ];
$no_sortorder  = [ ];
krsort( $arr );
foreach ( $arr as $key => $val ) {
    if ( isset( $val[\'sort_position\'] ) ) {
        $has_sortorder[ $val[\'sort_position\'] ] = [ $key, $val ];
    } else {
        $no_sortorder[] = [ $key, $val ];
    }
}


$out = [ ];
for ( $i = 0; $i < $count; $i ++ ) {
    if ( isset( $has_sortorder[ $i ] ) ) {
        $out[ $has_sortorder[ $i ][0] ] = $has_sortorder[ $i ][1];
    } else {
        $element            = array_shift( $no_sortorder );
        $out[ $element[0] ] = $element[1];
    }
}

var_dump( $out );
我只需要知道如何在得到结果之前将其应用于WP\\u查询,有吗?

UPDATE 3

以下是var_export($normal_query->posts) 正如您所看到的,没有元键,所以我可以根据元的值进行排序,然后如何排序?

$var = array(
    0 => WP_Post::__set_state( array(
        \'ID\'                    => 183034,
        \'post_author\'           => \'4\',
        \'post_date\'             => \'2015-12-01 16:44:35\',
        \'post_date_gmt\'         => \'2015-12-01 21:14:35\',
        \'post_content\'          => \'\',
        \'post_title\'            => \'Espacio Pub 3\',
        \'post_excerpt\'          => \'\',
        \'post_status\'           => \'publish\',
        \'comment_status\'        => \'closed\',
        \'ping_status\'           => \'closed\',
        \'post_password\'         => \'\',
        \'post_name\'             => \'espacio-pub-3\',
        \'to_ping\'               => \'\',
        \'pinged\'                => \'\',
        \'post_modified\'         => \'2015-12-01 16:54:38\',
        \'post_modified_gmt\'     => \'2015-12-01 21:24:38\',
        \'post_content_filtered\' => \'\',
        \'post_parent\'           => 0,
        \'guid\'                  => \'http://elclarinweb.local/?post_type=esp-publicitarios&p=183034\',
        \'menu_order\'            => 0,
        \'post_type\'             => \'esp-publicitarios\',
        \'post_mime_type\'        => \'\',
        \'comment_count\'         => \'0\',
        \'filter\'                => \'raw\',
    ) ),
    1 => WP_Post::__set_state( array(
        \'ID\'                    => 183033,
        \'post_author\'           => \'4\',
        \'post_date\'             => \'2015-12-01 16:44:13\',
        \'post_date_gmt\'         => \'2015-12-01 21:14:13\',
        \'post_content\'          => \'\',
        \'post_title\'            => \'Espacio Pub 2\',
        \'post_excerpt\'          => \'\',
        \'post_status\'           => \'publish\',
        \'comment_status\'        => \'closed\',
        \'ping_status\'           => \'closed\',
        \'post_password\'         => \'\',
        \'post_name\'             => \'183033\',
        \'to_ping\'               => \'\',
        \'pinged\'                => \'\',
        \'post_modified\'         => \'2015-12-01 16:44:21\',
        \'post_modified_gmt\'     => \'2015-12-01 21:14:21\',
        \'post_content_filtered\' => \'\',
        \'post_parent\'           => 0,
        \'guid\'                  => \'http://elclarinweb.local/?post_type=esp-publicitarios&p=183033\',
        \'menu_order\'            => 0,
        \'post_type\'             => \'esp-publicitarios\',
        \'post_mime_type\'        => \'\',
        \'comment_count\'         => \'0\',
        \'filter\'                => \'raw\',
    ) ),
    2 => WP_Post::__set_state( array(
        \'ID\'                    => 183032,
        \'post_author\'           => \'4\',
        \'post_date\'             => \'2015-12-01 15:53:56\',
        \'post_date_gmt\'         => \'2015-12-01 20:23:56\',
        \'post_content\'          => \'\',
        \'post_title\'            => \'Publicidad 1\',
        \'post_excerpt\'          => \'\',
        \'post_status\'           => \'publish\',
        \'comment_status\'        => \'closed\',
        \'ping_status\'           => \'closed\',
        \'post_password\'         => \'\',
        \'post_name\'             => \'publicidad-1\',
        \'to_ping\'               => \'\',
        \'pinged\'                => \'\',
        \'post_modified\'         => \'2015-12-01 15:53:56\',
        \'post_modified_gmt\'     => \'2015-12-01 20:23:56\',
        \'post_content_filtered\' => \'\',
        \'post_parent\'           => 0,
        \'guid\'                  => \'http://elclarinweb.local/?post_type=esp-publicitarios&p=183032\',
        \'menu_order\'            => 0,
        \'post_type\'             => \'esp-publicitarios\',
        \'post_mime_type\'        => \'\',
        \'comment_count\'         => \'0\',
        \'filter\'                => \'raw\',
    ) ),
    3 => WP_Post::__set_state( array(
            \'ID\'                    => 183002,
            \'post_author\'           => \'7\',
            \'post_date\'             => \'2015-11-22 00:08:00\',
            \'post_date_gmt\'         => \'2015-11-22 04:38:00\',
            \'post_content\'          => \'Borrón y cuenta nueva es lo que han hecho los Bravos de Margarita en este comienzo de la segunda parte de la campaña, en la que ayer sumaron su cuarto triunfo seguido, al vencer a los Tiburones de La Guaira 5 carreras por 3. Margarita, que ganó dos de tres ante los escualos en la semana, madrugó al dominicano Alexis Candelario, quien llegó a dicha cita como el mejor lanzador del campeonato. Los artilleros isleños fabricaron cuatro de sus cinco carreras en las primeras dos entradas, catapultados por un doble impulsor de dos de Eliézer Alfonzo. “No importa quién esté en la lomita contraria, siempre que los muchachos crean en ellos mismos, estos van a ser los resultados”, señaló el dirigente Henry Blanco. Bravos se haría presente en el marcador una vez más en el sexto con doble remolcador del jardinero Junior Sosa y aguantaría un intento de remontada de los litoralenses en la parte final para sellar el lauro. “La mentalidad que tenemos es no pensar en la primera parte, hay que salir a ganar”, indicó Alfonzo, quien cerró el cotejo de 5-2 con un par de impulsadas y ahora acumula cinco rayitas traídas al plato en los últimos dos desafíos. “Estaba bastante perdido cuando comenzó la temporada, pero he hecho el ajuste necesario”.\',
            \'post_title\'            => \'Ahora Bravos es puntero de la LVBP\',
            \'post_excerpt\'          => \'Las curiosidades del nuevo sistema de puntos del torneo coloca al antiguo colero de puntero\',
            \'post_status\'           => \'publish\',
            \'comment_status\'        => \'open\',
            \'ping_status\'           => \'open\',
            \'post_password\'         => \'\',
            \'post_name\'             => \'ahora-bravos-es-puntero-de-la-lvbp\',
            \'to_ping\'               => \'\',
            \'pinged\'                => \'\',
            \'post_modified\'         => \'2015-11-22 00:08:00\',
            \'post_modified_gmt\'     => \'2015-11-22 04:38:00\',
            \'post_content_filtered\' => \'\',
            \'post_parent\'           => 0,
            \'guid\'                  => \'http://elclarinweb.local/?p=183002\',
            \'menu_order\'            => 0,
            \'post_type\'             => \'post\',
            \'post_mime_type\'        => \'\',
            \'comment_count\'         => \'0\',
            \'filter\'                => \'raw\'
        )
    )
);

UPDATE 4

@bosco我对您的代码进行了一些次要更改,现在看起来如下所示:

function wpse_210493_apply_advertising_position( &$posts, $return = false ) {
    $ad_posts = array();

    // Seperate $posts into "Ads" and "Content" arrays based on whether or not they have \'rw_adversiting_position\' meta-data
    foreach ( $posts as $post ) {
        $position      = intval( get_post_meta( $post->ID, \'rw_adversiting_position\', true ) );
        $post_date     = $post->post_date;
        $post_modified = $post->post_modified;

        if ( ! empty( $position ) ) {
            if ( ! empty ( $ad_posts ) ) {
                if ( $post_date > $ad_posts[ $position ]->post_date || $post_modified > $ad_posts[ $position ]->post_modified ) {
                    $ad_posts[ $position ] = $post;
                }
            } else {
                $ad_posts[ $position ] = $post;
            }
        } else {
            $content_posts[] = $post;
        }
    }

    // Sort the ads from smallest position index to greatest such that re-insertion properly factors in all ads
    ksort( $ad_posts );

    // Add the ads back into the content at their specified positions
    foreach ( $ad_posts as $position => $ad ) {
        array_splice( $content_posts, $position, 0, array( $ad ) );
    }

    // If $return is true, return the resulting array. Otherwise replace the original $posts array with it.
    if ( $return ) {
        return $content_posts;
    } else {
        $posts = $content_posts;
    }
}
如果在模板上对此进行调试,则会得到以下输出:

echo \'<pre> BEFORE\';
echo count($normal_query->posts);
echo \'</pre>\';

wpse_210493_apply_advertising_position( $normal_query->posts );

echo \'<pre> AFTER\';
echo count($normal_query->posts);
echo \'</pre>\';

// Output
BEFORE25
AFTER23
AFTER是正确的值,但循环使用BEFORE并添加到循环上的空元素,为什么?看见this pic 了解更多信息。

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

您可以使用Metadata API 要检索rw_advertising_position 每个帖子的元数据,将广告与内容分开,然后在适当的位置重新插入广告:

/**
 * Extracts from an array posts with positional metadata and re-inserts them at the proper
 * indices. See https://wordpress.stackexchange.com/questions/210493
 **/
function wpse_210493_apply_advertising_position( &$posts, $return = false ) {
    $ad_posts      = array();
    $content_posts = array();

    // Seperate $posts into "Ads" and "Content" arrays based on whether or not they have \'rw_adversiting_position\' meta-data    
    foreach( $posts as $post ) {
        $position = get_post_meta( $post->ID, \'rw_adversiting_position\', true );

        if( ! empty( $position ) )
            $ad_posts[ intval( $position ) ] = $post;
        else
            $content_posts[] = $post;  
    }

    // Sort the ads from smallest position index to greatest such that re-insertion properly factors in all ads
    ksort( $ad_posts );

    // Add the ads back into the content at their specified positions
    foreach( $ad_posts as $position => $ad ) {
        array_splice( $content_posts, $position, 0, array( $ad ) );
    }

    // If $return is true, return the resulting array. Otherwise replace the original $posts array with it.
    if( $return )
        return $content_posts;
    else
        $posts = $content_posts;
}
免责声明在上述示例中,我指定了一个函数参数&$posts 指示PHP使用pass-by-reference 传递给函数的参数的求值策略$posts. 这意味着,不是引用作为第一个参数传递的数据的本地范围副本,而是$posts 变量将引用内存中原始位置的数据。

在这里,我使用这种机制提供了(默认)选项来直接重新排列post对象数组,而无需处理返回值。函数本身只是对数组进行排序,我选择通过引用传递数组参数,以便提供与all 12 of PHP\'s array sorting functions.

@Andrei Gheorghiu 在评论中指出,如果你不熟悉这种做法,通过引用传递可能会产生意想不到的结果。在这种情况下,您可能希望避开它,这可以通过设置$return 示例中的参数为true, 或者完全安全remove the option entirely as Andrei has.

在模板中:

// [...]
$normal_query = new WP_Query( $normal_args );

wpse_210493_apply_advertising_position( $normal_query->posts );

if ( $normal_query->have_posts() ) {
// [...]
我还没有测试该代码-它只是为了说明目的。

或者,单独使用第二个查询来检索广告可能会更好一些。

SO网友:tao

这是的修订版本bosco\'s 回答哪个does answer the question 但通过允许直接修改查询属性,增加了太多的灵活性,我个人认为这是一种不好的做法。

function wpse_210493_apply_advertising_position( $posts ) {
    $ad_posts      = array();
    $content_posts = array();

    // Seperate $posts into "Ads" and "Content" arrays based on whether or not they have \'rw_adversiting_position\' meta-data    
    foreach( $posts as $post ) {
        $position = get_post_meta( $post->ID, \'rw_adversiting_position\', true );

        if( ! empty( $position ) )
            $ad_posts[ intval( $position ) ] = $post;
        else
            $content_posts[] = $post;  
    }

    // Sort the ads from smallest position index to greatest such that re-insertion properly factors in all ads
    ksort( $ad_posts );

    // Add the ads back into the content at their specified positions
    foreach( $ad_posts as $position => $ad ) {
        array_splice( $content_posts, $position, 0, array( $ad ) );
    }

    return $content_posts;
}
运行过滤器后,我们检查是否返回了任何帖子,如果是,我们在foreach 这将输出我们的结果:

$normal_query = new WP_Query( $normal_args );

$filtered_posts = wpse_210493_apply_advertising_position( $normal_query->posts );

if ( count($filtered_posts) ) :
    foreach ($filtered_posts as $post) :
        setup_postdata($post);
        /* run any functions available in WP loop here 
         * (the_title(), the_content(), etc...)
         *
         */
    endforeach;
    wp_reset_postdata();
endif;

相关推荐

GET_POSTS在页面模板中工作,但不在短码中工作

我正在尝试编写一个短代码,其中包括“get\\u posts”,以便获取博客帖子数据,然后在页面上显示最近的3篇文章。此代码在模板中工作。然而,当我将其放入输出缓冲区(ob\\u start)内的短代码中时,它无法检索帖子。相反,它会获取当前页面本身并循环浏览该页面(在本例中为主页)。你知道我怎样才能让它按照最初的意图在帖子中循环吗?以下是在模板中工作的代码:<?php $lastposts = get_posts( array(\'posts_per_page\' => 3) );?>