You could use the Metadata API to retrieve the rw_advertising_position
metadata for each post, seperate the ads from the content, and then re-insert the ads at the proper locations:
/**
* 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;
}
DISCLAIMER
In the example above, I specify a function parameter
&$posts
which instructs PHP to use a pass-by-reference evaluation strategy for the argument passed to the function as$posts
. This means that instead of referring to a locally-scoped copy of the data passed as the first argument, the$posts
variable will refer to the data at it’s original place in memory.Here I’ve used this mechanism to provide the (default) option to directly re-arrange an array of post objects without needing to handle a return value. The function itself merely sorting an array, I choose to pass the array argument by reference in order to provide behavior more consistent with all 12 of PHP’s array sorting functions.
As @Andrei Gheorghiu points out in the comments, passing by reference can produce unexpected results if you’re unfamiliar with the practice. In such a scenario you may wish to steer clear of it which can be done by setting the
$return
argument in the example totrue
, or to be completely safe remove the option entirely as Andrei has.
In your template:
// [...]
$normal_query = new WP_Query( $normal_args );
wpse_210493_apply_advertising_position( $normal_query->posts );
if ( $normal_query->have_posts() ) {
// [...]
I haven’t tested that code – it’s just for illustrative purposes.
Alternately, using a second query to retrieve the ads alone might work a little better.