PluginProbe ʕ •ᴥ•ʔ
ShopPress – Shop Builder for Elementor and WooCommerce / trunk
ShopPress – Shop Builder for Elementor and WooCommerce vtrunk
shop-press / Admin / API / Posts.php
shop-press / Admin / API Last commit date
Export.php 2 years ago GetFields.php 4 months ago Import.php 2 years ago Options.php 1 week ago Pages.php 2 years ago Posts.php 4 months ago Services.php 1 year ago
Posts.php
834 lines
1 <?php
2 /**
3 * Posts.
4 *
5 * @package ShopPress
6 */
7
8 namespace ShopPress\Admin\API;
9
10 defined( 'ABSPATH' ) || exit;
11
12 use ShopPress\Admin;
13
14 class Posts {
15 /**
16 * Instance of this class.
17 *
18 * @since 1.2.0
19 */
20 public static $instance;
21
22 /**
23 * Provides access to a single instance of a module using the singleton pattern.
24 *
25 * @since 1.2.0
26 *
27 * @return object
28 */
29 public static function instance() {
30 if ( self::$instance === null ) {
31 self::$instance = new self();
32 }
33 return self::$instance;
34 }
35
36 /**
37 * Default term fields.
38 *
39 * @since 1.3.4
40 */
41 private static $default_term_fields = array( 'name', 'slug', 'description', 'parent' );
42
43 /**
44 * Default post fields.
45 *
46 * @since 1.3.4
47 */
48 private static $default_post_fields = array( 'post_title', 'post_content' );
49
50 /**
51 * Add a post.
52 *
53 * @since 1.2.0
54 *
55 * @param object $request
56 */
57 public function add_post( $request ) {
58 $post_type = $request->get_param( 'post_type' );
59 $name = $request->get_param( 'name' );
60
61 $post_id = \ShopPress\Templates\Main::add_post( $post_type, $name );
62 $item_array = array();
63
64 if ( $post_id ) {
65
66 $post = get_post( $post_id );
67
68 $item_array = array(
69 'id' => $post->ID,
70 'title' => $post->post_title,
71 'username' => $this->prepare_username( $post->post_author ),
72 'date' => $this->prepare_date( $post->post_date ),
73 'link' => $this->prepare_link( $post->ID ),
74 );
75
76 return new \WP_REST_Response(
77 $item_array,
78 200
79 );
80 }
81
82 return $item_array;
83 }
84
85 /**
86 * Update post.
87 *
88 * @since 1.2.0
89 *
90 * @param object $request
91 */
92 public function update_post( $request ) {
93 $post_id = $request->get_param( 'id' );
94 $updated_meta = $request->get_json_params();
95 $post_type = get_post_type( $post_id );
96
97 if ( ! $post_id || ! is_array( $updated_meta ) ) {
98 return;
99 }
100
101 /**
102 * Filters the default post fields.
103 *
104 * @since 1.4.3
105 *
106 * @param array $default_post_fields
107 * @param string $post_type
108 */
109 $default_post_fields = apply_filters( 'shoppress/api/post/default_post_fields', self::$default_post_fields, $post_type );
110
111 $post_data = array();
112 foreach ( $updated_meta as $key => $value ) {
113
114 if ( in_array( $key, $default_post_fields ) ) {
115
116 $value = ( is_array( $value ) && isset( $value['value'] ) ) ? $value['value'] : $value;
117
118 $post_data[ $key ] = $value;
119 } else {
120
121 // update value if it was string
122 if ( is_array( $value ) && isset( $value['url'] ) ) {
123 $value = json_encode( $value );
124 }
125
126 update_post_meta( $post_id, $key, $value );
127 }
128 }
129
130 if ( ! empty( $post_data ) ) {
131
132 $post_data['ID'] = $post_id;
133 wp_update_post( $post_data );
134 }
135 }
136
137 /**
138 * Delete post.
139 *
140 * @since 1.2.0
141 *
142 * @param object $request
143 */
144 public function delete_post( $request ) {
145 $post_id = $request->get_param( 'id' );
146
147 $deleted_post = wp_delete_post( $post_id, false );
148
149 return new \WP_REST_Response(
150 $deleted_post->ID,
151 200
152 );
153 }
154
155 /**
156 * Prepare date format.
157 *
158 * @since 1.2.0
159 *
160 * @param string $date
161 */
162 private function prepare_date( $date ) {
163
164 if ( ! $date ) {
165 return '';
166 }
167
168 $dateObj = new \DateTime( $date );
169
170 $year = $dateObj->format( 'Y' );
171 $month = $dateObj->format( 'm' );
172 $day = $dateObj->format( 'd' );
173
174 $formatted_date = "$day/$month/$year";
175
176 return $formatted_date;
177 }
178
179 /**
180 * Prepare the link.
181 *
182 * @since 1.2.0
183 *
184 * @param int $post_id
185 */
186 private function prepare_link( $post_id ) {
187 $post_type = get_post_type( $post_id );
188
189 return apply_filters( 'shoppress/api/get_posts/link', get_permalink( $post_id ), $post_type );
190 }
191
192 /**
193 * Prepare username.
194 *
195 * @since 1.2.0
196 *
197 * @param int $user_id
198 */
199 private function prepare_username( $user_id ) {
200 $user_data = get_userdata( $user_id );
201 $username = __( 'Guest', 'shop-press' );
202
203 if ( $user_data ) {
204 $username = $user_data->user_login;
205 }
206
207 return $username;
208 }
209
210 /**
211 * Prepare items data.
212 *
213 * @since 1.2.0
214 *
215 * @param object $items
216 * @param array $meta_in_table
217 *
218 * @return array $prepare_items_data
219 */
220 private function prepare_items_data( $items, $meta_in_table = array() ) {
221
222 if ( ! is_array( $items ) || empty( $items ) ) {
223 return array();
224 }
225
226 $prepare_items_data = array();
227
228 foreach ( $items as $item ) {
229
230 $item_id = $item->ID ?? $item->term_id;
231 $post_type = $item->post_type ?? null;
232 $data_type = $post_type ? 'posts' : 'terms';
233
234 $post_array = array(
235 'id' => $item_id ?? 'null',
236 'title' => $item->post_title ?? '',
237 'username' => $this->prepare_username( $item->post_author ?? '' ),
238 'date' => $this->prepare_date( $item->post_date ),
239 'link' => $this->prepare_link( $item_id ),
240 );
241
242 $term_array = array(
243 'id' => $item_id ?? null,
244 'title' => $item->name ?? '',
245 );
246
247 if ( ! empty( $meta_in_table ) ) {
248
249 $meta_list = $this->prepare_meta_list( $item_id, $meta_in_table );
250
251 foreach ( $meta_list as $key => $value ) {
252
253 $post_array[ $key ] = $value;
254 }
255 }
256
257 if ( 'posts' === $data_type ) {
258
259 $prepare_items_data[] = apply_filters( 'shoppress/api/get_posts/prepare_data', $post_array, $item_id, $post_type, $item );
260 } elseif ( 'terms' === $data_type ) {
261
262 $prepare_items_data[] = apply_filters( 'shoppress/api/get_terms/prepare_data', $term_array, $item_id, $item );
263 }
264 }
265
266 return $prepare_items_data;
267 }
268
269 /**
270 * Get post.
271 *
272 * @since 1.2.0
273 *
274 * @param object $request
275 */
276 public function get_post( $request ) {
277 $post_id = $request->get_param( 'id' );
278
279 if ( ! $post_id ) {
280 return;
281 }
282
283 $post = get_post( $post_id );
284
285 if ( ! $post || ! is_a( $post, 'WP_Post' ) ) {
286 return new \WP_REST_Response(
287 array( 'code' => 'post_not_found', 'message' => __( 'Post not found.', 'shop-press' ) ),
288 404
289 );
290 }
291
292 if ( ! current_user_can( 'read_post', $post_id ) ) {
293 return new \WP_REST_Response(
294 array( 'code' => 'rest_forbidden', 'message' => __( 'You cannot view this post.', 'shop-press' ) ),
295 403
296 );
297 }
298
299 $post_type = get_post_type( $post_id );
300
301 $meta_keys = get_post_custom_keys( $post_id );
302
303 // Ignore these items
304 $default_keys = array( '_edit_last', 'custom_type', '_edit_lock' );
305
306 /**
307 * Filters the default post keys.
308 *
309 * @since 1.4.3
310 *
311 * @param array $default_keys
312 * @param string $post_type
313 */
314 $default_post_keys = apply_filters( 'shoppress/api/get_post/default_post_keys', $default_keys, $post_type );
315
316 $keys_values = array();
317 if ( is_array( $meta_keys ) ) {
318
319 foreach ( $meta_keys as $key ) {
320
321 if ( in_array( $key, $default_post_keys ) ) {
322 continue;
323 }
324
325 $meta_value = get_post_custom_values( $key, $post_id )[0] ?? '';
326 $meta_value_json = json_decode( $meta_value, true );
327 $unserialized_value = maybe_unserialize( $meta_value );
328
329 if ( $meta_value_json !== null ) {
330 $unserialized_value = $meta_value_json;
331 }
332
333 $keys_values[ $key ] = $unserialized_value !== false ? $unserialized_value : $meta_value;
334 }
335 }
336
337 /**
338 * Filters the default post fields.
339 *
340 * @since 1.4.3
341 *
342 * @param array $default_post_fields
343 * @param string $post_type
344 */
345 $default_post_fields = apply_filters( 'shoppress/api/post/default_post_fields', self::$default_post_fields, $post_type );
346
347 foreach ( $post as $key => $value ) {
348
349 if ( in_array( $key, $default_post_fields ) ) {
350
351 $keys_values[ $key ] = $value ?? '';
352 }
353 }
354
355 if ( ! is_wp_error( $post ) ) {
356
357 $prepared_data = $this->prepare_item_data( $post );
358
359 $post_data = array(
360 'post' => $prepared_data,
361 'meta' => $keys_values,
362 'meta_fields' => array(),
363 );
364
365 $response = apply_filters( 'shoppress/api/get_post', $post_data, $post_id, $post_type );
366
367 // Fallback: ensure FBT meta_fields when Pro filter may not have run.
368 if ( 'shoppress_fbt' === $post_type && empty( $response['meta_fields'] ) ) {
369 if ( class_exists( '\ShopPressPro\Modules\FrequentlyBoughtTogether\Main' ) && method_exists( '\ShopPressPro\Modules\FrequentlyBoughtTogether\Main', 'add_meta_fields' ) ) {
370 $response = \ShopPressPro\Modules\FrequentlyBoughtTogether\Main::add_meta_fields( $response, $post_id, $post_type );
371 }
372 }
373
374 return new \WP_REST_Response(
375 $response,
376 200
377 );
378 } else {
379
380 $error_message = $post->get_error_message();
381
382 return new \WP_REST_Response(
383 $error_message,
384 500
385 );
386 }
387 }
388
389 /**
390 * Get posts.
391 *
392 * @since 1.2.0
393 *
394 * @param object $request
395 */
396 public function get_posts( $request ) {
397 $post_type = $request->get_param( 'post_type' );
398 $page = $request->get_param( 'page' );
399 $meta_in_table = $request->get_param( 'meta_in_table' );
400
401 if ( ! $post_type ) {
402 return;
403 }
404
405 $posts_per_page = apply_filters( 'shoppress/api/get_posts/per_page', 10, $post_type );
406
407 $args = array(
408 'post_type' => $post_type,
409 'posts_per_page' => $posts_per_page,
410 'paged' => $page ?? 1,
411 );
412
413 $query = new \WP_Query( $args );
414
415 if ( ! is_wp_error( $query ) ) {
416
417 $max_num_pages = $query->max_num_pages;
418 $prepare_items_data = $this->prepare_items_data( $query->get_posts(), $meta_in_table );
419
420 $response = rest_ensure_response(
421 new \WP_REST_Response(
422 $prepare_items_data,
423 200
424 )
425 );
426
427 $response->header( 'total_posts', (int) $max_num_pages );
428
429 return $response;
430 } else {
431
432 $error_message = $query->get_error_message();
433
434 return new \WP_REST_Response(
435 $error_message,
436 500
437 );
438 }
439 }
440
441 /**
442 * Ensure product_brand taxonomy is available (WooCommerce / Pro Brands module).
443 *
444 * @since 1.3.1
445 */
446 private function ensure_brands_taxonomy_registered() {
447 if ( taxonomy_exists( 'product_brand' ) ) {
448 return;
449 }
450 $pro_path = $this->get_pro_path();
451 $brand_file = $pro_path ? $pro_path . 'Modules/Brands/Brand.php' : '';
452 if ( $brand_file && file_exists( $brand_file ) ) {
453 require_once $brand_file;
454 }
455 // product_brand is registered by WooCommerce - no separate registration needed.
456 }
457
458 /**
459 * Get ShopPress Pro plugin path.
460 *
461 * @return string
462 */
463 private function get_pro_path() {
464 if ( defined( 'SHOPPRESS_PRO_PATH' ) ) {
465 return SHOPPRESS_PRO_PATH;
466 }
467 if ( ! function_exists( 'get_plugins' ) ) {
468 require_once ABSPATH . 'wp-admin/includes/plugin.php';
469 }
470 foreach ( array_keys( get_plugins() ) as $plugin_file ) {
471 if ( strpos( $plugin_file, 'shop-press-pro' ) === 0 && is_plugin_active( $plugin_file ) ) {
472 return trailingslashit( WP_PLUGIN_DIR . '/' . dirname( $plugin_file ) );
473 }
474 }
475 return '';
476 }
477
478 /**
479 * Get terms.
480 *
481 * @since 1.3.1
482 *
483 * @param object $request
484 */
485 public function get_terms( $request ) {
486 $taxonomy = $request->get_param( 'taxonomy' );
487 $page = $request->get_param( 'page' );
488 $meta_in_table = $request->get_param( 'meta_in_table' );
489
490 if ( ! $taxonomy ) {
491 return;
492 }
493
494 $this->ensure_brands_taxonomy_registered();
495
496 $number = apply_filters( 'shoppress/api/get_terms/number', 10, $taxonomy );
497
498 $args = array(
499 'taxonomy' => $taxonomy,
500 'hide_empty' => false,
501 'number' => $number,
502 'offset' => ( $page - 1 ) * $number,
503 );
504
505 $terms = get_terms( $args );
506
507 if ( ! is_wp_error( $terms ) ) {
508
509 $total_terms = ceil( wp_count_terms( $taxonomy ) / $number );
510 $prepare_items_data = $this->prepare_items_data( $terms, $meta_in_table );
511
512 $response = rest_ensure_response(
513 new \WP_REST_Response(
514 $prepare_items_data,
515 200
516 )
517 );
518
519 $response->header( 'total_terms', (int) $total_terms );
520
521 return $response;
522 } else {
523
524 $error_message = $terms->get_error_message();
525
526 return new \WP_REST_Response(
527 $error_message,
528 500
529 );
530 }
531 }
532
533 /**
534 * Add a term.
535 *
536 * @since 1.3.1
537 *
538 * @param object $request
539 */
540 public function add_term( $request ) {
541 $taxonomy = $request->get_param( 'taxonomy' );
542 $name = $request->get_param( 'name' );
543
544 if ( ! $name || ! $taxonomy ) {
545 return;
546 }
547
548 $this->ensure_brands_taxonomy_registered();
549
550 $result = wp_insert_term( $name, $taxonomy );
551 $term_array = array();
552
553 if ( ! is_wp_error( $result ) ) {
554
555 $term = get_term_by( 'id', $result['term_id'], $taxonomy );
556
557 $term_array = array(
558 'id' => $result['term_id'],
559 'title' => $term->name,
560 );
561
562 return new \WP_REST_Response(
563 $term_array,
564 200
565 );
566 } else {
567
568 $error_message = $result->get_error_message();
569
570 return new \WP_REST_Response(
571 $error_message,
572 500
573 );
574 }
575 }
576
577 /**
578 * Get term.
579 *
580 * @since 1.2.0
581 *
582 * @param object $request
583 */
584 public function get_term( $request ) {
585 $term_id = $request->get_param( 'id' );
586 $taxonomy = $request->get_param( 'taxonomy' );
587
588 if ( ! $term_id || ! $taxonomy ) {
589 return;
590 }
591
592 $this->ensure_brands_taxonomy_registered();
593
594 $term = get_term_by( 'term_id', $term_id, $taxonomy );
595
596 $prepared_term = $this->prepare_item_data( $term );
597 $prepared_data = $this->prepare_meta_data( $term );
598
599 if ( ! is_wp_error( $term ) ) {
600
601 $term_data = array(
602 'term' => $prepared_term,
603 'term_meta' => $prepared_data,
604 'term_meta_fields' => array(),
605 );
606
607 $response = apply_filters( 'shoppress/api/get_term', $term_data, $term_id, $taxonomy );
608
609 if ( 'product_brand' === $taxonomy && empty( $response['term_meta_fields'] ) && class_exists( 'ShopPressPro\Modules\Brands\Brand' ) ) {
610 $response = \ShopPressPro\Modules\Brands\Brand::add_brands_meta_fields( $response, $term_id, $taxonomy );
611 }
612
613 return new \WP_REST_Response(
614 $response,
615 200
616 );
617 } else {
618
619 $error_message = $term->get_error_message();
620
621 return new \WP_REST_Response(
622 $error_message,
623 500
624 );
625 }
626 }
627
628 /**
629 * Delete a term.
630 *
631 * @since 1.3.1
632 *
633 * @param object $request
634 */
635 public function delete_term( $request ) {
636 $term_id = $request->get_param( 'id' );
637 $taxonomy = $request->get_param( 'taxonomy' );
638
639 $this->ensure_brands_taxonomy_registered();
640
641 $result = wp_delete_term( $term_id, $taxonomy );
642
643 if ( ! is_wp_error( $result ) ) {
644
645 return new \WP_REST_Response(
646 (int) $term_id,
647 200
648 );
649 } else {
650
651 $error_message = $result->get_error_message();
652
653 return new \WP_REST_Response(
654 $error_message,
655 500
656 );
657 }
658 }
659
660 /**
661 * Update term.
662 *
663 * @since 1.3.1
664 *
665 * @param object $request
666 */
667 public function update_term( $request ) {
668 $term_id = $request->get_param( 'id' );
669 $updated_data = $request->get_json_params();
670 $taxonomy = $updated_data['term'] ?? '';
671
672 if ( ! $term_id || ! is_array( $updated_data ) && empty( $taxonomy ) ) {
673 return;
674 }
675
676 $this->ensure_brands_taxonomy_registered();
677
678 $term_data = array();
679 foreach ( $updated_data as $key => $value ) {
680
681 if ( in_array( $key, self::$default_term_fields ) ) {
682
683 $value = ( is_array( $value ) && isset( $value['value'] ) ) ? $value['value'] : $value;
684
685 $term_data[ $key ] = sanitize_text_field( $value );
686 } elseif ( $key !== 'term' ) {
687
688 // update value if it was string
689 if ( is_array( $value ) && isset( $value['url'] ) ) {
690 $value = json_encode( $value );
691 }
692
693 update_term_meta( $term_id, $key, $value );
694 }
695 }
696
697 if ( ! empty( $term_data ) ) {
698
699 wp_update_term( $term_id, $taxonomy, $term_data );
700 }
701 }
702
703 /**
704 * Prepare meta list to display in the table.
705 *
706 * @since 1.2.0
707 *
708 * @param int $user_id
709 * @param array $meta_in_table
710 */
711 private function prepare_meta_list( $post_id, $meta_in_table ) {
712
713 if ( ! $post_id || ! is_array( $meta_in_table ) ) {
714 return array();
715 }
716
717 $meta_value = array();
718
719 foreach ( $meta_in_table as $key => $value ) {
720
721 $post_meta = get_post_meta( $post_id, $key );
722 $meta_value[ $key ] = $post_meta[0] ?? '';
723 }
724
725 return $meta_value;
726 }
727
728 /**
729 * Prepare post data.
730 *
731 * @since 1.2.0
732 *
733 * @param array $post
734 *
735 * @return array
736 */
737 private function prepare_item_data( $item ) {
738
739 if ( ! $item ) {
740 return array();
741 }
742
743 $prepared_item_data = array(
744 'id' => $item->ID ?? $item->term_id,
745 'title' => $item->post_title ?? $item->name,
746 );
747
748 return $prepared_item_data;
749 }
750
751 /**
752 * Prepare term data
753 *
754 * @since 1.3.1
755 *
756 * @param array $term
757 *
758 * @return array
759 */
760 private function prepare_meta_data( $term ) {
761
762 if ( ! $term ) {
763 return array();
764 }
765
766 $meta_keys = get_term_meta( $term->term_id );
767
768 $keys_values = array();
769 if ( is_array( $meta_keys ) ) {
770
771 foreach ( $meta_keys as $key => $value ) {
772
773 $unserialized_value = maybe_unserialize( $value[0] ?? '' );
774 $meta_value_json = json_decode( $value[0] ?? '', true );
775
776 if ( $meta_value_json !== null ) {
777 $unserialized_value = $meta_value_json;
778 }
779
780 $keys_values[ $key ] = $unserialized_value !== false ? $unserialized_value : $value;
781 }
782 }
783
784 foreach ( $term as $key => $value ) {
785
786 if ( in_array( $key, self::$default_term_fields ) ) {
787
788 $keys_values[ $key ] = $value ?? '';
789 }
790 }
791
792 return $keys_values;
793 }
794
795 /**
796 * Custom list filter.
797 *
798 * @since 1.4.0
799 *
800 * @param object $request
801 */
802 public function custom_list_filter( $request ) {
803 $items_group = $request->get_param( 'items_group' );
804 $page = $request->get_param( 'page' );
805 $meta_in_table = $request->get_param( 'meta_in_table' );
806
807 if ( ! $items_group ) {
808 return;
809 }
810
811 $items_data = array(
812 'total_pages' => 1,
813 'items' => array(),
814 );
815
816 $items_per_page = apply_filters( 'shoppress/api/get_custom_list/per_page', 10, $items_group );
817 $items_data = apply_filters( 'shoppress/api/get_custom_list/data', $items_data, $items_group, $page, $items_per_page, $meta_in_table );
818
819 $max_num_pages = $items_data['total_pages'] ?? 1;
820 $prepare_items_data = $items_data['items'] ?? array();
821
822 $response = rest_ensure_response(
823 new \WP_REST_Response(
824 $prepare_items_data,
825 200
826 )
827 );
828
829 $response->header( 'total_pages', (int) $max_num_pages );
830
831 return $response;
832 }
833 }
834