PluginProbe ʕ •ᴥ•ʔ
Search Regex / trunk
Search Regex vtrunk
trunk 1.4.12 1.4.13 1.4.14 1.4.15 1.4.16 2.0 2.0.1 2.1 2.2 2.2.1 2.3 2.3.1 2.3.2 2.3.3 2.4 2.4.1 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.1 3.1.1 3.1.2 3.2 3.3 3.3.0 3.3.1 3.4 3.4.1 3.4.2
search-regex / includes / source / core / class-post.php
search-regex / includes / source / core Last commit date
class-comment-meta.php 5 months ago class-comment.php 5 months ago class-meta.php 5 months ago class-options.php 5 months ago class-post-meta.php 5 months ago class-post.php 5 months ago class-terms.php 4 months ago class-user-meta.php 5 months ago class-user.php 5 months ago
class-post.php
453 lines
1 <?php
2
3 namespace SearchRegex\Source\Core;
4
5 use SearchRegex\Source;
6 use SearchRegex\Search;
7 use SearchRegex\Sql;
8 use SearchRegex\Plugin;
9 use SearchRegex\Filter;
10
11 /**
12 * Source for posts, pages, and other custom post types
13 */
14 class Post extends Source\Source {
15 use Source\Has_Meta;
16 use Source\Has_Terms;
17
18 public function get_name( array $row = [] ) {
19 $post_type = isset( $row['post_type'] ) ? $this->get_post_type( $row['post_type'] ) : false;
20 if ( $post_type ) {
21 return $post_type['label'];
22 }
23
24 // Handle post types when it's not registered
25 return isset( $row['post_type'] ) ? ucwords( $row['post_type'] ) : $this->source_name;
26 }
27
28 /**
29 * Get the custom post type from the source
30 *
31 * @param string $post_type Source post type.
32 * @return array{value: string, label: string}|null
33 */
34 private function get_post_type( $post_type ) {
35 $post_types = get_post_types( [], 'objects' );
36
37 foreach ( $post_types as $type ) {
38 // @phpstan-ignore function.alreadyNarrowedType
39 if ( is_object( $type ) && $type->name === $post_type ) {
40 return [
41 'value' => $type->name,
42 'label' => $type->label,
43 ];
44 }
45 }
46
47 return null;
48 }
49
50 public function get_actions( Search\Result $result ) {
51 $edit = get_edit_post_link( $result->get_row_id(), '' );
52 $view = get_permalink( $result->get_row_id() );
53
54 if ( $edit && $view ) {
55 return [
56 'edit' => $edit,
57 'view' => $view,
58 ];
59 }
60
61 return [];
62 }
63
64 public function get_info_columns() {
65 return [
66 new Sql\Select\Select( Sql\Value::table( $this->get_table_name() ), Sql\Value::column( $this->get_title_column() ) ),
67 new Sql\Select\Select( Sql\Value::table( $this->get_table_name() ), Sql\Value::column( 'post_type' ) ), // We need this to show the 'source'
68 ];
69 }
70
71 public function get_title_column() {
72 return 'post_title';
73 }
74
75 public function get_table_id() {
76 return 'ID';
77 }
78
79 public function get_table_name() {
80 global $wpdb;
81
82 return $wpdb->posts;
83 }
84
85 public function get_row_columns( $row_id ) {
86 $extra = [
87 $this->get_meta( get_post_meta( $row_id ) ),
88 ];
89
90 $object_terms = wp_get_object_terms( $row_id, [ 'post_tag', 'category' ] );
91 if ( $object_terms instanceof \WP_Error ) {
92 return $object_terms;
93 }
94
95 $extra = array_merge( $extra, $this->get_terms( $object_terms ) );
96 $columns = parent::get_row_columns( $row_id );
97
98 if ( $columns instanceof \WP_Error ) {
99 return $columns;
100 }
101
102 return array_values( array_merge( $columns, $extra ) );
103 }
104
105 public function save( $row_id, array $changes ) {
106 $post = $this->get_columns_to_change( $changes );
107 $post['ID'] = $row_id;
108
109 $this->process_meta( $row_id, 'post', $changes );
110 $this->process_terms( $row_id, 'post', $changes );
111
112 if ( count( $post ) > 1 ) {
113 // wp_update_post expects slashes to be present, which are then removed
114 if ( isset( $post['post_content'] ) && is_string( $post['post_content'] ) ) {
115 $post['post_content'] = wp_slash( $post['post_content'] );
116 }
117
118 if ( isset( $post['post_excerpt'] ) && is_string( $post['post_excerpt'] ) ) {
119 $post['post_excerpt'] = wp_slash( $post['post_excerpt'] );
120 }
121
122 $this->log_save( 'post', $post );
123
124 // This does all the sanitization
125 $result = true;
126
127 if ( Plugin\Settings::init()->can_save() ) {
128 /** @phpstan-ignore argument.type */
129 $result = wp_update_post( $post );
130 }
131
132 if ( $result ) {
133 return true;
134 }
135
136 return new \WP_Error( 'searchregex', 'Failed to update post.' );
137 }
138
139 return true;
140 }
141
142 public function delete_row( $row_id ) {
143 $this->log_save( 'delete post', $row_id );
144
145 if ( Plugin\Settings::init()->can_save() ) {
146 if ( wp_delete_post( $row_id, true ) ) {
147 return true;
148 }
149
150 return new \WP_Error( 'searchregex_delete', 'Failed to delete post', 401 );
151 }
152
153 return true;
154 }
155
156 public function autocomplete( array $column, $value ) {
157 if ( $column['column'] === 'post_author' ) {
158 return Source\Autocomplete::get_user( $value );
159 }
160
161 if ( $column['column'] === 'post_parent' ) {
162 return Source\Autocomplete::get_post( $value, Sql\Value::column( 'ID' ), Sql\Value::column( 'post_title' ) );
163 }
164
165 if ( $column['column'] === 'category' ) {
166 return Source\Autocomplete::get_category( $value );
167 }
168
169 if ( $column['column'] === 'post_tag' ) {
170 return Source\Autocomplete::get_tag( $value );
171 }
172
173 if ( $column['column'] === 'meta' ) {
174 return Source\Autocomplete::get_meta( Sql\Value::table( 'postmeta' ), $value );
175 }
176
177 // General text
178 if ( in_array( $column['column'], [ 'post_title', 'post_name', 'guid', 'post_mime_type' ], true ) ) {
179 return Source\Autocomplete::get_post( $value, Sql\Value::column( $column['column'] ), Sql\Value::column( $column['column'] ) );
180 }
181
182 return [];
183 }
184
185 /**
186 * Get any preloadable data for the given filter
187 *
188 * @param array<string, mixed> $schema Schema.
189 * @param Filter\Type\Filter_Type $filter Filter.
190 * @return list<array{label: string, value: string}>
191 */
192 public function get_filter_preload( $schema, $filter ) {
193 if ( $filter instanceof Filter\Type\Filter_Member && ( $schema['column'] === 'category' || $schema['column'] === 'post_tag' ) ) {
194 $preload = [];
195
196 foreach ( $filter->get_values() as $value ) {
197 $term = get_term( intval( $value, 10 ), $schema['column'] );
198
199 if ( is_object( $term ) && ! $term instanceof \WP_Error ) {
200 $preload[] = [
201 'label' => $term->name,
202 'value' => $schema['column'] . '_' . (string) intval( $value, 10 ),
203 ];
204 }
205 }
206
207 return $preload;
208 } elseif (
209 $schema['column'] === 'post_author' &&
210 (
211 $filter instanceof Filter\Type\Filter_Integer ||
212 $filter instanceof Filter\Type\Filter_String
213 )
214 ) {
215 $convert = new Source\Convert_Values();
216
217 return [
218 [
219 'label' => $convert->get_user( '', (string) $filter->get_value() ),
220 'value' => $schema['column'] . '_' . (string) $filter->get_value(),
221 ],
222 ];
223 }
224
225 return [];
226 }
227
228 public function get_schema() {
229 global $wpdb;
230
231 $stati = get_post_stati();
232 $statuses = [];
233
234 foreach ( array_keys( $stati ) as $status ) {
235 $statuses[] = [
236 'value' => $status,
237 'label' => $status,
238 ];
239 }
240
241 return [
242 'name' => __( 'Posts (core & custom)', 'search-regex' ),
243 'table' => $wpdb->posts,
244 'columns' => [
245 [
246 'column' => 'ID',
247 'type' => 'integer',
248 'title' => __( 'ID', 'search-regex' ),
249 'modify' => false,
250 ],
251 [
252 'column' => 'post_title',
253 'type' => 'string',
254 'title' => __( 'Title', 'search-regex' ),
255 'options' => 'api',
256 'global' => true,
257 'source' => 'post_title',
258 ],
259 [
260 'column' => 'post_name',
261 'type' => 'string',
262 'title' => __( 'Slug', 'search-regex' ),
263 'options' => 'api',
264 'length' => 200,
265 'global' => true,
266 ],
267 [
268 'column' => 'post_type',
269 'type' => 'member',
270 'options' => $this->get_all_custom_post_types(),
271 'title' => __( 'Post Type', 'search-regex' ),
272 'source' => 'post_type',
273 ],
274 [
275 'column' => 'post_content',
276 'type' => 'string',
277 'title' => __( 'Content', 'search-regex' ),
278 'multiline' => true,
279 'global' => true,
280 ],
281 [
282 'column' => 'post_author',
283 'type' => 'integer',
284 'options' => 'api',
285 'title' => __( 'Author', 'search-regex' ),
286 'source' => 'user',
287 'joined_by' => 'user',
288 ],
289 [
290 'column' => 'post_date',
291 'type' => 'date',
292 'title' => __( 'Date', 'search-regex' ),
293 'source' => 'date',
294 ],
295 [
296 'column' => 'post_date_gmt',
297 'type' => 'date',
298 'title' => __( 'Date GMT', 'search-regex' ),
299 'source' => 'date',
300 ],
301 [
302 'column' => 'post_excerpt',
303 'type' => 'string',
304 'title' => __( 'Excerpt', 'search-regex' ),
305 'multiline' => true,
306 ],
307 [
308 'column' => 'post_status',
309 'type' => 'member',
310 'options' => $statuses,
311 'title' => __( 'Post Status', 'search-regex' ),
312 ],
313 [
314 'column' => 'comment_status',
315 'type' => 'member',
316 'options' => [
317 [
318 'value' => 'open',
319 'label' => __( 'Open', 'search-regex' ),
320 ],
321 [
322 'value' => 'closed',
323 'label' => __( 'Closed', 'search-regex' ),
324 ],
325 ],
326 'title' => __( 'Comment Status', 'search-regex' ),
327 'multiple' => false,
328 ],
329 [
330 'column' => 'ping_status',
331 'type' => 'member',
332 'options' => [
333 [
334 'value' => 'open',
335 'label' => __( 'Open', 'search-regex' ),
336 ],
337 [
338 'value' => 'closed',
339 'label' => __( 'Closed', 'search-regex' ),
340 ],
341 ],
342 'title' => __( 'Ping Status', 'search-regex' ),
343 'multiple' => false,
344 ],
345 [
346 'column' => 'post_password',
347 'type' => 'member',
348 'options' => [
349 [
350 'value' => 'password',
351 'label' => __( 'Has password', 'search-regex' ),
352 ],
353 [
354 'value' => 'nopassword',
355 'label' => __( 'Has no password', 'search-regex' ),
356 ],
357 ],
358 'title' => __( 'Password', 'search-regex' ),
359 'multiple' => false,
360 'modify' => false,
361 ],
362 [
363 'column' => 'post_modified',
364 'type' => 'date',
365 'title' => __( 'Modified', 'search-regex' ),
366 'source' => 'date',
367 ],
368 [
369 'column' => 'post_modified_gmt',
370 'type' => 'date',
371 'title' => __( 'Modified GMT', 'search-regex' ),
372 'source' => 'date',
373 ],
374 [
375 'column' => 'post_parent',
376 'type' => 'integer',
377 'title' => __( 'Parent', 'search-regex' ),
378 'options' => 'api',
379 'source' => 'post_title',
380 'joined_by' => 'post',
381 ],
382 [
383 'column' => 'guid',
384 'type' => 'string',
385 'title' => __( 'GUID', 'search-regex' ),
386 'options' => 'api',
387 'length' => 255,
388 ],
389 [
390 'column' => 'post_mime_type',
391 'type' => 'string',
392 'title' => __( 'MIME', 'search-regex' ),
393 'options' => 'api',
394 'length' => 100,
395 ],
396 [
397 'column' => 'comment_count',
398 'type' => 'integer',
399 'title' => __( 'Comment Count', 'search-regex' ),
400 'modify' => false,
401 ],
402 [
403 'column' => 'category',
404 'type' => 'member',
405 'title' => __( 'Post Category', 'search-regex' ),
406 'options' => 'api',
407 'preload' => true,
408 'join' => 'taxonomy',
409 'source' => 'term',
410 ],
411 [
412 'column' => 'post_tag',
413 'type' => 'member',
414 'title' => __( 'Post Tag', 'search-regex' ),
415 'options' => 'api',
416 'preload' => true,
417 'join' => 'taxonomy',
418 'source' => 'term',
419 ],
420 [
421 'column' => 'meta',
422 'type' => 'keyvalue',
423 'title' => __( 'Post Meta', 'search-regex' ),
424 'options' => 'api',
425 'join' => 'postmeta',
426 ],
427 ],
428 ];
429 }
430
431 /**
432 * Get list of all custom post types that have a label
433 *
434 * @return list<array{value: string, label: string}>
435 */
436 private function get_all_custom_post_types() {
437 $post_types = get_post_types( [], 'objects' );
438 $post_sources = [];
439
440 foreach ( $post_types as $type ) {
441 // @phpstan-ignore function.alreadyNarrowedType
442 if ( is_object( $type ) && strlen( $type->label ) > 0 ) {
443 $post_sources[] = [
444 'value' => $type->name,
445 'label' => $type->label,
446 ];
447 }
448 }
449
450 return apply_filters( 'searchregex_sources_posttype', $post_sources );
451 }
452 }
453