author-archive-helper.php
5.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
<?php
namespace Yoast\WP\SEO\Helpers;
use WP_Query;
use Yoast\WP\Lib\Model;
/**
* A helper object for author archives.
*/
class Author_Archive_Helper {
/**
* The options helper.
*
* @var Options_Helper
*/
private $options_helper;
/**
* The post type helper.
*
* @var Post_Type_Helper
*/
private $post_type_helper;
/**
* Creates a new author archive helper.
*
* @param Options_Helper $options_helper The options helper.
* @param Post_Type_Helper $post_type_helper The post type helper.
*/
public function __construct(
Options_Helper $options_helper,
Post_Type_Helper $post_type_helper
) {
$this->options_helper = $options_helper;
$this->post_type_helper = $post_type_helper;
}
/**
* Gets the array of post types that are shown on an author's archive.
*
* @return array The post types that are shown on an author's archive.
*/
public function get_author_archive_post_types() {
/**
* Filters the array of post types that are shown on an author's archive.
*
* @param array $args The post types that are shown on an author archive.
*/
return \apply_filters( 'wpseo_author_archive_post_types', [ 'post' ] );
}
/**
* Returns whether the author has at least one public post.
*
* @param int $author_id The author ID.
*
* @return bool|null Whether the author has at least one public post.
*/
public function author_has_public_posts( $author_id ) {
// First check if the author has at least one public post.
$has_public_post = $this->author_has_a_public_post( $author_id );
if ( $has_public_post ) {
return true;
}
// Then check if the author has at least one post where the status is the same as the global setting.
$has_public_post_depending_on_the_global_setting = $this->author_has_a_post_with_is_public_null( $author_id );
if ( $has_public_post_depending_on_the_global_setting ) {
return null;
}
return false;
}
/**
* Returns whether the author has at least one public post.
*
* **Note**: It uses WP_Query to determine the number of posts,
* not the indexables table.
*
* @param string $user_id The user ID.
*
* @return bool Whether the author has at least one public post.
*/
public function author_has_public_posts_wp( $user_id ) {
$post_types = \array_intersect( $this->get_author_archive_post_types(), $this->post_type_helper->get_indexable_post_types() );
$public_post_stati = \array_values( \array_filter( \get_post_stati(), 'is_post_status_viewable' ) );
$args = [
'post_type' => $post_types,
'post_status' => $public_post_stati,
'author' => $user_id,
'update_post_term_cache' => false,
'update_post_meta_cache' => false,
'no_found_rows' => true,
'fields' => 'ids',
'posts_per_page' => 1,
];
$query = new WP_Query( $args );
if ( $query->have_posts() ) {
return true;
}
return false;
}
/**
* Checks whether author archives are disabled.
*
* @return bool `true` if author archives are disabled, `false` if not.
*/
public function are_disabled() {
return $this->options_helper->get( 'disable-author' );
}
/**
* Returns whether the author has at least one public post.
*
* @codeCoverageIgnore It looks for the first ID through the ORM and converts it to a boolean.
*
* @param int $author_id The author ID.
*
* @return bool Whether the author has at least one public post.
*/
protected function author_has_a_public_post( $author_id ) {
$cache_key = 'author_has_a_public_post_' . $author_id;
$indexable_exists = \wp_cache_get( $cache_key );
if ( $indexable_exists === false ) {
$indexable_exists = Model::of_type( 'Indexable' )
->select( 'id' )
->where( 'object_type', 'post' )
->where_in( 'object_sub_type', $this->get_author_archive_post_types() )
->where( 'author_id', $author_id )
->where( 'is_public', 1 )
->find_one();
if ( $indexable_exists === false ) {
// Cache no results to prevent full table scanning on authors with no public posts.
\wp_cache_set( $cache_key, 0, '', \wp_rand( ( 2 * \HOUR_IN_SECONDS ), ( 4 * \HOUR_IN_SECONDS ) ) );
}
}
return (bool) $indexable_exists;
}
/**
* Returns whether the author has at least one post with the is public null.
*
* @codeCoverageIgnore It looks for the first ID through the ORM and converts it to a boolean.
*
* @param int $author_id The author ID.
*
* @return bool Whether the author has at least one post with the is public null.
*/
protected function author_has_a_post_with_is_public_null( $author_id ) {
$cache_key = 'author_has_a_post_with_is_public_null_' . $author_id;
$indexable_exists = \wp_cache_get( $cache_key );
if ( $indexable_exists === false ) {
$indexable_exists = Model::of_type( 'Indexable' )
->select( 'id' )
->where( 'object_type', 'post' )
->where_in( 'object_sub_type', $this->get_author_archive_post_types() )
->where( 'author_id', $author_id )
->where_null( 'is_public' )
->find_one();
if ( $indexable_exists === false ) {
// Cache no results to prevent full table scanning on authors with no is public null posts.
\wp_cache_set( $cache_key, 0, '', \wp_rand( ( 2 * \HOUR_IN_SECONDS ), ( 4 * \HOUR_IN_SECONDS ) ) );
}
}
return (bool) $indexable_exists;
}
}