The offset
parameter is ignored with posts_per_page
set to -1
in WP_Query
. If you look at the source code in the WP_Query
class, posts_per_page=-1
sets nopaging
to true.
if ( !isset($q['nopaging']) ) {
if ( $q['posts_per_page'] == -1 ) {
$q['nopaging'] = true;
} else {
$q['nopaging'] = false;
}
}
This in turn will not append the LIMIT
to the SQL query (empty($q['nopaging'] === false
which fail the conditional statement) meaning that the whole pagination/offset is ignored and all posts are returned regardless
if ( empty($q['nopaging']) && !$this->is_singular ) {
$page = absint($q['paged']);
if ( !$page )
$page = 1;
if ( empty($q['offset']) ) {
$pgstrt = absint( ( $page - 1 ) * $q['posts_per_page'] ) . ', ';
} else { // we're ignoring $page and using 'offset'
$q['offset'] = absint($q['offset']);
$pgstrt = $q['offset'] . ', ';
}
$limits="LIMIT " . $pgstrt . $q['posts_per_page'];
}
I think the best workaround here is to make use of normal PHP (array_slice()
)after getting all the posts. You want to get only post ID’s here as wp_delete_post
is quite expensive to run and only really need the post ID, so we don’t need any other post info.
In short, your query will look like this: (NOTE: This is all untested and needs PHP 5.4+)
add_action( 'publish_post', function ( $post_ID )
{
$args = [
'nopaging' => true,
'fields' => 'ids'
];
$posts_array = get_posts( $args );
// Make sure that we have post ID's returned
if ( $posts_array ) {
// Get all post ids after the 10th post using array_slice
$delete_posts = array_slice( $posts_array, 10 );
// Make sure that we actually have post ID's in the $delete_posts array
if ( $delete_posts ) {
foreach ( $delete_posts as $delete_post )
wp_delete_post( $delete_post, true );
}
}
});
EDIT
Just before I forget, you can also define posts_per_page
as an unlikely integer value instead of -1
. This will also work with your code with the offset
parameter set