PluginProbe
Snippet Shortcodes / 5.2
Snippet Shortcodes v5.2
5.2.1 5.2 5.1.8 5.1.6 5.1.7 5.1.5 trunk 1.0 1.1 1.2 1.3 1.3.1 1.4 1.5 1.5.1 1.6 1.6.1 1.7 1.7.1 1.7.2 1.7.3 1.7.4 1.8 2.0 2.0.1 All 74 releases
shortcode-variables / includes / functions.php

functions.php in Snippet Shortcodes 5.2, at includes/functions.php

981 lines 23.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 defined('ABSPATH') or die('Jog on!');
4
5 /**
6 * Is the Premium plugin enabled and do we have a valid license?
7 *
8 * @return bool
9 */
10 function sh_cd_is_premium() {
11
12 if ( false === sh_cd_is_premium_plugin_activated() ) {
13 return false;
14 }
15
16 return apply_filters( 'sh-cd-license-is-premium', false );
17 }
18
19 /**
20 * Is Premium plugin enabled?
21 */
22 function sh_cd_is_premium_plugin_activated() {
23 return defined( 'YK_SS_PLUGIN_NAME' );
24 }
25
26 /**
27 * Generate a site hash to identify this site.
28 **/
29 function sh_cd_generate_site_hash() {
30
31 $site_hash = get_option( 'sh-cd-hash' );
32
33 // Generate a basic site key from URL and plugin slug
34 if( false == $site_hash ) {
35
36 $site_hash = md5( 'yeken-sh-cd-' . site_url() );
37 $site_hash = substr( $site_hash, 0, 6 );
38
39 update_option( 'sh-cd-hash', $site_hash );
40
41 }
42 return $site_hash;
43 }
44
45 /**
46 * Save / Insert a shortcode
47 *
48 * @return bool
49 */
50 function sh_cd_shortcodes_save_post() {
51
52 $fields = apply_filters( 'sh-cd-post-field-keys', [ 'id', 'slug', 'previous_slug', 'data', 'disabled', 'multisite', 'editor' ] );
53
54 // Capture the raw $_POST fields, the save functions will process and validate the data
55 $shortcode = sh_cd_get_values_from_post( $fields );
56
57 // If we are not premium, then the user is not allowed to change the site slug (otherwise they could just re-use variables and by pass the limit)
58 if ( ! sh_cd_is_premium() && false === empty( $shortcode[ 'previous_slug' ] ) ) {
59 $shortcode[ 'slug' ] = $shortcode[ 'previous_slug' ];
60 }
61
62 return sh_cd_db_shortcodes_save( $shortcode );
63 }
64
65 /**
66 * Replace user parameters within a shortcode e.g. look for %%parameter%% and replace
67 *
68 * @param $shortcode
69 * @param $user_defined_parameters
70 *
71 * @return mixed
72 */
73 function sh_cd_apply_user_defined_parameters( $shortcode, $user_defined_parameters ){
74
75 // Ensure we have something to do!
76 if ( true === empty( $user_defined_parameters ) || false === is_array( $user_defined_parameters ) ) {
77 return $shortcode;
78 }
79
80 foreach ( $user_defined_parameters as $key => $value ) {
81 $shortcode = str_replace( '%%' . $key . '%%', esc_attr( $value ), $shortcode );
82 }
83
84 return $shortcode;
85 }
86
87 /**
88 * Generate a unique slug
89 *
90 * @param $slug
91 *
92 * @return string
93 */
94 function sh_cd_slug_generate( $slug, $exising_id = NULL ) {
95
96 if ( true === empty( $slug ) ) {
97 return NULL;
98 }
99
100 $slug = sanitize_key( $slug );
101
102 $original_slug = $slug;
103
104 $try = 1;
105
106 // Ensure the slug is unique
107 while ( false === sh_cd_slug_is_unique( $slug, $exising_id ) ) {
108
109 $slug = sprintf( '%s_%d', $original_slug, $try );
110
111 $try++;
112 }
113
114 return $slug;
115 }
116
117 /**
118 * Clone an existing shortcode!
119 *
120 * @param $id
121 *
122 * @return bool
123 */
124 function sh_cd_clone( $id ) {
125
126 if( false === sh_cd_is_premium() ) {
127 return true;
128 }
129
130 if ( false === is_numeric( $id ) ) {
131 return false;
132 }
133
134 $to_be_cloned = sh_cd_db_shortcodes_by_id( $id );
135
136 if ( true === empty( $to_be_cloned ) ) {
137 return false;
138 }
139
140 unset( $to_be_cloned['id'] );
141
142 return sh_cd_db_shortcodes_save( $to_be_cloned );
143 }
144
145 /**
146 * Display message in admin UI
147 *
148 * @param $text
149 * @param bool $error
150 */
151 function sh_cd_message_display( $text, $error = false ) {
152
153 if ( true === empty( $text ) ) {
154 return;
155 }
156
157 printf( '<div class="%s"><p>%s</p></div>',
158 true === $error ? 'error' : 'updated',
159 esc_html( $text )
160 );
161
162 //TODO: Hook this to use admin_notices
163 }
164
165 /**
166 * Fetch cache item
167 *
168 * @param $key
169 *
170 * @return mixed
171 */
172 function sh_cd_cache_get( $key ) {
173
174 $key = sh_cd_cache_generate_key( $key );
175
176 return get_transient( $key );
177 }
178
179 /**
180 * Set cache item
181 *
182 * @param $key
183 * @param $data
184 */
185 function sh_cd_cache_set( $key, $data, $expire = NULL ) {
186
187
188 $expire = ( false === empty( $expire ) ) ? (int) $expire : 1 * HOUR_IN_SECONDS;
189
190 $key = sh_cd_cache_generate_key( $key );
191
192 set_transient( $key, $data, $expire );
193
194 do_action( 'sh-cd-global-cache-delete' );
195 }
196
197 /**
198 * Delete cache for given shortcode slug / ID
199 *
200 * @param $slug_or_key
201 */
202 function sh_cd_cache_delete_by_slug_or_key( $slug_or_key ) {
203
204 if ( true === is_numeric( $slug_or_key ) ) {
205
206 $slug_or_key = sh_cd_db_shortcodes_get_slug_by_id( $slug_or_key );
207
208 sh_cd_cache_delete( $slug_or_key );
209
210 } else {
211 sh_cd_cache_delete( $slug_or_key );
212 }
213
214 // Delete site option
215 $slug_or_key = SH_CD_PREFIX . $slug_or_key;
216
217 delete_site_option( $slug_or_key );
218
219 }
220
221 /**
222 * Delete cache item
223 *
224 * @param $key
225 *
226 * @return mixed
227 */
228 function sh_cd_cache_delete( $key, $trigger_global_hook = true ) {
229
230 $key = sh_cd_cache_generate_key( $key );
231
232 if ( true === $trigger_global_hook ) {
233 do_action( 'sh-cd-global-cache-delete' );
234 }
235
236 return delete_transient( $key );
237 }
238
239
240 /**
241 * Generate cache key
242 *
243 * @param $key
244 *
245 * @return string
246 */
247 function sh_cd_cache_generate_key( $key ) {
248 return SH_CD_SHORTCODE . SH_CD_PLUGIN_VERSION . $key;
249 }
250
251 /**
252 * Return link to list own shortcodes
253 *
254 * @return mixed
255 */
256 function sh_cd_link_your_shortcodes() {
257
258 $link = admin_url('admin.php?page=sh-cd-shortcode-variables-your-shortcodes');
259
260 return esc_url( $link );
261 }
262
263 /**
264 * Return link to add own shortcode
265 *
266 * @return mixed
267 */
268 function sh_cd_link_your_shortcodes_add() {
269
270 $link = admin_url('admin.php?page=sh-cd-shortcode-variables-your-shortcodes&action=add');
271
272 return esc_url( $link );
273 }
274
275 /**
276 * Return link to edit own shortcode
277 *
278 * @return mixed
279 */
280 function sh_cd_link_your_shortcodes_edit( $id ) {
281
282 $link = admin_url('admin.php?page=sh-cd-shortcode-variables-your-shortcodes&action=edit&id=' . (int) $id );
283
284 return esc_url( $link );
285 }
286
287 /**
288 * Either fetch data from the $_POST object or from the array passed in!
289 *
290 * @param $object
291 * @param $key
292 * @return string
293 */
294 function sh_cd_get_value_from_post_or_obj( $object, $key ) {
295
296 if ( true === isset( $_POST[ $key ] ) ) {
297 return $_POST[ $key ];
298 }
299
300 if ( true === isset( $object[ $key ] ) ) {
301 return $object[ $key ];
302 }
303
304 return '';
305 }
306
307 /**
308 * Either fetch data from the $_POST object for the given object keys
309 *
310 * @param $keys
311 * @return array
312 */
313 function sh_cd_get_values_from_post( $keys ) {
314
315 $data = [];
316
317 foreach ( $keys as $key ) {
318
319 if ( true === isset( $_POST[ $key ] ) ) {
320 $data[ $key ] = $_POST[ $key ];
321 } else {
322 $data[ $key ] = '';
323 }
324
325 }
326
327 return $data;
328 }
329
330 /**
331 * Toggle the status of a shortcode
332 *
333 * @param $id
334 */
335 function sh_cd_toggle_status( $id ) {
336
337 $slug = sh_cd_db_shortcodes_by_id( (int) $id );
338
339 if ( false === empty( $slug ) ) {
340
341 $status = ( 1 === (int) $slug['disabled'] ) ? 0 : 1 ;
342
343 sh_cd_db_shortcodes_update_status( $id, $status );
344
345 return $status;
346 }
347
348 return NULL;
349 }
350
351 /**
352 * Toggle the multisite of a shortcode
353 *
354 * @param $id
355 * @return int|null
356 */
357 function sh_cd_toggle_multisite( $id ) {
358
359 $slug = sh_cd_db_shortcodes_by_id( (int) $id );
360
361 if ( false === empty( $slug ) ) {
362
363 $multisite = ( 1 === (int) $slug['multisite'] ) ? 0 : 1 ;
364
365 sh_cd_db_shortcodes_update_multisite( $id, $multisite );
366
367 return $multisite;
368 }
369
370 return NULL;
371 }
372
373 /**
374 * Display an upgrade button
375 *
376 * @param string $css_class
377 * @param null $link
378 */
379 function sh_cd_upgrade_button( $css_class = '', $link = NULL ) {
380
381 $link = ( false === empty( $link ) ) ? $link : SH_CD_UPGRADE_LINK . '?hash=' . sh_cd_generate_site_hash() ;
382
383 $price = sh_cd_license_price();
384 $price = ( false === empty( $price ) ) ? sprintf( '- £%s %s', $price, __( 'a year ', SH_CD_SLUG ) ) : '';
385
386 echo sprintf('<a href="%s" class="button-primary sh-cd-upgrade-button sh-cd-button %s"><i class="far fa-star"></i> %s %s</a>',
387 esc_url( $link ),
388 esc_attr( ' ' . $css_class ),
389 __( 'Purchase a license ', SH_CD_SLUG ),
390 $price
391 );
392 }
393
394 /**
395 * Display an upgrade button
396 *
397 * @param string $css_class
398 * @param null $link
399 */
400 function sh_cd_premium_shortcode_download( $return = false ) {
401
402 $link = SH_CD_GET_PREMIUM_LINK . '?hash=' . sh_cd_generate_site_hash();
403
404 $html = sprintf('<a href="%s" class="button-primary sh-cd-button sh-cd-upgrade-button"><i class="fas fa-download"></i> %s</a>',
405 esc_url( $link ),
406 __( 'Download Premium Plugin', SH_CD_SLUG )
407 );
408
409 if ( true === $return ) {
410 return $html;
411 }
412
413 echo $html;
414 }
415
416 /**
417 * Is multsite functionality active for this install?
418 *
419 * @return bool
420 */
421 function sh_cd_is_multisite_enabled() {
422
423 if ( true === defined( 'YK_TEST_IS_MULTISITE' ) && true === YK_TEST_IS_MULTISITE ) {
424 return true;
425 }
426
427 if ( false === is_multisite() ) {
428 return false;
429 }
430
431 if ( false === sh_cd_is_premium() ) {
432 return false;
433 }
434
435 return true;
436 }
437
438 /**
439 * Fetch all multisite slugs
440 *
441 * @return array|null
442 */
443 function sh_cd_multisite_slugs() {
444
445 if ( false === is_multisite() ) {
446 return [];
447 }
448
449 $cache = sh_cd_cache_get( 'sh-cd-multisite-slugs' );
450
451 if ( false !== $cache ) {
452 return $cache;
453 }
454
455 $slugs = sh_cd_db_shortcodes_multisite_slugs();
456
457 $slugs = ( false === empty( $slugs ) ) ? wp_list_pluck( $slugs, 'slug' ) : [];
458
459 // Cache this for a short time
460 sh_cd_cache_set( 'sh-cd-multisite-slugs', $slugs, 30 );
461
462 return ( true === is_array( $slugs ) ) ? $slugs : [];
463 }
464
465 /**
466 * Have we reached the limit of free shortcodes?
467 * @return bool
468 */
469 function sh_cd_reached_free_limit() {
470
471 if ( true === sh_cd_is_premium() ) {
472 return false;
473 }
474
475 $existing_shortcodes = sh_cd_db_shortcodes_count();
476
477 if ( true === empty( $existing_shortcodes ) ) {
478 return false;
479 }
480
481 return ( (int) $existing_shortcodes >= sh_cd_get_free_limit() );
482 }
483
484 /**
485 * Return free limit for shortcodes
486 */
487 function sh_cd_get_free_limit() {
488 return 10;
489 }
490
491 /**
492 * Get the minimum user role allowed for viewing data pages in admin
493 * @return mixed|void
494 */
495 function sh_cd_permission_role() {
496
497 // If not premium, then admin only
498 if ( false === sh_cd_is_premium() ) {
499 return 'manage_options';
500 }
501
502 $permission_role = get_option( 'sh-cd-edit-permissions', 'manage_options' );
503
504 return ( false === empty( $permission_role ) ) ? $permission_role : 'manage_options';
505 }
506
507 /**
508 * Does the user have the correct permissions to view this page?
509 */
510 function sh_cd_permission_check() {
511
512 $allowed_viewer = sh_cd_permission_role();
513
514 if ( false === current_user_can( $allowed_viewer ) ) {
515 wp_die( __( 'You do not have sufficient permissions to access this page.', SH_CD_SLUG ) );
516 }
517 }
518
519 /**
520 * Is the shortcode [sv slug="sc-db-value-by-id"] enabled
521 * @return bool (default false)
522 */
523 function sh_cd_is_shortcode_db_value_by_id_enabled() {
524
525 if ( false === sh_cd_is_premium() ) {
526 return false;
527 }
528
529 // Disabling by filter overrides the setting in WP admin
530 if ( true === apply_filters( 'disable-ss-sc-db-value-by-id', __return_false() ) ) {
531 return false;
532 }
533
534 $value = get_option( 'sh-cd-shortcode-db-value-by-id-enabled', false );
535
536 return sh_cd_to_bool( $value );
537 }
538
539 /**
540 * Display upgrade notice
541 *
542 * @param bool $pro_plus
543 */
544 function sh_cd_display_pro_upgrade_notice( $title = NULL, $content = '', $class = '' ) {
545
546 $title = ( true === empty( $title ) ) ? __( 'Upgrade Snippet Shortcodes and get more features!', SH_CD_SLUG ) : $title;
547
548 ?>
549 <div class="postbox sh-cd-advertise-premium <?php echo esc_attr( $class ) ?>">
550 <h3 class="hndle"><i class="fa-regular fa-star"></i> <?php echo esc_html( $title ) ?></h3>
551 <div style="padding: 0px 15px 0px 15px">
552 <p><?php echo wp_kses( $content, [ 'ul' => [ 'class' ], 'li' => [], 'strong' => [], 'span' => [], 'div' => [] ] ); ?></p>
553 <p><a href="<?php echo esc_url( admin_url('admin.php?page=sh-cd-shortcode-variables-upgrade') ); ?>" class="button-primary sh-cd-upgrade-button"><i class="fa-regular fa-star"></i> <?php echo __( 'Get Premium', SH_CD_SLUG ); ?></a></p>
554 </div>
555 </div>
556 <?php
557 }
558
559 /**
560 * Display a star to prompt for a Premioum upgrade
561 *
562 * @param bool $pro_plus
563 */
564 function sh_cd_display_premium_star() {
565
566 if ( true === sh_cd_is_premium() ) {
567 return ''; // We don't want to show the star if the user has already upgraded
568 }
569
570 return sprintf ('<a href="%s"><i class="fa-regular fa-star"></i></a>',
571 esc_url( admin_url('admin.php?page=sh-cd-shortcode-variables-upgrade') )
572 );
573 }
574
575 /**
576 * Display info symbol with tooltip
577 */
578 function sh_cd_display_info_tooltip( $text ) {
579
580 return sprintf ('<i class="fa-regular fa-circle-question sh-cd-tooltip" title="%s">',
581 esc_html( $text )
582 );
583 }
584
585 /**
586 * Process a CSV attachment and import into database
587 *
588 * @param $attachment_id
589 *
590 * @param bool $dry_run
591 *
592 * @return string
593 */
594 function sh_cd_import_csv( $attachment_id, $dry_run = true ) {
595
596 sh_cd_permission_check();
597
598 if ( false === sh_cd_is_premium() ) {
599 return 'This is a premium feature';
600 }
601
602 $csv_path = get_attached_file( $attachment_id );
603 $admin_id = get_current_user_id();
604
605 if ( true === empty( $csv_path ) || false === file_exists( $csv_path )) {
606 return 'Error: Error loading CSV from disk.';
607 }
608
609 $csv = array_map('str_getcsv', file( $csv_path ) );
610
611 if ( true === empty( $csv ) ) {
612 return 'Error: The CSV appears to be empty.';
613 }
614
615 // Lowercase the header row up front so it's compared consistently against our
616 // (lowercase) column names both here and per-row below - previously the header row
617 // was validated case-sensitively while each data row's keys were lowercased.
618 $csv[0] = array_map( 'strtolower', $csv[0] );
619
620 array_walk($csv, function(&$a) use ($csv) {
621 $a = array_combine($csv[0], $a);
622 });
623
624 $validate_header_result = sh_cd_import_csv_validate_header( $csv[0] );
625
626 if ( true !== $validate_header_result ) {
627 return $validate_header_result;
628 }
629
630 array_shift($csv );
631
632 if ( true === empty( $csv ) ) {
633 return 'Error: The CSV appears to be empty (when header hs been removed).';
634 }
635
636 $errors = 0;
637
638 $output = sprintf( '%d rows to process...' . PHP_EOL, count( $csv ) );
639
640 if ( true === $dry_run ) {
641 $output .= 'DRY RUN MODE! No data will be imported.' . PHP_EOL;
642 }
643
644 foreach ( $csv as $row ) {
645
646 if ( $errors >= 50 ) {
647 $output .= 'Aborted! More than 50 errors have been detected in this file.' . PHP_EOL;
648 break;
649 }
650
651 $row = array_change_key_case( $row ); // Force CSV headers to lowercase
652
653 $validation_result = sh_cd_import_csv_validate_row( $row );
654
655 // Validate a row before proceeding
656 if ( true !== $validation_result ) {
657 $output .= $validation_result . PHP_EOL;
658 $errors++;
659 continue;
660 }
661
662 if ( false === $dry_run ) {
663
664 $shortcode = [ 'previous_slug' => '' ];
665
666 foreach ( sh_cd_csv_columns() as $column_name => $column ) {
667
668 if ( false === isset( $row[ $column_name ] ) ) {
669 continue;
670 }
671
672 $shortcode = array_merge( $shortcode, call_user_func( $column[ 'import' ], $row[ $column_name ] ) );
673 }
674
675 $result = sh_cd_db_shortcodes_save( $shortcode );
676
677 if ( false === $result ) {
678 $output .= 'Skipped: Error inserting into database (most likely a field contains too many characters or in the wrong format): ' . implode( ',', $row ) . PHP_EOL;
679 }
680 }
681
682 }
683
684 if ( $errors > 0 ) {
685 $output .= sprintf( '%d errors were detected and the rows skipped.' . PHP_EOL, $errors );
686 }
687
688 $output .= 'Completed.';
689
690 return $output;
691
692 }
693
694 /**
695 * Verify header row
696 * @param $header_row
697 *
698 * @return bool|string
699 */
700 function sh_cd_import_csv_validate_header( $header_row ) {
701
702 $required_columns = array_keys( array_filter( sh_cd_csv_columns(), function( $column ) {
703 return true === $column[ 'required' ];
704 } ) );
705
706 foreach ( $required_columns as $column ) {
707
708 if ( false === isset( $header_row[ $column ] ) ) {
709 return 'Missing column: ' . $column . '. Expecting at least: ' . implode( ',', $required_columns ) . PHP_EOL;
710 }
711 }
712
713 return true;
714 }
715
716 /**
717 * Validate CSV row
718 * @param $csv_row
719 *
720 * @return bool|string
721 */
722 function sh_cd_import_csv_validate_row( $csv_row ) {
723
724 if ( true === empty( $csv_row[ 'slug' ] ) ) {
725 return 'Skipped: Missing slug: ' . implode( ',', $csv_row );
726 }
727
728 if ( true === empty( $csv_row[ 'content' ] ) ) {
729 return 'Skipped: Missing content: ' . implode( ',', $csv_row );
730 }
731
732 $allowed_bools = [ 'yes', 'no', 'true', 'false', '1', '0' ];
733
734 if ( true === empty( $csv_row[ 'global' ] ) ||
735 false === in_array( $csv_row[ 'global' ], $allowed_bools ) ) {
736 return 'Skipped: Invalid "global" value. Must be "yes" or "no": ' . implode( ',', $csv_row );
737 }
738
739 if ( true === empty( $csv_row[ 'enabled' ] ) ||
740 false === in_array( $csv_row[ 'enabled' ], $allowed_bools ) ) {
741 return 'Skipped: Invalid "enabled" value. Must be "yes" or "no": ' . implode( ',', $csv_row );
742 }
743
744 // Give any Premium-registered columns a chance to reject their own value, so dry-run
745 // mode surfaces bad input instead of it being silently coerced later on save.
746 foreach ( sh_cd_csv_columns() as $column_name => $column ) {
747
748 if ( false === isset( $csv_row[ $column_name ] ) || false === isset( $column[ 'validate' ] ) ) {
749 continue;
750 }
751
752 $validation_result = call_user_func( $column[ 'validate' ], $csv_row[ $column_name ] );
753
754 if ( true !== $validation_result ) {
755 return $validation_result;
756 }
757 }
758
759 return true;
760 }
761
762 /**
763 * Ordered map of CSV column name => column definition, used by both sh_cd_import_csv() and
764 * sh_cd_export_csv(). Extensible via the 'sh-cd-csv-columns' filter so Premium can add columns
765 * for its own fields without core knowing about them - column names must be unique (a later
766 * registration silently overwrites an earlier one of the same name, same as any other array-shaped
767 * filter in this plugin).
768 *
769 * Each column definition:
770 * 'required' => bool column must be present in the CSV header row
771 * 'export' => callable( array $shortcode ): string decoded shortcode row -> CSV cell value
772 * 'import' => callable( string $value ): array CSV cell value -> partial $shortcode to merge
773 * 'validate' => callable( string $value ): true|string optional; true, or an error message
774 *
775 * @return array
776 */
777 function sh_cd_csv_columns() {
778
779 $columns = [
780 'slug' => [
781 'required' => true,
782 'export' => function( $shortcode ) { return $shortcode[ 'slug' ]; },
783 'import' => function( $value ) { return [ 'slug' => $value ]; },
784 ],
785 'content' => [
786 'required' => true,
787 'export' => function( $shortcode ) { return stripslashes( $shortcode[ 'data' ] ); },
788 'import' => function( $value ) { return [ 'data' => $value ]; },
789 ],
790 'global' => [
791 'required' => true,
792 'export' => function( $shortcode ) { return ( 1 === (int) $shortcode[ 'multisite' ] ) ? 'yes' : 'no'; },
793 'import' => function( $value ) { return [ 'multisite' => sh_cd_to_bool( $value ) ? 1 : 0 ]; },
794 ],
795 'enabled' => [
796 'required' => true,
797 'export' => function( $shortcode ) { return ( 1 === (int) $shortcode[ 'disabled' ] ) ? 'no' : 'yes'; },
798 'import' => function( $value ) { return [ 'disabled' => sh_cd_to_bool( $value ) ? 0 : 1 ]; },
799 ],
800 ];
801
802 return apply_filters( 'sh-cd-csv-columns', $columns );
803 }
804
805 /**
806 * Convert string to bool
807 * @param $string
808 * @return mixed
809 */
810 function sh_cd_to_bool( $string ) {
811 return filter_var( $string, FILTER_VALIDATE_BOOLEAN );
812 }
813
814 /**
815 * Export all shortcodes as a CSV string in the same column format sh_cd_import_csv() expects
816 * (see sh_cd_csv_columns()), so the output can be re-imported unchanged.
817 *
818 * @return string
819 */
820 function sh_cd_export_csv() {
821
822 sh_cd_permission_check();
823
824 $shortcodes = sh_cd_db_shortcodes_all();
825 $columns = sh_cd_csv_columns();
826
827 $stream = fopen( 'php://temp', 'r+' );
828
829 fputcsv( $stream, array_keys( $columns ) );
830
831 foreach ( $shortcodes as $shortcode ) {
832
833 // sh_cd_db_shortcodes_all() returns raw DB rows - run each through the same
834 // 'sh-cd-db-loaded-shortcode' filter used when loading a single shortcode, so
835 // Premium's JSON-encoded columns (device_type, roles, etc.) are decoded back into
836 // arrays before the column export callbacks below run.
837 $shortcode = sh_cd_db_filter_loaded_shortcode( $shortcode );
838
839 $row = [];
840
841 foreach ( $columns as $column ) {
842 $row[] = call_user_func( $column[ 'export' ], $shortcode );
843 }
844
845 fputcsv( $stream, $row );
846 }
847
848 rewind( $stream );
849 $csv = stream_get_contents( $stream );
850 fclose( $stream );
851
852 return $csv;
853 }
854
855 /**
856 * Our version of kses and the HTML we are happy with
857 */
858 function sh_cd_wp_kses( $value ) {
859
860 $basic_tags = wp_kses_allowed_html( 'html' );
861
862 $basic_tags[ 'a' ] = [ 'id' => true, 'class' => true, 'href' => true, 'title' => true, 'target' => true];
863 $basic_tags[ 'canvas' ] = [ 'id' => true, 'class' => true ];
864 $basic_tags[ 'div' ] = [ 'id' => true, 'class' => true, 'style' => true ];
865 $basic_tags[ 'i' ] = [ 'id' => true, 'class' => true ];
866 $basic_tags[ 'p' ] = [ 'id' => true, 'class' => true ];
867 $basic_tags[ 'span' ] = [ 'id' => true, 'class' => true ];
868 $basic_tags[ 'table' ] = [ 'id' => true, 'class' => true ];
869 $basic_tags[ 'tr' ] = [ 'id' => true, 'class' => true ];
870 $basic_tags[ 'td' ] = [ 'id' => true, 'class' => true ];
871 $basic_tags[ 'li' ] = [ 'class' => true ];
872
873 return wp_kses( $value, $basic_tags );
874 }
875
876 /**
877 * Return the current url
878 */
879 function sh_cd_get_current_url() {
880 $protocol = (
881 ( isset($_SERVER['HTTPS'] ) && 'on' == $_SERVER['HTTPS'] ) ||
882 ( isset($_SERVER['SERVER_PORT'] ) && 443 == $_SERVER['SERVER_PORT'] )
883 ) ? 'https://' : 'http://';
884
885 return $protocol . $_SERVER["HTTP_HOST"] . $_SERVER["REQUEST_URI"];
886 }
887
888 /**
889 * Get selected default editor
890 */
891 function sh_cd_default_editor_get() {
892 return get_option( 'sh-cd-option-default-editor', 'tinymce' );
893 }
894
895 /**
896 * Is editor valid
897 */
898 function sh_cd_editors_is_valid( $editor ) {
899 $editors = sh_cd_editors_options();
900
901 return ! empty( $editors[ $editor ] );
902 }
903
904 /**
905 * Return valid editors
906 */
907 function sh_cd_editors_options( $keys_only = true ) {
908 return [ 'tinymce' => __( 'WordPress Editor', SH_CD_SLUG ), 'code' => __( 'HTML Editor', SH_CD_SLUG ) ];
909 }
910
911 /**
912 * Are tooltips enabled?
913 */
914 function sh_cd_tooltips_is_enabled() {
915 return ( 'yes' === get_option( 'sh-cd-option-tool-tips-enabled', 'yes' ) );
916 }
917
918 /**
919 * Is render-count analytics (tracking how many times each shortcode is rendered, incrementing
920 * a DB counter on every render) enabled? A Premium-only feature, on by default - lets a
921 * high-traffic site opt out of the extra database write on every shortcode render.
922 *
923 * @return bool (default true when Premium, always false otherwise)
924 */
925 function sh_cd_is_render_count_enabled() {
926
927 if ( false === sh_cd_is_premium() ) {
928 return false;
929 }
930
931 return ( 'yes' === get_option( 'sh-cd-option-render-count-enabled', 'yes' ) );
932 }
933
934 /**
935 * Fetch icons for given shortcode
936 *
937 * @param [type] $shortcode
938 * @param boolean $return_array
939 * @return void
940 */
941 function sh_cd_icons_for_shortcode( $shortcode, $return_array = false ) {
942
943 if ( true === empty( $shortcode ) ) {
944 return [];
945 }
946
947 $icons = [];
948
949 if ( false === empty( $shortcode[ 'header' ] ) ) {
950 $icons[] = sprintf( '<i class="fa-solid fa-heading sh-cd-option-icon sh-cd-tooltip" title="%s"></i>', esc_html( __( 'Insert into WP Header', SH_CD_SLUG ) ) );
951 }
952
953 if ( false === empty( $shortcode[ 'footer' ] ) ) {
954 $icons[] = sprintf( '<i class="fa-solid fa-shoe-prints sh-cd-option-icon sh-cd-tooltip" title="%s"></i>', esc_html( __( 'Insert into WP Footer', SH_CD_SLUG ) ) );
955 }
956
957 if ( false === empty( $shortcode[ 'device_type' ] ) ) {
958 $shortcode[ 'device_type' ] = json_decode( $shortcode[ 'device_type' ] );
959 }
960
961 if ( true === is_array( $shortcode[ 'device_type' ] ) ) {
962
963 if ( true === in_array( 'desktop', $shortcode[ 'device_type' ] ) ) {
964 $icons[] = sprintf( '<i class="fa-solid fa-desktop sh-cd-option-icon sh-cd-tooltip" title="%s"></i>', esc_html( __( 'Display only on desktop devices', SH_CD_SLUG ) ) );
965 }
966
967 if ( true === in_array( 'mobile', $shortcode[ 'device_type' ] ) ) {
968 $icons[] = sprintf( '<i class="fa-solid fa-mobile-screen sh-cd-option-icon sh-cd-tooltip" title="%s"></i>', esc_html( __( 'Display only on mobile devices', SH_CD_SLUG ) ) );
969 }
970
971 if ( true === in_array( 'tablet', $shortcode[ 'device_type' ] ) ) {
972 $icons[] = sprintf( '<i class="fa-solid fa-tablet-screen-button sh-cd-option-icon sh-cd-tooltip" title="%s"></i>', esc_html( __( 'Display only on tablet devices', SH_CD_SLUG ) ) );
973 }
974 }
975
976 if ( true === $return_array ) {
977 return $icons;
978 }
979
980 return ( false === empty( $icons ) ) ? implode( PHP_EOL, $icons ) : '';
981 }