it-swarm.com.de

Wie kann ich Elemente aus WP_Query neu anordnen (Pop und Push)?

Ich habe diesen Code:

$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 ++;
    }
}

Und ich möchte Elemente basierend auf post_type und einem metakey rw_adversiting_position neu anordnen und sie dann normal anzeigen. Im Moment erhalte ich dieses Ergebnis:

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 ==>

Das liegt daran, dass nur 0, 1 und 2 esp-publicitarios Beitragstypen sind. Die Zahl auf der rechten Seite 9, 6 und 3 ist die Position, an der ich den Artikel verschieben soll. Wenn Sie diese Informationen haben, sollte das Ergebnis ungefähr so ​​aussehen:

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 ==>

Kann mir jemand einige Ideen geben, um dies zu erreichen?

UPDATE 1

Ich habe dies gefunden, bin mir aber nicht sicher, wie ich es anwenden soll.

UPDATE 2

Dies ist der PHP Code für die Sortierung, sort_position könnte rw_adversiting_position sein:

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

Ich muss nur wissen, wie ich dies auf WP_Query anwenden kann, bevor ich das Ergebnis erhalte.

UPDATE 3

Hier ist ein Ausschnitt aus var_export($normal_query->posts), wie Sie sehen, gibt es keinen Metaschlüssel, so dass ich basierend auf den Werten eines Metas bestellen kann. Wie dann?

$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 Ich habe einige kleinere Änderungen an Ihrem Code vorgenommen und jetzt sieht es so aus:

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;
    }
}

Wenn ich dies auf der Vorlage debugge, erhalte ich die folgende Ausgabe:

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 ist der richtige Wert, aber die Schleife verwendet BEFORE und fügt leere Elemente in der Schleife hinzu. Warum? Siehe dieses Bild für weitere Informationen.

3
ReynierPM

Sie können die Metadaten-API verwenden, um die rw_advertising_position-Metadaten für jeden Beitrag abzurufen, die Anzeigen vom Inhalt zu trennen und die Anzeigen an den richtigen Stellen erneut einzufügen:

/**
 * 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;
}

HAFTUNGSAUSSCHLUSS

Im obigen Beispiel gebe ich einen Funktionsparameter &$posts an, der PHP anweist, eine Referenzübergabe Auswertungsstrategie für das an die Funktion übergebene Argument als $posts zu verwenden. Dies bedeutet, dass sich die Variable $posts nicht auf eine lokal begrenzte Kopie der als erstes Argument übergebenen Daten bezieht, sondern auf die Daten an ihrem ursprünglichen Speicherort .

Hier habe ich diesen Mechanismus verwendet, um die (Standard-) Option bereitzustellen, mit der ein Array von Post-Objekten direkt neu angeordnet werden kann, ohne dass ein Rückgabewert verarbeitet werden muss. Da die Funktion selbst lediglich ein Array sortiert, entscheide ich mich, das Array-Argument als Referenz zu übergeben, um ein konsistenteres Verhalten mit allen 12 PHP-Array-Sortierfunktionen zu erzielen.

Wie @Andrei Gheorghiu in den Kommentaren ausführt, kann das Übergeben von Referenzen zu unerwarteten Ergebnissen führen, wenn Sie mit der Praxis nicht vertraut sind. In einem solchen Szenario möchten Sie sich vielleicht davon fernhalten, indem Sie das Argument $return im Beispiel auf true setzen, oder ganz sicher sein, die Option ganz entfernen, wie es Andrei getan hat .

In Ihrer Vorlage:

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

wpse_210493_apply_advertising_position( $normal_query->posts );

if ( $normal_query->have_posts() ) {
// [...]

Ich habe diesen Code nicht getestet - er dient nur zur Veranschaulichung.

Alternativ könnte die Verwendung einer zweiten Abfrage zum Abrufen der Anzeigen allein etwas besser funktionieren.

3
bosco

Dies ist eine überarbeitete Version von Boscos Antwort, die die Frage beantwortet , aber zu viel Flexibilität hinzufügt, indem sie die direkte Änderung von Abfrageeigenschaften ermöglicht, die ich persönlich als schlechte Praxis betrachte.

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;
}

Nachdem wir den Filter ausgeführt haben, prüfen wir, ob Beiträge zurückgegeben wurden. In diesem Fall verwenden wir sie in einer foreach, die unser Ergebnis ausgibt:

$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;
1