PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / trunk
Yoast SEO – Advanced SEO with real-time guidance and built-in AI vtrunk
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
← All changes | src/bulk-editor/user-interface/posts-route.php +61 -6 28.2 → trunk View file →
@@ -11,8 +11,10 @@
11 11 use Yoast\WP\SEO\Bulk_Editor\Application\Posts\Posts_Collector_Interface;
12 12 use Yoast\WP\SEO\Bulk_Editor\Application\Posts\Posts_Repository;
13 13 use Yoast\WP\SEO\Bulk_Editor\Domain\Posts\Posts_Query;
14 14 use Yoast\WP\SEO\Conditionals\No_Conditionals;
15 +use Yoast\WP\SEO\Helpers\Options_Helper;
16 +use Yoast\WP\SEO\Helpers\Post_Type_Helper;
15 17 use Yoast\WP\SEO\Helpers\User_Helper;
16 18 use Yoast\WP\SEO\Main;
17 19 use Yoast\WP\SEO\Routes\Route_Interface;
18 20
@@ -79,8 +81,22 @@
79 81 */
80 82 private $user_helper;
81 83
82 84 /**
85 + * The options helper.
86 + *
87 + * @var Options_Helper
88 + */
89 + private $options_helper;
90 +
91 + /**
92 + * The post type helper.
93 + *
94 + * @var Post_Type_Helper
95 + */
96 + private $post_type_helper;
97 +
98 + /**
83 99 * The constructor.
84 100 *
85 101 * @param Posts_Repository $posts_repository The posts repository.
86 102 * @param Content_Types_Repository $content_types_repository The content types repository.
@@ -85,19 +101,25 @@
85 101 * @param Posts_Repository $posts_repository The posts repository.
86 102 * @param Content_Types_Repository $content_types_repository The content types repository.
87 103 * @param Content_Type_Access_Checker_Interface $content_type_access_checker The content type access checker.
88 104 * @param User_Helper $user_helper The user helper.
105 + * @param Options_Helper $options_helper The options helper.
106 + * @param Post_Type_Helper $post_type_helper The post type helper.
89 107 */
90 108 public function __construct(
91 109 Posts_Repository $posts_repository,
92 110 Content_Types_Repository $content_types_repository,
93 111 Content_Type_Access_Checker_Interface $content_type_access_checker,
94 - User_Helper $user_helper
112 + User_Helper $user_helper,
113 + Options_Helper $options_helper,
114 + Post_Type_Helper $post_type_helper
95 115 ) {
96 116 $this->posts_repository = $posts_repository;
97 117 $this->content_types_repository = $content_types_repository;
98 118 $this->content_type_access_checker = $content_type_access_checker;
99 119 $this->user_helper = $user_helper;
120 + $this->options_helper = $options_helper;
121 + $this->post_type_helper = $post_type_helper;
100 122 }
101 123
102 124 /**
103 125 * Registers routes with WordPress.
@@ -110,15 +132,15 @@
110 132 self::ROUTE_PREFIX,
111 133 [
112 134 'methods' => 'GET',
113 135 'args' => [
114 - 'content_type' => [
136 + 'content_type' => [
115 137 'required' => true,
116 138 'type' => 'string',
117 139 'description' => 'The content type to fetch posts for.',
118 140 'sanitize_callback' => 'sanitize_text_field',
119 141 ],
120 - 'per_page' => [
142 + 'per_page' => [
121 143 'required' => false,
122 144 'type' => 'integer',
123 145 'default' => self::DEFAULT_PER_PAGE,
124 146 'minimum' => 1,
@@ -125,9 +147,9 @@
125 147 'maximum' => self::MAX_PER_PAGE,
126 148 'description' => 'The number of posts to fetch.',
127 149 'sanitize_callback' => 'absint',
128 150 ],
129 - 'page' => [
151 + 'page' => [
130 152 'required' => false,
131 153 'type' => 'integer',
132 154 'default' => 1,
133 155 'minimum' => 1,
@@ -133,9 +155,9 @@
133 155 'minimum' => 1,
134 156 'description' => 'The page of posts to fetch.',
135 157 'sanitize_callback' => 'absint',
136 158 ],
137 - 'search' => [
159 + 'search' => [
138 160 'required' => false,
139 161 'type' => 'string',
140 162 'default' => '',
141 163 'description' => 'The term to search posts by.',
@@ -140,9 +162,9 @@
140 162 'default' => '',
141 163 'description' => 'The term to search posts by.',
142 164 'sanitize_callback' => 'sanitize_text_field',
143 165 ],
144 - 'status' => [
166 + 'status' => [
145 167 'required' => false,
146 168 'type' => 'array',
147 169 'default' => Posts_Collector_Interface::STATUSES,
148 170 'items' => [
@@ -150,8 +172,29 @@
150 172 'enum' => Posts_Collector_Interface::STATUSES,
151 173 ],
152 174 'description' => 'The post statuses to include.',
153 175 ],
176 + 'needs_improvement' => [
177 + 'required' => false,
178 + 'type' => 'array',
179 + 'default' => [],
180 + 'items' => [
181 + 'type' => 'string',
182 + 'enum' => Posts_Collector_Interface::NEEDS_IMPROVEMENT_FIELDS,
183 + ],
184 + 'description' => 'The fields to filter posts by; a field matches when it is empty, or (for search fields, while SEO analysis is enabled and the content type shows Yoast\'s controls and assessments) when its score needs improvement.',
185 + ],
186 + 'include' => [
187 + 'required' => false,
188 + 'type' => 'array',
189 + 'default' => [],
190 + 'maxItems' => self::MAX_PER_PAGE,
191 + 'items' => [
192 + 'type' => 'integer',
193 + 'minimum' => 1,
194 + ],
195 + 'description' => 'Limits the posts to these post IDs, e.g. a selection carried over from the posts overview.',
196 + ],
154 197 ],
155 198 'callback' => [ $this, 'get_posts' ],
156 199 'permission_callback' => [ $this, 'check_permissions' ],
157 200 ],
@@ -188,8 +231,17 @@
188 231 if ( ! $this->content_type_access_checker->can_edit_others( $content_type ) ) {
189 232 $author_id = $this->user_helper->get_current_user_id();
190 233 }
191 234
235 + // The per-field scores only back the filter while SEO analysis is on globally and the content type
236 + // shows Yoast's controls and assessments; otherwise they go stale and the filter falls back to the
237 + // empty-field check.
238 + $scores_enabled = $this->options_helper->get( 'keyword_analysis_active' ) === true
239 + && $this->post_type_helper->has_metabox( $content_type );
240 +
241 + // The schema already coerces the items to positive integers; deduplicate on top of that.
242 + $include = \array_values( \array_unique( \array_map( 'intval', (array) $request->get_param( 'include' ) ) ) );
243 +
192 244 $query = new Posts_Query(
193 245 $content_type,
194 246 (int) $request->get_param( 'page' ),
195 247 (int) $request->get_param( 'per_page' ),
@@ -195,8 +247,11 @@
195 247 (int) $request->get_param( 'per_page' ),
196 248 (string) $request->get_param( 'search' ),
197 249 $statuses,
198 250 $author_id,
251 + (array) $request->get_param( 'needs_improvement' ),
252 + $scores_enabled,
253 + $include,
199 254 );
200 255
201 256 // Posts the current user cannot edit are returned locked and without their SEO data; the per-post
202 257 // permission is resolved while collecting the page.