Skip to content

Commit

Permalink
Merge pull request #45 from alleyinteractive/post-status-any
Browse files Browse the repository at this point in the history
Include archiveless posts in a post_status any query
  • Loading branch information
srtfisher committed Oct 7, 2022
2 parents 8229a76 + 1aabf23 commit 28f649c
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 23 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

All notable changes to this plugin will be documented in this file.

## 1.0.1

- Bug fix from previous use of the archiveless plugin that broke backwards
compatibility: only include archiveless posts when no `post_status` is
specified for the query. For `get_posts()` calls, this means that archiveless
posts will never be included by default since `get_posts()` sets a default
post status. To include archiveless posts with `get_posts()`, you can include
`archiveless` in the `post_status` or pass `include_archiveless` set to `true.
- Introduces `include_archiveless` query paramater.

## 1.0.0

- Initial release
35 changes: 30 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,17 @@ older content that shouldn't appear in search results because it is untimely.

## Usage

By default, the plugin will prevent archiveless posts from appearing on page.
This is limited to the [main
By default, the plugin will prevent archiveless posts from appearing on the page. This is limited to the [main
query](https://developer.wordpress.org/reference/functions/is_main_query/) of
the page. It will not affect other queries by default.

Archiveless posts can be excluded from normal queries by passing
`exclude_archiveless`:

```php
// Via get_posts()/WP_Query.
$posts = get_posts(
$query = new WP_Query(
[
'exclude_archiveless' => true,
'suppress_filters' => false,
// ...
]
);
Expand All @@ -46,6 +43,34 @@ add_action(
);
```

### Handling archiveless posts with `get_posts()` calls

Queries made with `get_posts()` will always exclude archiveless posts by default
since `get_posts()` sets a default `post_status` of `publish`. To include
archiveless posts, you can specify the `post_status` of `any`, declare the
`post_status` explicitly with `[ 'publish', 'archiveless' ]`, or pass
`include_archiveless` set to true:

```php
// $post_ids will include archiveless posts.
$post_ids = get_posts(
[
'fields' => 'ids',
'include_archiveless' => true,
'suppress_filters' => false,
]
);

// Or declare the post_status explicitly.
$post_ids = get_posts(
[
'fields' => 'ids',
'suppress_filters' => false,
'post_status' => [ 'archiveless', 'publish' ],
]
);
```

### Install

The plugin includes uncompiled Javascript. You can install the plugin by
Expand Down
40 changes: 30 additions & 10 deletions inc/class-archiveless.php
Original file line number Diff line number Diff line change
Expand Up @@ -330,13 +330,22 @@ public function on_pre_get_posts( $query ) {
return;
}

// Don't modify the query if the post_status is set. A status of 'any'
// or 'publish' is ignored since get_post() sets 'publish' as the
// default post_status value when not defined.
/**
* Don't modify the query if the post_status is set.
*
* A `post_status` of 'any' is ignored since we need to include archiveless
* posts because the post_status will be excluded by default (the post
* status is set to be excluded from search).
*
* `get_posts()` will set a default `post_status` of `publish` that is
* respected. To include archiveless posts, set `post_status` to
* `['publish', 'archiveless']` or pass `include_archiveless` as true.
*/
if (
! empty( $query->get( 'post_status' ) )
&& 'any' !== $query->get( 'post_status' )
&& 'publish' !== $query->get( 'post_status' )
&& ! isset( $query->query_vars['include_archiveless'] )
&& ! isset( $query->query_vars['exclude_archiveless'] )
) {
return;
}
Expand All @@ -348,6 +357,7 @@ public function on_pre_get_posts( $query ) {
if (
( $query->is_main_query() && $query->is_singular() )
|| ( ! $query->is_main_query() && ! $query->get( 'exclude_archiveless' ) )
|| $query->get( 'include_archiveless' )
) {
$query->set(
'post_status',
Expand All @@ -370,14 +380,24 @@ public function on_pre_get_posts( $query ) {
* @return string[]
*/
public function get_default_post_statuses( $query ) {
return array_keys(
get_post_stati(
[
'exclude_from_search' => false,
'publicly_queryable' => true,
]
$post_statuses = $query->get( 'post_status', [] );

if ( ! is_array( $post_statuses ) ) {
$post_statuses = explode( ',', $post_statuses );
}

$post_statuses = array_merge(
$post_statuses,
array_keys(
get_post_stati(
[
'exclude_from_search' => false,
]
)
)
);

return array_values( array_unique( $post_statuses ) );
}

/**
Expand Down
157 changes: 149 additions & 8 deletions tests/test-general.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,19 @@ class Test_General extends Test_Case {

protected $archiveable_post;

protected $archiveable_post_custom_status;

protected function setUp(): void {
parent::setUp();

$category_id = $this->factory->term->create(
$category_id = static::factory()->term->create(
[
'taxonomy' => 'category',
'name' => 'archives',
]
);

$author_id = $this->factory->user->create(
$author_id = static::factory()->user->create(
[
'role' => 'author',
'user_login' => 'test_author',
Expand All @@ -45,7 +47,7 @@ protected function setUp(): void {
'post_content' => 'Lorem ipsum',
];

$this->archiveless_post = $this->factory->post->create(
$this->archiveless_post = static::factory()->post->create(
array_merge(
$defaults,
[
Expand All @@ -54,7 +56,8 @@ protected function setUp(): void {
]
)
);
$this->archiveable_post = $this->factory->post->create(

$this->archiveable_post = static::factory()->post->create(
array_merge(
$defaults,
[
Expand All @@ -63,6 +66,22 @@ protected function setUp(): void {
]
)
);

// Register another custom post status that is public.
register_post_status(
'other-public-status',
[
'public' => true,
'exclude_from_search' => false,
]
);

$this->archiveable_post_custom_status = static::factory()->post->create(
[
'post_title' => 'Test Archiveless Post',
'post_status' => 'other-public-status',
]
);
}

public function test_verify_post_status_exists() {
Expand Down Expand Up @@ -91,12 +110,85 @@ public function test_archiveless_is_method() {
$this->assertFalse( Archiveless::is( get_post( $this->archiveable_post ) ) );
}

public function test_always_included_outside_of_main_query() {
public function test_always_included_outside_of_main_query_by_default_with_wp_query() {
$post_ids = $this->query(
[
'fields' => 'ids',
'posts_per_page' => -1,
'suppress_filters' => false,
]
);

$this->assertContains( $this->archiveless_post, $post_ids );
$this->assertContains( $this->archiveable_post, $post_ids );
}

/**
* Test that archiveless posts are included in get_posts() calls by default.
* get_posts() sets a default post_status argument of 'publish'.
*/
public function test_not_included_with_get_posts_by_default() {
$post_ids = get_posts(
[
'fields' => 'ids',
'posts_per_page' => -1,
'suppress_filters' => false,
]
);

$this->assertNotContains( $this->archiveless_post, $post_ids );
$this->assertContains( $this->archiveable_post, $post_ids );
}

public function test_always_included_outside_of_main_query_with_post_status_publish_with_get_posts_and_post_statuses() {
$post_ids = get_posts(
[
'fields' => 'ids',
'post_status' => [ 'archiveless', 'publish' ],
'posts_per_page' => -1,
'suppress_filters' => false,
]
);

$this->assertContains( $this->archiveless_post, $post_ids );
$this->assertContains( $this->archiveable_post, $post_ids );
}

public function test_always_included_outside_of_main_query_with_post_status_publish_with_get_posts_and_include_archiveless() {
$post_ids = get_posts(
[
'fields' => 'ids',
'include_archiveless' => true,
'posts_per_page' => -1,
'suppress_filters' => false,
]
);

$this->assertContains( $this->archiveless_post, $post_ids );
$this->assertContains( $this->archiveable_post, $post_ids );
}

public function test_always_included_outside_of_main_query_with_post_status_any_with_wp_query() {
$post_ids = $this->query(
[
'fields' => 'ids',
'posts_per_page' => 100,
'suppress_filters' => false,
'post_status' => 'any',
]
);

$this->assertContains( $this->archiveless_post, $post_ids );
$this->assertContains( $this->archiveable_post, $post_ids );
}

public function test_always_included_outside_of_main_query_with_post_status_any_with_get_posts() {
$post_ids = get_posts(
[
'fields' => 'ids',
'posts_per_page' => 100,
'suppress_filters' => false,
'post_status' => 'any',
]
);

Expand All @@ -105,7 +197,7 @@ public function test_always_included_outside_of_main_query() {
}

public function test_query_archiveless_posts_only() {
$post_ids = get_posts(
$post_ids = $this->query(
[
'fields' => 'ids',
'post_status' => 'archiveless',
Expand All @@ -118,8 +210,8 @@ public function test_query_archiveless_posts_only() {
$this->assertNotContains( $this->archiveable_post, $post_ids );
}

public function test_optionally_excluded_outside_of_main_query() {
$post_ids = get_posts(
public function test_optionally_excluded_outside_of_main_query_with_exclude_archiveless() {
$post_ids = $this->query(
[
'exclude_archiveless' => true,
'fields' => 'ids',
Expand Down Expand Up @@ -237,4 +329,53 @@ public function test_post_preview() {
->assertOk()
->assertQueriedObjectId( $post_id );
}

public function test_custom_post_status_singular() {
$this->get( get_permalink( $this->archiveable_post_custom_status ) )
->assertOk()
->assertElementMissing( 'head/meta[@name="robots"][@content="noindex,nofollow"]' );
}

public function test_custom_post_status_query_included() {
// Ensure the custom post status is queryable.
$post_ids = $this->query(
[
'fields' => 'ids',
'posts_per_page' => 100,
'suppress_filters' => false,
]
);

$this->assertContains( $this->archiveable_post_custom_status, $post_ids );
$this->assertContains( $this->archiveable_post, $post_ids );
$this->assertContains( $this->archiveless_post, $post_ids );

// Make the query again but exclude the archiveless post.
$post_ids = $this->query(
[
'exclude_archiveless' => true,
'fields' => 'ids',
'posts_per_page' => 100,
'suppress_filters' => false,
]
);

$this->assertContains( $this->archiveable_post_custom_status, $post_ids );
$this->assertContains( $this->archiveable_post, $post_ids );
$this->assertNotContains( $this->archiveless_post, $post_ids );
}

/**
* Make a query and retrieve with WP_Query the posts only.
*
* Similar to `get_posts()` but does not set any defaults like `get_posts()` does.
*
* @param array $args Query arguments.
* @return array \WP_Post[]|int[] Array of posts.
*/
protected function query( array $args ): array {
$query = new \WP_Query( $args );

return $query->posts;
}
}

0 comments on commit 28f649c

Please sign in to comment.