PluginProbe
Block Animations, Motion & Scroll Effects – Ghost Kit / 3.4.3
Block Animations, Motion & Scroll Effects – Ghost Kit v3.4.3
3.7.1 3.7.0 3.6.1 trunk 1.6.3 2.25.0 3.3.0 3.3.1 3.3.2 3.3.3 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.4.5 3.4.6 3.5.0 3.5.1 3.6.0
ghostkit / classes / class-rest.php

class-rest.php in Block Animations, Motion & Scroll Effects – Ghost Kit 3.4.3, at classes/class-rest.php

1,887 lines 52.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Rest API functions
4 *
5 * @package ghostkit
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit;
10 }
11
12 /**
13 * Class GhostKit_Rest
14 */
15 class GhostKit_Rest extends WP_REST_Controller {
16 /**
17 * Namespace.
18 *
19 * @var string
20 */
21 protected $namespace = 'ghostkit/v';
22
23 /**
24 * Version.
25 *
26 * @var string
27 */
28 protected $version = '1';
29
30 /**
31 * GhostKit_Rest constructor.
32 */
33 public function __construct() {
34 add_action( 'rest_api_init', array( $this, 'register_routes' ) );
35 }
36
37 /**
38 * Register rest routes.
39 */
40 public function register_routes() {
41 $namespace = $this->namespace . $this->version;
42
43 // Get layouts list.
44 register_rest_route(
45 $namespace,
46 '/get_customizer/',
47 array(
48 'methods' => WP_REST_Server::READABLE,
49 'callback' => array( $this, 'get_customizer' ),
50 'permission_callback' => array( $this, 'get_customizer_permission' ),
51 )
52 );
53
54 // Get attachment image <img> tag.
55 register_rest_route(
56 $namespace,
57 '/get_attachment_image/(?P<id>[\d]+)',
58 array(
59 'methods' => WP_REST_Server::READABLE,
60 'callback' => array( $this, 'get_attachment_image' ),
61 'permission_callback' => array( $this, 'get_attachment_image_permission' ),
62 )
63 );
64
65 // Get Instagram profile.
66 register_rest_route(
67 $namespace,
68 '/get_instagram_profile/',
69 array(
70 'methods' => WP_REST_Server::READABLE,
71 'callback' => array( $this, 'get_instagram_profile' ),
72 'permission_callback' => array( $this, 'get_instagram_profile_permission' ),
73 )
74 );
75
76 // Get Instagram feed.
77 register_rest_route(
78 $namespace,
79 '/get_instagram_feed/',
80 array(
81 'methods' => WP_REST_Server::READABLE,
82 'callback' => array( $this, 'get_instagram_feed' ),
83 'permission_callback' => array( $this, 'get_instagram_feed_permission' ),
84 )
85 );
86
87 // Get Twitter profile.
88 register_rest_route(
89 $namespace,
90 '/get_twitter_profile/',
91 array(
92 'methods' => WP_REST_Server::READABLE,
93 'callback' => array( $this, 'get_twitter_profile' ),
94 'permission_callback' => array( $this, 'get_twitter_profile_permission' ),
95 )
96 );
97
98 // Get Twitter feed.
99 register_rest_route(
100 $namespace,
101 '/get_twitter_feed/',
102 array(
103 'methods' => WP_REST_Server::READABLE,
104 'callback' => array( $this, 'get_twitter_feed' ),
105 'permission_callback' => array( $this, 'get_twitter_feed_permission' ),
106 )
107 );
108
109 // Get TOC.
110 register_rest_route(
111 $namespace,
112 '/get_table_of_contents/',
113 array(
114 'methods' => WP_REST_Server::READABLE,
115 'callback' => array( $this, 'get_table_of_contents' ),
116 'permission_callback' => '__return_true',
117 )
118 );
119
120 // Get Templates.
121 register_rest_route(
122 $namespace,
123 '/get_templates/',
124 array(
125 'methods' => WP_REST_Server::READABLE,
126 'callback' => array( $this, 'get_templates' ),
127 'permission_callback' => '__return_true',
128 )
129 );
130
131 // Get template data.
132 register_rest_route(
133 $namespace,
134 '/get_template_data/',
135 array(
136 'methods' => WP_REST_Server::READABLE,
137 'callback' => array( $this, 'get_template_data' ),
138 'permission_callback' => '__return_true',
139 )
140 );
141
142 // Get Custom Code.
143 register_rest_route(
144 $namespace,
145 '/get_custom_code/',
146 array(
147 'methods' => WP_REST_Server::READABLE,
148 'callback' => array( $this, 'get_custom_code' ),
149 'permission_callback' => array( $this, 'get_custom_code_permission' ),
150 )
151 );
152
153 // Update Custom Code.
154 register_rest_route(
155 $namespace,
156 '/update_custom_code/',
157 array(
158 'methods' => WP_REST_Server::EDITABLE,
159 'callback' => array( $this, 'update_custom_code' ),
160 'permission_callback' => array( $this, 'update_custom_code_permission' ),
161 )
162 );
163
164 // Update Color Palette.
165 register_rest_route(
166 $namespace,
167 '/update_color_palette/',
168 array(
169 'methods' => WP_REST_Server::EDITABLE,
170 'callback' => array( $this, 'update_color_palette' ),
171 'permission_callback' => array( $this, 'update_color_palette_permission' ),
172 )
173 );
174
175 // Get Typography.
176 register_rest_route(
177 $namespace,
178 '/get_custom_typography/',
179 array(
180 'methods' => WP_REST_Server::READABLE,
181 'callback' => array( $this, 'get_custom_typography' ),
182 'permission_callback' => array( $this, 'get_custom_typography_permission' ),
183 )
184 );
185
186 // Update Typography.
187 register_rest_route(
188 $namespace,
189 '/update_custom_typography/',
190 array(
191 'methods' => WP_REST_Server::EDITABLE,
192 'callback' => array( $this, 'update_custom_typography' ),
193 'permission_callback' => array( $this, 'update_custom_typography_permission' ),
194 )
195 );
196
197 // Update Google Maps API key.
198 register_rest_route(
199 $namespace,
200 '/update_google_maps_api_key/',
201 array(
202 'methods' => WP_REST_Server::EDITABLE,
203 'callback' => array( $this, 'update_google_maps_api_key' ),
204 'permission_callback' => array( $this, 'update_google_maps_api_key_permission' ),
205 )
206 );
207
208 // Update Google reCaptcha keys.
209 register_rest_route(
210 $namespace,
211 '/update_google_recaptcha_keys/',
212 array(
213 'methods' => WP_REST_Server::EDITABLE,
214 'callback' => array( $this, 'update_google_recaptcha_keys' ),
215 'permission_callback' => array( $this, 'update_google_recaptcha_keys_permission' ),
216 )
217 );
218
219 // Update Disabled Blocks.
220 register_rest_route(
221 $namespace,
222 '/update_disabled_blocks/',
223 array(
224 'methods' => WP_REST_Server::EDITABLE,
225 'callback' => array( $this, 'update_disabled_blocks' ),
226 'permission_callback' => array( $this, 'update_disabled_blocks_permission' ),
227 )
228 );
229
230 // Update Settings.
231 register_rest_route(
232 $namespace,
233 '/update_settings/',
234 array(
235 'methods' => WP_REST_Server::EDITABLE,
236 'callback' => array( $this, 'update_settings' ),
237 'permission_callback' => array( $this, 'update_settings_permission' ),
238 )
239 );
240
241 // Get Custom Fonts.
242 register_rest_route(
243 $namespace,
244 '/get_custom_fonts/',
245 array(
246 'methods' => WP_REST_Server::READABLE,
247 'callback' => array( $this, 'get_custom_fonts' ),
248 'permission_callback' => array( $this, 'get_custom_fonts_permission' ),
249 )
250 );
251
252 // Update Custom Fonts.
253 register_rest_route(
254 $namespace,
255 '/update_custom_fonts/',
256 array(
257 'methods' => WP_REST_Server::EDITABLE,
258 'callback' => array( $this, 'update_custom_fonts' ),
259 'permission_callback' => array( $this, 'update_custom_fonts_permission' ),
260 )
261 );
262 }
263
264 /**
265 * Get read fonts permissions.
266 *
267 * @return bool
268 */
269 public function get_custom_fonts_permission() {
270 if ( ! current_user_can( 'edit_theme_options' ) ) {
271 return $this->error( 'user_dont_have_permission', __( 'User don\'t have permissions to change options.', 'ghostkit' ), true );
272 }
273
274 return true;
275 }
276
277 /**
278 * Get edit fonts permissions.
279 *
280 * @return bool
281 */
282 public function update_custom_fonts_permission() {
283 if ( ! current_user_can( 'manage_options' ) ) {
284 return $this->error( 'user_dont_have_permission', __( 'User don\'t have permissions to change options.', 'ghostkit' ), true );
285 }
286
287 return true;
288 }
289
290 /**
291 * Get read customizer permissions.
292 *
293 * @return bool
294 */
295 public function get_customizer_permission() {
296 if ( ! current_user_can( 'edit_theme_options' ) ) {
297 return $this->error( 'user_dont_have_permission', __( 'User don\'t have permissions to change Customizer options.', 'ghostkit' ), true );
298 }
299 return true;
300 }
301
302 /**
303 * Get attachment image <img> tag permissions.
304 *
305 * @return bool
306 */
307 public function get_attachment_image_permission() {
308 return true;
309 }
310
311 /**
312 * Get Instagram feed permissions.
313 *
314 * @return bool
315 */
316 public function get_instagram_feed_permission() {
317 return true;
318 }
319
320 /**
321 * Get Instagram profile permissions.
322 *
323 * @return bool
324 */
325 public function get_instagram_profile_permission() {
326 return true;
327 }
328
329 /**
330 * Get Twitter feed permissions.
331 *
332 * @return bool
333 */
334 public function get_twitter_feed_permission() {
335 return true;
336 }
337
338 /**
339 * Get Twitter profile permissions.
340 *
341 * @return bool
342 */
343 public function get_twitter_profile_permission() {
344 return true;
345 }
346
347 /**
348 * Get read custom code permissions.
349 *
350 * @return bool
351 */
352 public function get_custom_code_permission() {
353 if ( ! current_user_can( 'edit_theme_options' ) ) {
354 return $this->error( 'user_dont_have_permission', __( 'User don\'t have permissions to change options.', 'ghostkit' ), true );
355 }
356
357 return true;
358 }
359
360 /**
361 * Get edit custom code permissions.
362 *
363 * @return bool
364 */
365 public function update_custom_code_permission() {
366 if ( ! current_user_can( 'manage_options' ) ) {
367 return $this->error( 'user_dont_have_permission', __( 'User don\'t have permissions to change options.', 'ghostkit' ), true );
368 }
369
370 return true;
371 }
372
373 /**
374 * Get edit color palette permissions.
375 *
376 * @return bool
377 */
378 public function update_color_palette_permission() {
379 if ( ! current_user_can( 'manage_options' ) ) {
380 return $this->error( 'user_dont_have_permission', __( 'User don\'t have permissions to change options.', 'ghostkit' ), true );
381 }
382
383 return true;
384 }
385
386 /**
387 * Get read typography permissions.
388 *
389 * @return bool
390 */
391 public function get_custom_typography_permission() {
392 if ( ! current_user_can( 'edit_theme_options' ) ) {
393 return $this->error( 'user_dont_have_permission', __( 'User don\'t have permissions to change options.', 'ghostkit' ), true );
394 }
395
396 return true;
397 }
398
399 /**
400 * Get edit typography permissions.
401 *
402 * @return bool
403 */
404 public function update_custom_typography_permission() {
405 if ( ! current_user_can( 'manage_options' ) ) {
406 return $this->error( 'user_dont_have_permission', __( 'User don\'t have permissions to change options.', 'ghostkit' ), true );
407 }
408
409 return true;
410 }
411
412 /**
413 * Get read Google Maps API key permissions.
414 *
415 * @return bool
416 */
417 public function update_google_maps_api_key_permission() {
418 if ( ! current_user_can( 'manage_options' ) ) {
419 return $this->error( 'user_dont_have_permission', __( 'User don\'t have permissions to change options.', 'ghostkit' ), true );
420 }
421
422 return true;
423 }
424
425 /**
426 * Get read Google reCaptcha API keys permissions.
427 *
428 * @return bool
429 */
430 public function update_google_recaptcha_keys_permission() {
431 if ( ! current_user_can( 'manage_options' ) ) {
432 return $this->error( 'user_dont_have_permission', __( 'User don\'t have permissions to change options.', 'ghostkit' ), true );
433 }
434
435 return true;
436 }
437
438 /**
439 * Get edit options permissions.
440 *
441 * @return bool
442 */
443 public function update_disabled_blocks_permission() {
444 if ( ! current_user_can( 'manage_options' ) ) {
445 return $this->error( 'user_dont_have_permission', __( 'User don\'t have permissions to change options.', 'ghostkit' ), true );
446 }
447
448 return true;
449 }
450
451 /**
452 * Get edit options permissions.
453 *
454 * @return bool
455 */
456 public function update_settings_permission() {
457 if ( ! current_user_can( 'manage_options' ) ) {
458 return $this->error( 'user_dont_have_permission', __( 'User don\'t have permissions to change options.', 'ghostkit' ), true );
459 }
460
461 return true;
462 }
463
464 /**
465 * Get custom fonts.
466 *
467 * @return mixed
468 */
469 public function get_custom_fonts() {
470 $fonts = get_option( 'ghostkit_fonts_settings', array() );
471 $fonts = apply_filters( 'gkt_rest_get_custom_fonts', $fonts );
472
473 if ( is_array( $fonts ) ) {
474 return $this->success( $fonts );
475 } else {
476 return $this->error( 'no_fonts', __( 'Custom fonts not found.', 'ghostkit' ) );
477 }
478 }
479
480 /**
481 * Update fonts.
482 *
483 * @param WP_REST_Request $request request object.
484 *
485 * @return mixed
486 */
487 public function update_custom_fonts( WP_REST_Request $request ) {
488 $new_fonts = $request->get_param( 'data' );
489 $updated_option = array();
490
491 $new_fonts = apply_filters( 'gkt_rest_update_custom_fonts', $new_fonts );
492
493 if ( is_array( $new_fonts ) ) {
494 $current_fonts = get_option( 'ghostkit_fonts_settings', array() );
495
496 $updated_option = array_merge( is_array( $current_fonts ) ? $current_fonts : array(), $new_fonts );
497
498 update_option( 'ghostkit_fonts_settings', $updated_option );
499 }
500
501 return $this->success( $updated_option );
502 }
503
504 /**
505 * Get customizer data.
506 *
507 * @return mixed
508 */
509 public function get_customizer() {
510 $options = get_option( 'ghostkit_customizer_fields' );
511
512 if ( ! empty( $options ) ) {
513 return $this->success( $options );
514 } else {
515 return $this->error( 'no_options_found', __( 'Options not found.', 'ghostkit' ) );
516 }
517 }
518
519 /**
520 * Get attachment image <img> tag.
521 *
522 * @param WP_REST_Request $request request object.
523 *
524 * @return mixed
525 */
526 public function get_attachment_image( WP_REST_Request $request ) {
527 $id = $request->get_param( 'id' );
528 $size = $request->get_param( 'size' );
529 $icon = $request->get_param( 'icon' );
530 $attr = $request->get_param( 'attr' );
531 $div_tag = $request->get_param( 'div_tag' );
532
533 if ( ! $id ) {
534 return $this->error( 'no_id_found', __( 'Provide image ID.', 'ghostkit' ) );
535 }
536
537 $attr = isset( $attr ) && $attr && is_array( $attr ) ? $attr : array();
538
539 if ( $div_tag ) {
540 $image_url = wp_get_attachment_image_url( $id, $size, $icon );
541
542 if ( ! isset( $attr['style'] ) ) {
543 $attr['style'] = '';
544 }
545
546 $attr['style'] .= 'background-image: url("' . esc_url( $image_url ) . '");';
547
548 $attr = array_map( 'esc_attr', $attr );
549 $image = '<div';
550
551 foreach ( $attr as $name => $value ) {
552 $image .= " $name=" . '"' . $value . '"';
553 }
554
555 $image .= '></div>';
556 } else {
557 $image_src = wp_get_attachment_image_src( $id, $size, $icon );
558
559 if ( $image_src ) {
560 list( $src, $width, $height ) = $image_src;
561
562 $alt = trim( wp_strip_all_tags( get_post_meta( $id, '_wp_attachment_image_alt', true ) ) );
563
564 if ( $alt ) {
565 $attr['alt'] = $alt;
566 }
567
568 if ( ! isset( $attr['class'] ) ) {
569 $attr['class'] = 'wp-image-' . $id;
570 } else {
571 $attr['class'] = 'wp-image-' . $id . ' ' . $attr['class'];
572 }
573
574 $attr['width'] = $width;
575 $attr['height'] = $height;
576
577 $attrs_str = '';
578
579 if ( isset( $attr ) && is_array( $attr ) ) {
580 foreach ( $attr as $name => $val ) {
581 $attrs_str .= ' ' . $name . '="' . esc_attr( $val ) . '"';
582 }
583 }
584
585 $image = '<img src="' . esc_url( $src ) . '"' . $attrs_str . ' />';
586 }
587 }
588
589 if ( isset( $image ) && $image ) {
590 return $this->success( $image );
591 } else {
592 return $this->error( 'no_image_found', __( 'Image not found.', 'ghostkit' ) );
593 }
594 }
595
596 /**
597 * Get Instagram feed.
598 *
599 * @param WP_REST_Request $request request object.
600 *
601 * @return mixed
602 */
603 public function get_instagram_feed( WP_REST_Request $request ) {
604 $cache_name = 'ghostkit_instagram_feed_cache';
605 $cache_expiration = $request->get_param( 'cache_expiration' ) ? $request->get_param( 'cache_expiration' ) : DAY_IN_SECONDS;
606 $count = $request->get_param( 'count' ) ? $request->get_param( 'count' ) : 6;
607 $access_token = $request->get_param( 'access_token' );
608
609 if ( ! $access_token ) {
610 return $this->error( 'no_token_found', __( 'Provide Instagram Access Token.', 'ghostkit' ) );
611 }
612
613 $hash = md5(
614 wp_json_encode(
615 array(
616 $access_token,
617 $count,
618 $cache_expiration,
619 )
620 )
621 );
622
623 $cache_name = $cache_name . '_' . $hash;
624
625 // get cached data.
626 $result = get_transient( $cache_name );
627
628 // if there is no cache available, request instagram feed.
629 if ( false === $result && $access_token ) {
630 // Make Requests.
631 $feed = wp_remote_get( 'https://api.instagram.com/v1/users/self/media/recent/?access_token=' . $access_token . '&count=' . $count );
632
633 if ( ! is_wp_error( $feed ) && isset( $feed['body'] ) ) {
634 $feed = json_decode( $feed['body'], true );
635 } else {
636 $feed = false;
637 }
638
639 if ( $feed && is_array( $feed ) ) {
640 $result = $feed;
641 set_transient( $cache_name, $result, $cache_expiration );
642 }
643 }
644
645 if ( $result ) {
646 return $this->success( $result );
647 } else {
648 return $this->error( 'no_instagram_data_loaded', __( 'Instagram data failed to load.', 'ghostkit' ) );
649 }
650 }
651
652 /**
653 * Get Instagram profile.
654 *
655 * @param WP_REST_Request $request request object.
656 *
657 * @return mixed
658 */
659 public function get_instagram_profile( WP_REST_Request $request ) {
660 $cache_name = 'ghostkit_instagram_profile_cache';
661 $cache_expiration = $request->get_param( 'cache_expiration' ) ? $request->get_param( 'cache_expiration' ) : DAY_IN_SECONDS;
662 $access_token = $request->get_param( 'access_token' );
663
664 if ( ! $access_token ) {
665 return $this->error( 'no_token_found', __( 'Provide Instagram Access Token.', 'ghostkit' ) );
666 }
667
668 $hash = md5(
669 wp_json_encode(
670 array(
671 $access_token,
672 $cache_expiration,
673 )
674 )
675 );
676
677 $cache_name = $cache_name . '_' . $hash;
678
679 // get cached data.
680 $result = get_transient( $cache_name );
681
682 // if there is no cache available, request instagram feed.
683 if ( false === $result && $access_token ) {
684 // Make Requests.
685 $profile = wp_remote_get( 'https://api.instagram.com/v1/users/self/?access_token=' . $access_token );
686
687 if ( ! is_wp_error( $profile ) && isset( $profile['body'] ) ) {
688 $profile = json_decode( $profile['body'], true );
689 } else {
690 $profile = false;
691 }
692
693 if ( $profile && is_array( $profile ) ) {
694 $result = $profile;
695 set_transient( $cache_name, $result, $cache_expiration );
696 }
697 }
698
699 if ( $result ) {
700 return $this->success( $result );
701 } else {
702 return $this->error( 'no_instagram_data_loaded', __( 'Instagram data failed to load.', 'ghostkit' ) );
703 }
704 }
705
706 /**
707 * Get Twitter profile.
708 *
709 * @param WP_REST_Request $request request object.
710 *
711 * @return mixed
712 */
713 public function get_twitter_profile( WP_REST_Request $request ) {
714 $cache_name = 'ghostkit_twitter_profile_cache';
715 $cache_expiration = $request->get_param( 'cache_expiration' ) ? $request->get_param( 'cache_expiration' ) : DAY_IN_SECONDS;
716
717 $consumer_key = $request->get_param( 'consumer_key' );
718 $consumer_secret = $request->get_param( 'consumer_secret' );
719 $access_token = $request->get_param( 'access_token' );
720 $access_token_secret = $request->get_param( 'access_token_secret' );
721 $screen_name = $request->get_param( 'screen_name' );
722
723 if ( ! $consumer_key ) {
724 return $this->error( 'no_consumer_key_found', __( 'Provide Twitter Consumer Key.', 'ghostkit' ) );
725 }
726 if ( ! $consumer_secret ) {
727 return $this->error( 'no_consumer_secret_found', __( 'Provide Twitter Consumer Secret.', 'ghostkit' ) );
728 }
729 if ( ! $access_token ) {
730 return $this->error( 'no_access_token_found', __( 'Provide Twitter Access Token.', 'ghostkit' ) );
731 }
732 if ( ! $access_token_secret ) {
733 return $this->error( 'no_access_token_secret_found', __( 'Provide Twitter Access Token Secret.', 'ghostkit' ) );
734 }
735 if ( ! $screen_name ) {
736 return $this->error( 'no_screen_name_found', __( 'Provide Username.', 'ghostkit' ) );
737 }
738
739 $api_data_ready = $consumer_key && $consumer_secret && $access_token && $access_token_secret;
740
741 $hash = md5(
742 wp_json_encode(
743 array(
744 $consumer_key,
745 $consumer_secret,
746 $access_token,
747 $access_token_secret,
748 $cache_expiration,
749 )
750 )
751 );
752
753 $cache_name = $cache_name . '_' . $screen_name . '_' . $hash;
754
755 // get cached data.
756 $result = get_transient( $cache_name );
757
758 // if there is no cache available, request twitter feed.
759 if ( false === $result && $api_data_ready ) {
760 // request_api_twitter.
761 $profile = $this->request_api_twitter(
762 array(
763 'url' => 'https://api.twitter.com/1.1/users/show.json',
764 'consumer_key' => $consumer_key,
765 'consumer_secret' => $consumer_secret,
766 'access_token' => $access_token,
767 'access_token_secret' => $access_token_secret,
768 'include_entities' => 'true',
769 'screen_name' => $screen_name,
770 )
771 );
772
773 if ( $profile && isset( $profile['screen_name'] ) ) {
774 $result = $profile;
775
776 // prepare different profile image sizes.
777 if ( $result['profile_image_url'] ) {
778 $result['profile_images'] = $this->get_twitter_profile_images( $result['profile_image_url'] );
779 }
780 if ( $result['profile_image_url_https'] ) {
781 $result['profile_images_https'] = $this->get_twitter_profile_images( $result['profile_image_url_https'] );
782 }
783
784 // prepare short counts.
785 $result['followers_count_short'] = $this->convert_number_short( $result['followers_count'] );
786 $result['friends_count_short'] = $this->convert_number_short( $result['friends_count'] );
787 $result['listed_count_short'] = $this->convert_number_short( $result['listed_count'] );
788 $result['favourites_count_short'] = $this->convert_number_short( $result['favourites_count'] );
789 $result['statuses_count_short'] = $this->convert_number_short( $result['statuses_count'] );
790
791 // prepare url link.
792 if ( $result['url'] && isset( $result['entities']['url'] ) ) {
793 $result['url_entitled'] = $this->add_tweet_entity_links( $result['url'], $result['entities']['url'] );
794 }
795
796 // description with links.
797 if ( isset( $result['entities']['description'] ) ) {
798 $result['description_entitled'] = $this->add_tweet_entity_links( $result['description'], $result['entities']['description'] );
799 }
800
801 set_transient( $cache_name, $result, $cache_expiration );
802 }
803 }
804
805 if ( $result ) {
806 return $this->success( $result );
807 } else {
808 return $this->error( 'no_twitter_data_loaded', __( 'Twitter data failed to load.', 'ghostkit' ) );
809 }
810 }
811
812 /**
813 * Get Twitter feed.
814 *
815 * @param WP_REST_Request $request request object.
816 *
817 * @return mixed
818 */
819 public function get_twitter_feed( WP_REST_Request $request ) {
820 $cache_name = 'ghostkit_twitter_feed_cache';
821 $cache_expiration = $request->get_param( 'cache_expiration' ) ? $request->get_param( 'cache_expiration' ) : DAY_IN_SECONDS;
822
823 $count = (int) ( $request->get_param( 'count' ) ? $request->get_param( 'count' ) : 6 );
824 $consumer_key = $request->get_param( 'consumer_key' );
825 $consumer_secret = $request->get_param( 'consumer_secret' );
826 $access_token = $request->get_param( 'access_token' );
827 $access_token_secret = $request->get_param( 'access_token_secret' );
828 $screen_name = $request->get_param( 'screen_name' );
829 $exclude_replies = 'true' === $request->get_param( 'exclude_replies' );
830 $include_rts = 'true' === $request->get_param( 'include_rts' );
831 $tweet_mode_extended = 'true' === $request->get_param( 'tweet_mode_extended' );
832
833 $api_data_ready = $consumer_key && $consumer_secret && $access_token && $access_token_secret;
834
835 if ( ! $consumer_key ) {
836 return $this->error( 'no_consumer_key_found', __( 'Provide Twitter Consumer Key.', 'ghostkit' ) );
837 }
838 if ( ! $consumer_secret ) {
839 return $this->error( 'no_consumer_secret_found', __( 'Provide Twitter Consumer Secret.', 'ghostkit' ) );
840 }
841 if ( ! $access_token ) {
842 return $this->error( 'no_access_token_found', __( 'Provide Twitter Access Token.', 'ghostkit' ) );
843 }
844 if ( ! $access_token_secret ) {
845 return $this->error( 'no_access_token_secret_found', __( 'Provide Twitter Access Token Secret.', 'ghostkit' ) );
846 }
847 if ( ! $screen_name ) {
848 return $this->error( 'no_screen_name_found', __( 'Provide Username.', 'ghostkit' ) );
849 }
850
851 $hash = md5(
852 wp_json_encode(
853 array(
854 $consumer_key,
855 $consumer_secret,
856 $access_token,
857 $access_token_secret,
858 $cache_expiration,
859 $tweet_mode_extended,
860 )
861 )
862 );
863
864 $cache_name = $cache_name . '_' . $screen_name . '_' . $hash;
865
866 // get cached data.
867 $feed = get_transient( $cache_name );
868
869 $result = array();
870
871 if ( $api_data_ready ) {
872 // if there is no cache available, request twitter feed.
873 if ( false === $feed ) {
874 $feed = $this->request_api_twitter(
875 array(
876 'url' => 'https://api.twitter.com/1.1/statuses/user_timeline.json',
877 'consumer_key' => $consumer_key,
878 'consumer_secret' => $consumer_secret,
879 'access_token' => $access_token,
880 'access_token_secret' => $access_token_secret,
881 'screen_name' => $screen_name,
882 'tweet_mode_extended' => $tweet_mode_extended,
883 'exclude_replies' => 'false',
884 'include_rts' => 'true',
885 'count' => 200,
886 )
887 );
888
889 if ( $feed && ! ( isset( $feed['errors'] ) && count( $feed['errors'] ) > 0 ) ) {
890 set_transient( $cache_name, $feed, $cache_expiration );
891 } else {
892 $feed = false;
893 }
894 }
895
896 $tweets_count = $feed ? count( $feed ) : 0;
897 $limit_to_display = min( $count, $tweets_count );
898
899 if ( $limit_to_display > 0 ) {
900 for ( $i = 0; $i < $tweets_count; $i++ ) {
901 $new_item = $feed[ $i ];
902
903 // check for replies.
904 if ( $exclude_replies && $new_item['in_reply_to_user_id'] ) {
905 continue;
906 }
907
908 // check for retweets.
909 if ( ! $include_rts && isset( $new_item['retweeted_status'] ) ) {
910 continue;
911 }
912
913 // full text.
914 if ( $tweet_mode_extended || ! isset( $new_item['text'] ) ) {
915 $text = isset( $new_item['full_text'] ) ? $new_item['full_text'] : null;
916
917 if ( null === $text ) {
918 $text = isset( $new_item['text'] ) ? $new_item['text'] : '';
919 }
920
921 $new_item['text'] = $text;
922 }
923
924 // prepare tweet content.
925 $new_item = $this->prepare_tweet_content( $new_item );
926
927 if ( isset( $new_item['retweeted_status'] ) ) {
928 // full text.
929 if ( $tweet_mode_extended || ! isset( $new_item['retweeted_status']['text'] ) ) {
930 $text = isset( $new_item['retweeted_status']['full_text'] ) ? $new_item['retweeted_status']['full_text'] : null;
931
932 if ( null === $text ) {
933 $text = isset( $new_item['retweeted_status']['text'] ) ? $new_item['retweeted_status']['text'] : '';
934 }
935
936 $new_item['retweeted_status']['text'] = $text;
937 }
938
939 $new_item['retweeted_status'] = $this->prepare_tweet_content( $new_item['retweeted_status'] );
940 }
941
942 $result[] = $new_item;
943
944 if ( count( $result ) >= $limit_to_display ) {
945 break;
946 }
947 }
948 }
949 }
950
951 if ( $result ) {
952 return $this->success( $result );
953 } else {
954 return $this->error( 'no_twitter_data_loaded', __( 'Twitter data failed to load.', 'ghostkit' ) );
955 }
956 }
957
958 /**
959 * Get Twitter API url result
960 *
961 * @param array $data - api request data.
962 *
963 * @return bool|mixed
964 */
965 public function request_api_twitter( $data ) {
966 $data = array_merge(
967 array(
968 'url' => 'https://api.twitter.com/1.1/statuses/user_timeline.json',
969 'consumer_key' => '',
970 'consumer_secret' => '',
971 'access_token' => '',
972 'access_token_secret' => '',
973 'screen_name' => '',
974 'exclude_replies' => '',
975 'include_rts' => '',
976 'count' => '',
977 'include_entities' => '',
978 'tweet_mode_extended' => '',
979 ),
980 $data
981 );
982
983 $oauth = array(
984 'oauth_consumer_key' => $data['consumer_key'],
985 'oauth_nonce' => time(),
986 'oauth_signature_method' => 'HMAC-SHA1',
987 'oauth_token' => $data['access_token'],
988 'oauth_timestamp' => time(),
989 'oauth_version' => '1.0',
990 );
991
992 $base_info_url = $data['url'];
993
994 if ( $data['screen_name'] ) {
995 $data['url'] .= strpos( $data['url'], '?' ) !== false ? '&' : '?';
996 $data['url'] .= 'screen_name=' . $data['screen_name'];
997 $oauth['screen_name'] = $data['screen_name'];
998 }
999 if ( $data['exclude_replies'] ) {
1000 $data['url'] .= strpos( $data['url'], '?' ) !== false ? '&' : '?';
1001 $data['url'] .= 'exclude_replies=' . $data['exclude_replies'];
1002 $oauth['exclude_replies'] = $data['exclude_replies'];
1003 }
1004 if ( $data['include_rts'] ) {
1005 $data['url'] .= strpos( $data['url'], '?' ) !== false ? '&' : '?';
1006 $data['url'] .= 'include_rts=' . $data['include_rts'];
1007 $oauth['include_rts'] = $data['include_rts'];
1008 }
1009 if ( $data['count'] ) {
1010 $data['url'] .= strpos( $data['url'], '?' ) !== false ? '&' : '?';
1011 $data['url'] .= 'count=' . $data['count'];
1012 $oauth['count'] = $data['count'];
1013 }
1014 if ( $data['include_entities'] ) {
1015 $data['url'] .= strpos( $data['url'], '?' ) !== false ? '&' : '?';
1016 $data['url'] .= 'include_entities=' . $data['include_entities'];
1017 $oauth['include_entities'] = $data['include_entities'];
1018 }
1019
1020 // Tweet Mode.
1021 if ( $data['tweet_mode_extended'] ) {
1022 $data['url'] .= strpos( $data['url'], '?' ) !== false ? '&' : '?';
1023 $data['url'] .= 'tweet_mode=extended';
1024 $oauth['tweet_mode'] = 'extended';
1025 }
1026
1027 $base_info = $this->build_base_string( $base_info_url, 'GET', $oauth );
1028 $composite_key = rawurlencode( $data['consumer_secret'] ) . '&' . rawurlencode( $data['access_token_secret'] );
1029
1030 // phpcs:ignore
1031 $oauth_signature = base64_encode( hash_hmac( 'sha1', $base_info, $composite_key, true ) );
1032 $oauth['oauth_signature'] = $oauth_signature;
1033
1034 // Make Requests.
1035 $header = array( $this->build_authorization_header( $oauth ), 'Expect:' );
1036 $options_buf = wp_remote_get(
1037 $data['url'],
1038 array(
1039 'headers' => implode( "\n", $header ),
1040 'sslverify' => false,
1041 )
1042 );
1043
1044 if ( ! is_wp_error( $options_buf ) && isset( $options_buf['body'] ) ) {
1045 return json_decode( $options_buf['body'], true );
1046 } else {
1047 return false;
1048 }
1049 }
1050
1051 /**
1052 * Build base string
1053 *
1054 * @param string $base_uri - url.
1055 * @param string $method - method.
1056 * @param array $params - params.
1057 *
1058 * @return string
1059 */
1060 private function build_base_string( $base_uri, $method, $params ) {
1061 $r = array();
1062 ksort( $params );
1063 foreach ( $params as $key => $value ) {
1064 $r[] = "$key=" . rawurlencode( $value );
1065 }
1066 return $method . '&' . rawurlencode( $base_uri ) . '&' . rawurlencode( implode( '&', $r ) );
1067 }
1068
1069 /**
1070 * Build authorization header
1071 *
1072 * @param array $oauth - auth data.
1073 *
1074 * @return string
1075 */
1076 private function build_authorization_header( $oauth ) {
1077 $r = 'Authorization: OAuth ';
1078 $values = array();
1079
1080 foreach ( $oauth as $key => $value ) {
1081 $values[] = "$key=\"" . rawurlencode( $value ) . '"';
1082 }
1083
1084 $r .= implode( ', ', $values );
1085
1086 return $r;
1087 }
1088
1089 /**
1090 * Prepare tweet content.
1091 *
1092 * @param array $tweet - tweet data.
1093 *
1094 * @return array - new tweet data.
1095 */
1096 public function prepare_tweet_content( $tweet ) {
1097 // prepare different profile image sizes.
1098 if ( $tweet['user']['profile_image_url'] ) {
1099 $tweet['user']['profile_images'] = $this->get_twitter_profile_images( $tweet['user']['profile_image_url'] );
1100 }
1101 if ( $tweet['user']['profile_image_url_https'] ) {
1102 $tweet['user']['profile_images_https'] = $this->get_twitter_profile_images( $tweet['user']['profile_image_url_https'] );
1103 }
1104
1105 // prepare short counts.
1106 $tweet['retweet_count_short'] = $this->convert_number_short( $tweet['retweet_count'] );
1107 $tweet['favorite_count_short'] = $this->convert_number_short( $tweet['favorite_count'] );
1108
1109 // user friendly date.
1110 $date = strtotime( $tweet['created_at'] );
1111 $now = time();
1112 $diff_date = $now - $date;
1113
1114 if ( $diff_date / 60 < 1 ) {
1115 // seconds.
1116 // translators: %d - seconds.
1117 $date = sprintf( esc_html__( '%ds', 'ghostkit' ), intval( $diff_date % 60 ) );
1118 } elseif ( $diff_date / 60 < 60 ) {
1119 // minutes.
1120 // translators: %d - minutes.
1121 $date = sprintf( esc_html__( '%dm', 'ghostkit' ), intval( $diff_date / 60 ) );
1122 } elseif ( $diff_date / 3600 < 24 ) {
1123 // hours.
1124 // translators: %d - hours.
1125 $date = sprintf( esc_html__( '%dh', 'ghostkit' ), intval( $diff_date / 3600 ) );
1126 } elseif ( gmdate( 'Y' ) === gmdate( 'Y', $date ) ) {
1127 // current year.
1128 $date = gmdate( esc_html__( 'M j', 'ghostkit' ), $date );
1129 } else {
1130 // past years.
1131 $date = gmdate( esc_html__( 'Y M j', 'ghostkit' ), $date );
1132 }
1133
1134 $tweet['date_formatted'] = $date;
1135
1136 // text with links and media.
1137 $tweet['text_entitled'] = $this->add_tweet_entity_links( $tweet['text'], $tweet['entities'] );
1138
1139 // text with links only.
1140 $tweet['text_entitled_no_media'] = $this->add_tweet_entity_links( $tweet['text'], $tweet['entities'], false );
1141
1142 return $tweet;
1143 }
1144
1145 /**
1146 * Adds a link around any entities in a twitter feed
1147 * twitter entities include urls, user mentions, hashtags and media
1148 * http://stackoverflow.com/a/15390225
1149 *
1150 * @param string $text - tweet text.
1151 * @param array $entities - available entities.
1152 * @param boolean $show_media - show tweet images.
1153 *
1154 * @return string tweet
1155 */
1156 public function add_tweet_entity_links( $text, $entities, $show_media = true ) {
1157 $replacements = array();
1158 if ( isset( $entities['hashtags'] ) ) {
1159 foreach ( $entities['hashtags'] as $hashtag ) {
1160 list ($start, $end) = $hashtag['indices'];
1161 $replacements[ $start ] = array(
1162 $start,
1163 $end,
1164 "<a href=\"https://twitter.com/hashtag/{$hashtag['text']}\" target=\"_blank\">#{$hashtag['text']}</a>",
1165 );
1166 }
1167 }
1168 if ( isset( $entities['urls'] ) ) {
1169 foreach ( $entities['urls'] as $url ) {
1170 list ($start, $end) = $url['indices'];
1171 // you can also use $url['expanded_url'] in place of $url['url'].
1172 $replacements[ $start ] = array(
1173 $start,
1174 $end,
1175 "<a href=\"{$url['url']}\" target=\"_blank\">{$url['display_url']}</a>",
1176 );
1177 }
1178 }
1179 if ( isset( $entities['user_mentions'] ) ) {
1180 foreach ( $entities['user_mentions'] as $mention ) {
1181 list ($start, $end) = $mention['indices'];
1182 $replacements[ $start ] = array(
1183 $start,
1184 $end,
1185 "<a href=\"https://twitter.com/{$mention['screen_name']}\" target=\"_blank\">@{$mention['screen_name']}</a>",
1186 );
1187 }
1188 }
1189 if ( isset( $entities['media'] ) ) {
1190 foreach ( $entities['media'] as $media ) {
1191 list ($start, $end) = $media['indices'];
1192
1193 if ( $show_media ) {
1194 $replacements[ $start ] = array(
1195 $start,
1196 $end,
1197 "<div><a href=\"{$media['url']}\" target=\"_blank\"><img src=\"{$media['media_url_https']}\" /></a></div>",
1198 );
1199 } else {
1200 $replacements[ $start ] = array(
1201 $start,
1202 $end,
1203 "<a href=\"{$media['url']}\" target=\"_blank\">{$media['url']}</a>",
1204 );
1205 }
1206 }
1207 }
1208
1209 // sort in reverse order by start location.
1210 krsort( $replacements );
1211
1212 foreach ( $replacements as $replace_data ) {
1213 list ($start, $end, $replace_text) = $replace_data;
1214
1215 $text = mb_substr( $text, 0, $start, 'UTF-8' ) . $replace_text . mb_substr( $text, $end, null, 'UTF-8' );
1216 }
1217
1218 return $text;
1219 }
1220
1221 /**
1222 * Convert long numbers to short. eg: 1500 -> 1.5K
1223 * Thanks https://code.recuweb.com/2018/php-format-numbers-to-nearest-thousands/ .
1224 *
1225 * @param number $num - number.
1226 * @return string
1227 */
1228 public function convert_number_short( $num ) {
1229 if ( $num > 1000 ) {
1230 $x = round( $num );
1231 $x_number_format = number_format( $x );
1232 $x_array = explode( ',', $x_number_format );
1233 $x_parts = array( 'K', 'M', 'B', 'T' );
1234 $x_count_parts = count( $x_array ) - 1;
1235 $x_display = $x;
1236 $x_display = $x_array[0] . ( (int) 0 !== $x_array[1][0] ? '.' . $x_array[1][0] : '' );
1237 $x_display .= $x_parts[ $x_count_parts - 1 ];
1238
1239 return $x_display;
1240 }
1241
1242 return $num;
1243 }
1244
1245 /**
1246 * Prepare profile image urls
1247 * https://developer.twitter.com/en/docs/accounts-and-users/user-profile-images-and-banners
1248 *
1249 * @param string $url - profile image.
1250 *
1251 * @return array images
1252 */
1253 public function get_twitter_profile_images( $url ) {
1254 if ( strpos( $url, '.jpg' ) !== false ) {
1255 return array(
1256 'normal' => $url,
1257 'bigger' => str_replace( '_normal.jpg', '_bigger.jpg', $url ),
1258 'mini' => str_replace( '_normal.jpg', '_mini.jpg', $url ),
1259 'original' => str_replace( '_normal.jpg', '.jpg', $url ),
1260 );
1261 }
1262
1263 return array(
1264 'normal' => $url,
1265 'bigger' => str_replace( '_normal.png', '_bigger.png', $url ),
1266 'mini' => str_replace( '_normal.png', '_mini.png', $url ),
1267 'original' => str_replace( '_normal.png', '.png', $url ),
1268 );
1269 }
1270
1271 /**
1272 * Get TOC.
1273 *
1274 * @param WP_REST_Request $request request object.
1275 *
1276 * @return mixed
1277 */
1278 public function get_table_of_contents( WP_REST_Request $request ) {
1279 $headings = $request->get_param( 'headings' );
1280 $allowed_headers = $request->get_param( 'allowedHeaders' );
1281 $list_style = $request->get_param( 'listStyle' ) ? $request->get_param( 'listStyle' ) : 'ol';
1282
1283 $html = '';
1284
1285 if ( ! $allowed_headers || empty( $allowed_headers ) ) {
1286 return $this->success( $html );
1287 }
1288
1289 // covert string values to int.
1290 $allowed_headers = array_map( 'intval', $allowed_headers );
1291
1292 $current_depth = 6;
1293 $numbered_items = array();
1294 $numbered_items_min = null;
1295 $count = count( $headings );
1296
1297 // find the minimum heading to establish our baseline.
1298 for ( $i = 0; $i < $count; $i++ ) {
1299 if ( $current_depth > (int) $headings[ $i ]['level'] ) {
1300 $current_depth = (int) $headings[ $i ]['level'];
1301 }
1302 }
1303
1304 $numbered_items[ $current_depth ] = 0;
1305 $numbered_items_min = $current_depth;
1306 for ( $i = 0; $i < $count; $i ++ ) {
1307 if ( $current_depth === (int) $headings[ $i ]['level'] ) {
1308 $html .= '<li>';
1309 }
1310
1311 // start lists.
1312 if ( $current_depth !== (int) $headings[ $i ]['level'] ) {
1313 for ( $current_depth; $current_depth < (int) $headings[ $i ]['level']; $current_depth++ ) {
1314 $numbered_items[ $current_depth + 1 ] = 0;
1315
1316 if ( ! in_array( $current_depth, $allowed_headers, true ) ) {
1317 continue;
1318 }
1319
1320 $html .= '<ul>';
1321 $html .= '<li>';
1322 }
1323 }
1324
1325 $html .= '<a href="' . esc_attr( '#' . $headings[ $i ]['anchor'] ) . '">' . wp_kses_post( $headings[ $i ]['content'] ) . '</a>';
1326
1327 // end lists.
1328 if ( $i !== $count - 1 ) {
1329 if ( $current_depth > (int) $headings[ $i + 1 ]['level'] ) {
1330 for ( $current_depth; $current_depth > (int) $headings[ $i + 1 ]['level']; $current_depth-- ) {
1331 $numbered_items[ $current_depth ] = 0;
1332
1333 if ( ! in_array( $current_depth, $allowed_headers, true ) ) {
1334 continue;
1335 }
1336
1337 $html .= '</li>';
1338 $html .= '</ul>';
1339 }
1340 }
1341 if ( isset( $headings[ $i + 1 ]['level'] ) && (int) $headings[ $i + 1 ]['level'] === $current_depth ) {
1342 $html .= '</li>';
1343 }
1344 } else {
1345 // this is the last item, make sure we close off all tags.
1346 for ( $current_depth; $current_depth >= $numbered_items_min; $current_depth-- ) {
1347 if ( ! in_array( $current_depth, $allowed_headers, true ) ) {
1348 continue;
1349 }
1350
1351 $html .= '</li>';
1352 if ( $current_depth !== $numbered_items_min ) {
1353 $html .= '</ul>';
1354 }
1355 }
1356 }
1357 }
1358
1359 // Wrapper.
1360 if ( $html ) {
1361 $list = 'ol';
1362 $list_class_name = '';
1363
1364 switch ( $list_style ) {
1365 case 'ul':
1366 $list = 'ul';
1367 break;
1368 case 'ul-styled':
1369 $list = 'ul';
1370 $list_class_name = 'is-style-styled';
1371 break;
1372 case 'ol-styled':
1373 $list_class_name = 'is-style-styled';
1374 break;
1375 }
1376
1377 $html = '<' . $list . ( $list_class_name ? ( ' class="' . $list_class_name . '"' ) : '' ) . '>' . $html . '</' . $list . '>';
1378 }
1379
1380 return $this->success( $html );
1381 }
1382
1383 /**
1384 * Get templates.
1385 *
1386 * @return mixed
1387 */
1388 public function get_templates() {
1389 $url = 'https://library.ghostkit.io/wp-json/ghostkit-library/v1/get_library/';
1390 $templates = get_transient( 'ghostkit_remote_templates', false );
1391
1392 /*
1393 * Get remote templates.
1394 */
1395 if ( ! $templates ) {
1396 $requested_templates = wp_remote_get(
1397 add_query_arg(
1398 array(
1399 'ghostkit_version' => GHOSTKIT_VERSION,
1400 'ghostkit_pro' => function_exists( 'ghostkit_pro' ),
1401 'ghostkit_pro_version' => function_exists( 'ghostkit_pro' ) ? ghostkit_pro()->plugin_version : null,
1402 ),
1403 $url
1404 )
1405 );
1406
1407 if ( ! is_wp_error( $requested_templates ) ) {
1408 $new_templates = wp_remote_retrieve_body( $requested_templates );
1409 $new_templates = json_decode( $new_templates, true );
1410
1411 if ( $new_templates && isset( $new_templates['response'] ) && is_array( $new_templates['response'] ) ) {
1412 $templates = $new_templates['response'];
1413 set_transient( 'ghostkit_remote_templates', $templates, DAY_IN_SECONDS );
1414 }
1415 }
1416 }
1417
1418 // Remove Pro templates from array, cause for now there is no way to check if pro addon is activated.
1419 if ( $templates ) {
1420 foreach ( $templates as $k => $template ) {
1421 $is_pro = false;
1422
1423 if ( isset( $template['types'] ) && is_array( $template['types'] ) ) {
1424 foreach ( $template['types'] as $type ) {
1425 $is_pro = $is_pro || 'pro' === $type['slug'];
1426 }
1427 }
1428
1429 if ( $is_pro ) {
1430 unset( $templates[ $k ] );
1431 }
1432 }
1433 }
1434
1435 /*
1436 * Get user templates from db.
1437 */
1438
1439 // Stupid hack.
1440 // https://core.trac.wordpress.org/ticket/18408.
1441 global $post;
1442 $backup_global_post = $post;
1443 $local_templates = array();
1444
1445 $local_templates_query = new WP_Query(
1446 array(
1447 'post_type' => 'ghostkit_template',
1448 'posts_per_page' => -1,
1449 'showposts' => -1,
1450 'paged' => -1,
1451 )
1452 );
1453
1454 while ( $local_templates_query->have_posts() ) {
1455 $local_templates_query->the_post();
1456 $db_template = get_post();
1457
1458 $categories = array();
1459 $category_terms = get_the_terms( $db_template->ID, 'ghostkit_template_category' );
1460
1461 if ( $category_terms ) {
1462 foreach ( $category_terms as $cat ) {
1463 $categories[] = array(
1464 'slug' => $cat->slug,
1465 'name' => $cat->name,
1466 );
1467 }
1468 }
1469
1470 $image_id = get_post_thumbnail_id( $db_template->ID );
1471 $image_data = wp_get_attachment_image_src( $image_id, 'large' );
1472
1473 $local_templates[] = array(
1474 'id' => $db_template->ID,
1475 'title' => $db_template->post_title,
1476 'types' => array(
1477 array(
1478 'slug' => 'local',
1479 ),
1480 ),
1481 'categories' => empty( $categories ) ? false : $categories,
1482 'url' => get_post_permalink( $db_template->ID ),
1483 'thumbnail' => isset( $image_data[0] ) ? $image_data[0] : false,
1484 'thumbnail_width' => isset( $image_data[1] ) ? $image_data[1] : false,
1485 'thumbnail_height' => isset( $image_data[2] ) ? $image_data[2] : false,
1486 );
1487 }
1488
1489 // Restore the global $post as it was before custom WP_Query.
1490 // phpcs:ignore
1491 $post = $backup_global_post;
1492
1493 /*
1494 * Get theme templates.
1495 */
1496 $theme_templates = array();
1497 $theme_templates_data = array();
1498
1499 foreach ( glob( get_template_directory() . '/ghostkit/templates/*/content.php' ) as $template ) {
1500 $template_path = dirname( $template );
1501 $template_url = get_template_directory_uri() . str_replace( get_template_directory(), '', $template_path );
1502 $slug = basename( $template_path );
1503
1504 $theme_templates_data[ $slug ] = array(
1505 'slug' => $slug,
1506 'path' => $template_path,
1507 'url' => $template_url,
1508 );
1509 }
1510
1511 // get child theme templates.
1512 if ( get_stylesheet_directory() !== get_template_directory() ) {
1513 foreach ( glob( get_stylesheet_directory() . '/ghostkit/templates/*/content.php' ) as $template ) {
1514 $template_path = dirname( $template );
1515 $template_url = get_stylesheet_directory_uri() . str_replace( get_stylesheet_directory(), '', $template_path );
1516 $slug = basename( $template_path );
1517
1518 $theme_templates_data[ $slug ] = array(
1519 'slug' => $slug,
1520 'path' => $template_path,
1521 'url' => $template_url,
1522 );
1523 }
1524 }
1525
1526 // natural sort.
1527 array_multisort( array_keys( $theme_templates_data ), SORT_NATURAL, $theme_templates_data );
1528
1529 foreach ( $theme_templates_data as $template_data ) {
1530 $file_data = get_file_data(
1531 $template_data['path'] . '/content.php',
1532 array(
1533 'name' => 'Name',
1534 'category' => 'Category',
1535 'source' => 'Source',
1536 )
1537 );
1538
1539 $thumbnail = false;
1540 $thumbnail_width = false;
1541 $thumbnail_height = false;
1542
1543 if ( file_exists( $template_data['path'] . '/thumbnail.png' ) ) {
1544 $thumbnail = $template_data['url'] . '/thumbnail.png';
1545
1546 list($thumbnail_width, $thumbnail_height) = getimagesize( $thumbnail );
1547 }
1548
1549 if ( file_exists( $template_data['path'] . '/thumbnail.jpg' ) ) {
1550 $thumbnail = $template_data['url'] . '/thumbnail.jpg';
1551 }
1552
1553 $theme_templates[] = array(
1554 'id' => basename( $template_data['path'] ),
1555 'title' => $file_data['name'],
1556 'types' => array(
1557 array(
1558 'slug' => 'theme',
1559 ),
1560 ),
1561 'categories' => isset( $file_data['category'] ) && $file_data['category'] ? array(
1562 array(
1563 'slug' => $file_data['category'],
1564 'name' => $file_data['category'],
1565 ),
1566 ) : false,
1567 'url' => false,
1568 'thumbnail' => $thumbnail,
1569 'thumbnail_width' => $thumbnail_width,
1570 'thumbnail_height' => $thumbnail_height,
1571 );
1572 }
1573
1574 // merge all available templates.
1575 $templates = array_merge( $templates, $local_templates, $theme_templates );
1576
1577 if ( is_array( $templates ) ) {
1578 return $this->success( $templates );
1579 } else {
1580 return $this->error( 'no_templates', __( 'Templates not found.', 'ghostkit' ) );
1581 }
1582 }
1583
1584 /**
1585 * Get templates.
1586 *
1587 * @param WP_REST_Request $request request object.
1588 *
1589 * @return mixed
1590 */
1591 public function get_template_data( WP_REST_Request $request ) {
1592 $url = 'https://library.ghostkit.io/wp-json/ghostkit-library/v1/get_library_item/';
1593 $id = $request->get_param( 'id' );
1594 $type = $request->get_param( 'type' );
1595 $template_data = false;
1596
1597 // Validation and security checks.
1598 if ( empty( $id ) || ! preg_match( '/^[a-zA-Z0-9_-]+$/', $id ) ) {
1599 return $this->error( 'invalid_id', __( 'Invalid template ID.', 'ghostkit' ) );
1600 }
1601
1602 switch ( $type ) {
1603 case 'remote':
1604 $template_data = get_transient( 'ghostkit_template_' . $type . '_' . $id, false );
1605
1606 if ( ! $template_data ) {
1607 $requested_template_data = wp_remote_get(
1608 add_query_arg(
1609 array(
1610 'id' => $id,
1611 'ghostkit_version' => GHOSTKIT_VERSION,
1612 'ghostkit_pro' => function_exists( 'ghostkit_pro' ),
1613 'ghostkit_pro_version' => function_exists( 'ghostkit_pro' ) ? ghostkit_pro()->plugin_version : null,
1614 ),
1615 $url
1616 )
1617 );
1618
1619 if ( ! is_wp_error( $requested_template_data ) ) {
1620 $new_template_data = wp_remote_retrieve_body( $requested_template_data );
1621 $new_template_data = json_decode( $new_template_data, true );
1622
1623 if ( $new_template_data && isset( $new_template_data['response'] ) && is_array( $new_template_data['response'] ) ) {
1624 $template_data = $new_template_data['response'];
1625 set_transient( 'ghostkit_template_' . $type . '_' . $id, $template_data, DAY_IN_SECONDS );
1626 }
1627 }
1628 }
1629 break;
1630 case 'local':
1631 $post = get_post( $id );
1632
1633 if ( $post && 'ghostkit_template' === $post->post_type ) {
1634 $template_data = array(
1635 'id' => $post->ID,
1636 'title' => $post->post_title,
1637 'content' => $post->post_content,
1638 );
1639 }
1640
1641 break;
1642 case 'theme':
1643 $template_content_file = get_stylesheet_directory() . '/ghostkit/templates/' . $id . '/content.php';
1644
1645 if ( ! file_exists( $template_content_file ) ) {
1646 $template_content_file = get_template_directory() . '/ghostkit/templates/' . $id . '/content.php';
1647 }
1648
1649 if ( file_exists( $template_content_file ) ) {
1650 ob_start();
1651 include $template_content_file;
1652 $template_content = ob_get_clean();
1653
1654 if ( $template_content ) {
1655 $template_data = get_file_data(
1656 $template_content_file,
1657 array(
1658 'name' => 'Name',
1659 )
1660 );
1661
1662 $template_data = array(
1663 'id' => $id,
1664 'title' => $template_data['name'],
1665 'content' => $template_content,
1666 );
1667 }
1668 }
1669 break;
1670 }
1671
1672 if ( is_array( $template_data ) ) {
1673 return $this->success( $template_data );
1674 } else {
1675 return $this->error( 'no_template_data', __( 'Template data not found.', 'ghostkit' ) );
1676 }
1677 }
1678
1679 /**
1680 * Get custom code.
1681 *
1682 * @return mixed
1683 */
1684 public function get_custom_code() {
1685 $custom_code = get_option( 'ghostkit_custom_code', array() );
1686
1687 if ( is_array( $custom_code ) ) {
1688 return $this->success( $custom_code );
1689 } else {
1690 return $this->error( 'no_custom_code', __( 'Custom code not found.', 'ghostkit' ) );
1691 }
1692 }
1693
1694 /**
1695 * Update custom code.
1696 *
1697 * @param WP_REST_Request $request request object.
1698 *
1699 * @return mixed
1700 */
1701 public function update_custom_code( WP_REST_Request $request ) {
1702 $new_code = $request->get_param( 'data' );
1703
1704 if ( is_array( $new_code ) ) {
1705 $current_code = get_option( 'ghostkit_custom_code', array() );
1706 update_option( 'ghostkit_custom_code', array_merge( $current_code, $new_code ) );
1707 }
1708
1709 return $this->success( true );
1710 }
1711
1712 /**
1713 * Update color palette.
1714 *
1715 * @param WP_REST_Request $request request object.
1716 *
1717 * @return mixed
1718 */
1719 public function update_color_palette( WP_REST_Request $request ) {
1720 $colors = $request->get_param( 'data' );
1721
1722 if ( is_array( $colors ) ) {
1723 update_option( 'ghostkit_color_palette', $colors );
1724 }
1725
1726 return $this->success( true );
1727 }
1728
1729 /**
1730 * Get custom typography.
1731 *
1732 * @return mixed
1733 */
1734 public function get_custom_typography() {
1735 $typography = get_option( 'ghostkit_typography', array() );
1736
1737 if ( is_array( $typography ) ) {
1738 return $this->success( $typography );
1739 } else {
1740 return $this->error( 'no_typography', __( 'Typography not found.', 'ghostkit' ) );
1741 }
1742 }
1743
1744 /**
1745 * Update typography.
1746 *
1747 * @param WP_REST_Request $request request object.
1748 *
1749 * @return mixed
1750 */
1751 public function update_custom_typography( WP_REST_Request $request ) {
1752 $new_typography = $request->get_param( 'data' );
1753 $updated_option = array();
1754
1755 if ( is_array( $new_typography ) ) {
1756 $current_typography = get_option( 'ghostkit_typography', array() );
1757
1758 if ( empty( $current_typography ) ) {
1759 $updated_option = $new_typography;
1760 } else {
1761 $current_typography['ghostkit_typography'] = json_decode( $current_typography['ghostkit_typography'], true );
1762 $new_typography['ghostkit_typography'] = json_decode( $new_typography['ghostkit_typography'], true );
1763
1764 $updated_option = array_merge( $current_typography, $new_typography );
1765
1766 $updated_option['ghostkit_typography'] = wp_json_encode( $updated_option['ghostkit_typography'] );
1767 }
1768
1769 update_option( 'ghostkit_typography', $updated_option );
1770 }
1771
1772 return $this->success( true );
1773 }
1774
1775 /**
1776 * Update Google Maps API key.
1777 *
1778 * @param WP_REST_Request $request request object.
1779 *
1780 * @return mixed
1781 */
1782 public function update_google_maps_api_key( WP_REST_Request $request ) {
1783 update_option( 'ghostkit_google_maps_api_key', $request->get_param( 'key' ) );
1784
1785 return $this->success( true );
1786 }
1787
1788 /**
1789 * Update Google reCaptcha API keys.
1790 *
1791 * @param WP_REST_Request $request request object.
1792 *
1793 * @return mixed
1794 */
1795 public function update_google_recaptcha_keys( WP_REST_Request $request ) {
1796 update_option( 'ghostkit_google_recaptcha_api_site_key', $request->get_param( 'site_key' ) );
1797 update_option( 'ghostkit_google_recaptcha_api_secret_key', $request->get_param( 'secret_key' ) );
1798
1799 return $this->success( true );
1800 }
1801
1802 /**
1803 * Update Disabled Blocks.
1804 *
1805 * @param WP_REST_Request $request request object.
1806 *
1807 * @return mixed
1808 */
1809 public function update_disabled_blocks( WP_REST_Request $request ) {
1810 $new_disabled_blocks = $request->get_param( 'blocks' );
1811
1812 if ( is_array( $new_disabled_blocks ) ) {
1813 $disabled_blocks = array_merge( get_option( 'ghostkit_disabled_blocks', array() ), $new_disabled_blocks );
1814 $result = array();
1815
1816 foreach ( $disabled_blocks as $k => $block_disabled ) {
1817 if ( $block_disabled ) {
1818 $result[ $k ] = true;
1819 }
1820 }
1821
1822 update_option( 'ghostkit_disabled_blocks', $result );
1823 }
1824
1825 return $this->success( true );
1826 }
1827
1828 /**
1829 * Update Settings.
1830 *
1831 * @param WP_REST_Request $request request object.
1832 *
1833 * @return mixed
1834 */
1835 public function update_settings( WP_REST_Request $request ) {
1836 $new_settings = $request->get_param( 'settings' );
1837
1838 if ( is_array( $new_settings ) ) {
1839 $current_settings = get_option( 'ghostkit_settings', array() );
1840 update_option( 'ghostkit_settings', array_merge( $current_settings, $new_settings ) );
1841 }
1842
1843 return $this->success( true );
1844 }
1845
1846 /**
1847 * Success rest.
1848 *
1849 * @param mixed $response response data.
1850 * @return mixed
1851 */
1852 public function success( $response ) {
1853 return new WP_REST_Response(
1854 array(
1855 'success' => true,
1856 'response' => $response,
1857 ),
1858 200
1859 );
1860 }
1861
1862 /**
1863 * Error rest.
1864 *
1865 * @param mixed $code error code.
1866 * @param mixed $response response data.
1867 * @param boolean $true_error use true error response to stop the code processing.
1868 * @return mixed
1869 */
1870 public function error( $code, $response, $true_error = false ) {
1871 if ( $true_error ) {
1872 return new WP_Error( $code, $response, array( 'status' => 401 ) );
1873 }
1874
1875 return new WP_REST_Response(
1876 array(
1877 'error' => true,
1878 'success' => false,
1879 'error_code' => $code,
1880 'response' => $response,
1881 ),
1882 401
1883 );
1884 }
1885 }
1886 new GhostKit_Rest();
1887