PluginProbe
Social Media Auto Poster – Schedule & Publish to Buffer / 6.2.1
Social Media Auto Poster – Schedule & Publish to Buffer v6.2.1
6.2.4 6.2.3 6.2.2 6.2.1 6.2.0 6.1.2 6.1.1 6.1.0 6.0.9 6.0.8 6.0.7 6.0.6 6.0.5 6.0.4 6.0.3 6.0.2 6.0.1 6.0.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 All 125 releases
wp-to-buffer / lib / shared / class-admin-ui.php

class-admin-ui.php in Social Media Auto Poster – Schedule & Publish to Buffer 6.2.1, at lib/shared/class-admin-ui.php

1,142 lines 33.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Provides common functionality, styling and views for WP Zinc Plugins.
4 *
5 * @package WPZinc\Shared
6 * @author WP Zinc
7 */
8
9 namespace WPZinc\Shared;
10
11 // Exit if accessed directly.
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit;
14 }
15
16 /**
17 * Provides common functionality, styling and views for WP Zinc Plugins.
18 */
19 class Admin_UI {
20
21 /**
22 * Holds the plugin object
23 *
24 * @since 1.0.0
25 *
26 * @var object
27 */
28 public $plugin;
29
30 /**
31 * Holds the exact path to this file's folder
32 *
33 * @since 1.0.0
34 *
35 * @var string
36 */
37 public $dashboard_folder;
38
39 /**
40 * Holds the exact URL to this file's folder
41 *
42 * @since 1.0.0
43 *
44 * @var string
45 */
46 public $dashboard_url;
47
48 /**
49 * Flag to show the Import and Export Sub Menu
50 *
51 * @since 1.0.0
52 *
53 * @var bool
54 */
55 private $show_import_export_menu = true;
56
57 /**
58 * Flag to show the Support Sub Menu
59 *
60 * @since 1.0.0
61 *
62 * @var bool
63 */
64 private $show_support_menu = false;
65
66 /**
67 * Flag to show the Review Request
68 *
69 * @since 1.0.0
70 *
71 * @var bool
72 */
73 private $show_review_request = true;
74
75 /**
76 * Holds the message to display when importing or exporting a configuration file.
77 *
78 * @since 1.0.0
79 *
80 * @var string
81 */
82 private $message = '';
83
84 /**
85 * Holds the error message to display when importing or exporting a configuration file.
86 *
87 * @since 1.0.0
88 *
89 * @var string
90 */
91 private $error_message = '';
92
93 /**
94 * Constructor
95 *
96 * @since 1.0.0
97 *
98 * @param object $plugin WordPress Plugin.
99 */
100 public function __construct( $plugin ) {
101
102 // Plugin Details.
103 $this->plugin = $plugin;
104
105 // Set class vars.
106 $this->dashboard_folder = plugin_dir_path( __FILE__ );
107 $this->dashboard_url = plugin_dir_url( __FILE__ );
108
109 // Admin CSS, JS and Menu.
110 add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) );
111 add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts_css' ) );
112 add_action( str_replace( '-', '_', $this->plugin->name ) . '_admin_menu_import_export', array( $this, 'register_import_export_menu' ), 99 );
113 add_action( str_replace( '-', '_', $this->plugin->name ) . '_admin_menu_support', array( $this, 'register_support_menu' ), 99 );
114
115 // Plugin Actions.
116 if ( ! isset( $this->plugin->hide_upgrade_menu ) || ! $this->plugin->hide_upgrade_menu ) {
117 add_filter( 'plugin_action_links_' . $this->plugin->name . '/' . $this->plugin->name . '.php', array( $this, 'add_action_link' ), 10, 1 );
118 }
119
120 // Reviews.
121 if ( $this->plugin->review_name !== false ) {
122 add_action( 'wp_ajax_' . str_replace( '-', '_', $this->plugin->name ) . '_dismiss_review', array( $this, 'dismiss_review' ) );
123 add_action( 'admin_notices', array( $this, 'maybe_display_review_request' ) );
124 add_filter( 'admin_footer_text', array( $this, 'maybe_display_footer_review_request' ) );
125 }
126
127 // About.
128 if ( isset( $this->plugin->about_hook ) && $this->plugin->about_hook !== false ) {
129 add_action( $this->plugin->about_hook, array( $this, 'about_section' ) );
130 }
131
132 // Export and Redirects.
133 add_action( 'init', array( $this, 'export' ), 9999 );
134 add_action( 'init', array( $this, 'maybe_redirect' ), 2 );
135
136 // Permit wpzinc.com to be redirected to when using wp_safe_redirect().
137 add_filter( 'allowed_redirect_hosts', array( $this, 'allowed_redirect_hosts' ) );
138
139 }
140
141 /**
142 * Helper function to determine whether to load minified Javascript
143 * files or not.
144 *
145 * @since 1.0.0
146 *
147 * @return bool Load Minified JS
148 */
149 public function should_load_minified_js() {
150
151 // If script debugging is enabled, don't load minified JS.
152 if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) {
153 return false;
154 }
155
156 // If we can't determine a Plugin's activation state, minify JS.
157 if ( ! function_exists( 'is_plugin_active' ) ) {
158 return true;
159 }
160
161 // If a known third party Plugin exists that minifies JS, don't load minified JS
162 // as double minification seems to break things.
163 $minification_plugins = array(
164 'wp-rocket/wp-rocket.php',
165 );
166
167 /**
168 * Defines an array of third party minification Plugins that, if activate, will result
169 * in this Plugin's JS non-minified files being loaded.
170 *
171 * This allows said third party minification Plugins to minify JS, avoiding double minification
172 * which can result in errors.
173 *
174 * If SCRIPT_DEBUG is enabled, non minified JS will always be loaded, regardless of whether
175 * a minification Plugin is active.
176 *
177 * @since 1.0.0
178 *
179 * @param array $minification_plugins Plugin Folder and Filename Paths e.g. wp-rocket/wp-rocket.php
180 */
181 $minification_plugins = apply_filters( 'wpzinc_dashboard_should_load_minified_js_plugins', $minification_plugins );
182
183 // If no minification Plugins, load minified JS.
184 if ( ! is_array( $minification_plugins ) || ! count( $minification_plugins ) ) {
185 return true;
186 }
187
188 // Check if any minification Plugin is active.
189 foreach ( $minification_plugins as $plugin_folder_filename ) {
190 if ( is_plugin_active( $plugin_folder_filename ) ) {
191 // A known minification Plugin is active.
192 // Don't minify JS, as the third party Plugin will do this.
193 return false;
194 }
195 }
196
197 // If here, OK to load minified JS.
198 return true;
199
200 }
201
202 /**
203 * Shows the Import & Export Submenu in the Plugin's Menu
204 *
205 * @since 1.0.0
206 */
207 public function show_import_export_menu() {
208
209 $this->show_import_export_menu = true;
210
211 }
212
213 /**
214 * Hides the Import & Export Submenu in the Plugin's Menu
215 *
216 * @since 1.0.0
217 */
218 public function hide_import_export_menu() {
219
220 $this->show_import_export_menu = false;
221
222 }
223
224 /**
225 * Shows the Support Submenu in the Plugin's Menu
226 *
227 * @since 1.0.0
228 */
229 public function show_support_menu() {
230
231 $this->show_support_menu = true;
232
233 }
234
235 /**
236 * Hides the Support Submenu in the Plugin's Menu
237 *
238 * @since 1.0.0
239 */
240 public function hide_support_menu() {
241
242 $this->show_support_menu = false;
243
244 }
245
246 /**
247 * Disables the Review Request Notification, regardless of whether
248 * it has been set by the Plugin calling request_review()
249 *
250 * @since 1.0.0
251 */
252 public function disable_review_request() {
253
254 $this->show_review_request = false;
255
256 }
257
258 /**
259 * Adds the WP Zinc CSS class to the <body> tag when we're in the WordPress Admin interface
260 * and viewing a Plugin Screen
261 *
262 * This allows us to then override some WordPress layout styling on e.g. #wpcontent, without
263 * affecting other screens, Plugins etc.
264 *
265 * @since 1.0.0
266 *
267 * @param string $classes CSS Classes.
268 * @return string CSS Classes
269 */
270 public function admin_body_class( $classes ) {
271
272 // Define a list of strings that determine whether we're viewing a Plugin Screen.
273 $screens = array(
274 $this->plugin->name,
275 );
276
277 /**
278 * Filter the body classes to output on the <body> tag.
279 *
280 * @since 1.0.0
281 *
282 * @param array $screens Screens.
283 * @param array $classes Classes.
284 */
285 $screens = apply_filters( 'wpzinc_admin_body_class', $screens, $classes );
286
287 // Determine whether we're on a Plugin Screen.
288 $is_plugin_screen = $this->is_plugin_screen( $screens );
289
290 // Bail if we're not a Plugin screen.
291 if ( ! $is_plugin_screen ) {
292 return $classes;
293 }
294
295 // Add the wpzinc class and plugin name.
296 $classes .= ' wpzinc ' . $this->plugin->name;
297
298 // Return.
299 return trim( $classes );
300
301 }
302
303 /**
304 * Determines whether we're viewing this Plugin's screen in the WordPress Administration
305 * interface.
306 *
307 * @since 1.0.0
308 *
309 * @param array $screens Screens.
310 * @return bool Is Plugin Screen
311 */
312 private function is_plugin_screen( $screens ) {
313
314 // Bail if the current screen can't be obtained.
315 if ( ! function_exists( 'get_current_screen' ) ) {
316 return false;
317 }
318
319 // Bail if no screen names were specified to search for.
320 if ( empty( $screens ) || count( $screens ) === 0 ) {
321 return false;
322 }
323
324 // Get screen.
325 $screen = get_current_screen();
326
327 foreach ( $screens as $screen_name ) {
328 if ( strpos( $screen->id, $screen_name ) === false ) {
329 continue;
330 }
331
332 // We're on a Plugin Screen.
333 return true;
334 }
335
336 // If here, we're not on a Plugin Screen.
337 return false;
338
339 }
340
341 /**
342 * Register JS scripts, which Plugins may optionally load via wp_enqueue_script()
343 * Enqueues CSS
344 *
345 * @since 1.0.0
346 */
347 public function admin_scripts_css() {
348
349 // Determine whether to load minified versions of JS.
350 $minified = $this->should_load_minified_js();
351
352 // JS.
353 wp_register_script( 'wpzinc-admin-autocomplete-gutenberg', $this->dashboard_url . 'js/' . ( $minified ? 'min/' : '' ) . 'autocomplete-gutenberg' . ( $minified ? '-min' : '' ) . '.js', false, $this->plugin->version, true );
354 wp_register_script( 'wpzinc-admin-autocomplete', $this->dashboard_url . 'js/' . ( $minified ? 'min/' : '' ) . 'autocomplete' . ( $minified ? '-min' : '' ) . '.js', array( 'wpzinc-admin-tribute' ), $this->plugin->version, true );
355 wp_register_script( 'wpzinc-admin-autosize', $this->dashboard_url . 'js/' . ( $minified ? 'min/' : '' ) . 'autosize' . ( $minified ? '-min' : '' ) . '.js', false, $this->plugin->version, true );
356 wp_register_script( 'wpzinc-admin-conditional', $this->dashboard_url . 'js/' . ( $minified ? 'min/' : '' ) . 'jquery.form-conditionals' . ( $minified ? '-min' : '' ) . '.js', array( 'jquery' ), $this->plugin->version, true );
357 wp_register_script( 'wpzinc-admin-inline-search', $this->dashboard_url . 'js/' . ( $minified ? 'min/' : '' ) . 'inline-search' . ( $minified ? '-min' : '' ) . '.js', array( 'jquery' ), $this->plugin->version, true );
358 wp_register_script( 'wpzinc-admin-media-library', $this->dashboard_url . 'js/' . ( $minified ? 'min/' : '' ) . 'media-library' . ( $minified ? '-min' : '' ) . '.js', array( 'jquery', 'jquery-ui-sortable' ), $this->plugin->version, true );
359 wp_register_script( 'wpzinc-admin-modal', $this->dashboard_url . 'js/' . ( $minified ? 'min/' : '' ) . 'modal' . ( $minified ? '-min' : '' ) . '.js', array( 'jquery' ), $this->plugin->version, true );
360 wp_register_script( 'wpzinc-admin-notification', $this->dashboard_url . 'js/' . ( $minified ? 'min/' : '' ) . 'notification' . ( $minified ? '-min' : '' ) . '.js', array( 'jquery' ), $this->plugin->version, true );
361 wp_register_script( 'wpzinc-admin-review-notice', $this->dashboard_url . 'js/' . ( $minified ? 'min/' : '' ) . 'review-notice' . ( $minified ? '-min' : '' ) . '.js', array( 'jquery' ), $this->plugin->version, true );
362 wp_register_script( 'wpzinc-admin-selectize', $this->dashboard_url . 'js/' . ( $minified ? 'min/' : '' ) . 'selectize' . ( $minified ? '-min' : '' ) . '.js', array( 'jquery' ), $this->plugin->version, true );
363 wp_register_script( 'wpzinc-admin-synchronous-ajax', $this->dashboard_url . 'js/' . ( $minified ? 'min/' : '' ) . 'synchronous-ajax' . ( $minified ? '-min' : '' ) . '.js', array( 'jquery' ), $this->plugin->version, true );
364 wp_register_script( 'wpzinc-admin-tables', $this->dashboard_url . 'js/' . ( $minified ? 'min/' : '' ) . 'tables' . ( $minified ? '-min' : '' ) . '.js', array( 'jquery' ), $this->plugin->version, true );
365 wp_register_script( 'wpzinc-admin-tabs', $this->dashboard_url . 'js/' . ( $minified ? 'min/' : '' ) . 'tabs' . ( $minified ? '-min' : '' ) . '.js', array( 'jquery' ), $this->plugin->version, true );
366 wp_register_script( 'wpzinc-admin-tags', $this->dashboard_url . 'js/' . ( $minified ? 'min/' : '' ) . 'tags' . ( $minified ? '-min' : '' ) . '.js', array( 'jquery' ), $this->plugin->version, true );
367 wp_register_script( 'wpzinc-admin-tinymce-modal', $this->dashboard_url . 'js/' . ( $minified ? 'min/' : '' ) . 'tinymce-modal' . ( $minified ? '-min' : '' ) . '.js', array( 'jquery' ), $this->plugin->version, true );
368 wp_register_script( 'wpzinc-admin-toggle', $this->dashboard_url . 'js/' . ( $minified ? 'min/' : '' ) . 'toggle' . ( $minified ? '-min' : '' ) . '.js', array( 'jquery' ), $this->plugin->version, true );
369 wp_register_script( 'wpzinc-admin-tribute', $this->dashboard_url . 'js/' . ( $minified ? 'min/' : '' ) . 'tribute' . ( $minified ? '-min' : '' ) . '.js', false, $this->plugin->version, true );
370 wp_register_script( 'wpzinc-admin', $this->dashboard_url . 'js/' . ( $minified ? 'min/' : '' ) . 'admin' . ( $minified ? '-min' : '' ) . '.js', array( 'jquery' ), $this->plugin->version, true );
371
372 // CSS.
373 wp_register_style( 'wpzinc-admin-selectize', $this->dashboard_url . 'css/selectize.css', false, $this->plugin->version );
374 wp_enqueue_style( 'wpzinc-admin', $this->dashboard_url . 'css/admin.css', false, $this->plugin->version );
375
376 // Depending on the screen we're on, maybe enqueue specific scripts now.
377 if ( ! function_exists( 'get_current_screen' ) ) {
378 return;
379 }
380
381 // Bail if we couldn't get the current screen.
382 $screen = get_current_screen();
383 if ( is_null( $screen ) ) {
384 return;
385 }
386
387 switch ( $screen->id ) {
388
389 /**
390 * Import / Export
391 * - Use of displayName is deliberate.
392 */
393 case sanitize_title( $this->plugin->displayName ) . '_page_' . $this->plugin->name . '-import-export':
394 wp_enqueue_script( 'wpzinc-admin-tabs' );
395 wp_enqueue_script( 'wpzinc-admin-toggle' );
396 break;
397
398 }
399
400 }
401
402 /**
403 * Registers the Import / Export Menu Link in the WordPress Administration interface
404 *
405 * @since 1.0.0
406 *
407 * @param string $parent_slug Parent Slug.
408 */
409 public function register_import_export_menu( $parent_slug = '' ) {
410
411 // Bail if the Import & Export Menu is hidden.
412 if ( ! $this->show_import_export_menu ) {
413 return;
414 }
415
416 // If a parent slug is defined, attach the submenu items to that.
417 // Otherwise use the plugin's name.
418 $slug = ( ! empty( $parent_slug ) ? $parent_slug : $this->plugin->name );
419
420 /**
421 * Filter the minimum capability for accessing Import and Export Sub Menu.
422 *
423 * @since 1.0.0
424 *
425 * @param string $minimum_capability Minimum Capability.
426 */
427 $minimum_capability = apply_filters( str_replace( '-', '_', $this->plugin->name ) . '_admin_admin_menu_minimum_capability', 'manage_options' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName
428
429 add_submenu_page( $slug, __( 'Import & Export', 'wp-to-buffer' ), __( 'Import & Export', 'wp-to-buffer' ), $minimum_capability, $this->plugin->name . '-import-export', array( $this, 'import_export_screen' ) );
430
431 }
432
433 /**
434 * Registers the Support Menu Link in the WordPress Administration interface
435 *
436 * @since 1.0.0
437 *
438 * @param string $parent_slug Parent Slug.
439 */
440 public function register_support_menu( $parent_slug = '' ) {
441
442 // Bail if the Support Menu is hidden.
443 if ( ! $this->show_support_menu ) {
444 return;
445 }
446
447 // If a parent slug is defined, attach the submenu items to that.
448 // Otherwise use the plugin's name.
449 $slug = ( ! empty( $parent_slug ) ? $parent_slug : $this->plugin->name );
450
451 /**
452 * Filter the minimum capability for accessing Support Sub Menu.
453 *
454 * @since 1.0.0
455 *
456 * @param string $minimum_capability Minimum Capability.
457 */
458 $minimum_capability = apply_filters( str_replace( '-', '_', $this->plugin->name ) . '_admin_admin_menu_minimum_capability', 'manage_options' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName
459
460 add_submenu_page( $slug, __( 'Support', 'wp-to-buffer' ), __( 'Support', 'wp-to-buffer' ), $minimum_capability, $this->plugin->name . '-support', array( $this, 'support_screen' ) );
461
462 }
463
464 /**
465 * Adds Plugin Action Links to the Plugin when activated in the Plugins Screen.
466 *
467 * @since 1.0.0
468 *
469 * @param array $links Action Links.
470 * @return array Action Links
471 */
472 public function add_action_link( $links ) {
473
474 // Bail if the licensing class exists,as this means we're on a Pro version.
475 if ( class_exists( 'LicensingUpdateManager' ) ) {
476 return $links;
477 }
478
479 // Add Links.
480 if ( $this->get_upgrade_url( 'plugins' ) ) {
481 $links[] = '<a href="' . esc_attr( $this->get_upgrade_url( 'plugins' ) ) . '" rel="noopener" target="_blank">' . __( 'Upgrade', 'wp-to-buffer' ) . '</a>';
482 }
483
484 /**
485 * Filter the action links.
486 *
487 * @since 1.0.0
488 *
489 * @param array $links Action Links.
490 * @param string $plugin_name Plugin Name.
491 * @param object $plugin Plugin.
492 */
493 $links = apply_filters( 'wpzinc_dashboard_add_action_link', $links, $this->plugin->name, $this->plugin );
494
495 // Return.
496 return $links;
497
498 }
499
500 /**
501 * Displays a dismissible WordPress Administration notice requesting a review, if requested
502 * by the main Plugin and the Review Request hasn't been disabled.
503 *
504 * @since 1.0.0
505 */
506 public function maybe_display_review_request() {
507
508 // If the review request is disabled, bail.
509 if ( ! $this->show_review_request ) {
510 return;
511 }
512
513 // If we're not an Admin user, bail.
514 if ( ! function_exists( 'current_user_can' ) ) {
515 return;
516 }
517 if ( ! current_user_can( 'activate_plugins' ) ) {
518 return;
519 }
520
521 // If the review request was dismissed by the user, bail.
522 if ( $this->dismissed_review() ) {
523 return;
524 }
525
526 // If no review request has been set by the plugin, bail.
527 if ( ! $this->requested_review() ) {
528 return;
529 }
530
531 // Enqueue JS.
532 wp_enqueue_script( 'wpzinc-admin-review-notice' );
533 wp_localize_script(
534 'wpzinc-admin-review-notice',
535 'wpzinc_admin_review_notice',
536 array(
537 'plugin_name' => $this->plugin->name,
538 'action' => esc_attr( str_replace( '-', '_', $this->plugin->name ) ) . '_dismiss_review',
539 'nonce' => wp_create_nonce( 'wpzinc_admin_review_notice_dismiss_review' ),
540 )
541 );
542
543 // If here, display the request for a review.
544 include_once $this->dashboard_folder . '/views/review-notice.php';
545
546 }
547
548 /**
549 * Displays a message in the WordPress Administration footer requesting a review if
550 * the Review Request hasn't been disabled.
551 *
552 * @since 1.0.0
553 *
554 * @param string $text Message.
555 */
556 public function maybe_display_footer_review_request( $text ) {
557
558 // If the review request is disabled, bail.
559 if ( ! $this->show_review_request ) {
560 return $text;
561 }
562
563 // Bail if we're not on a Plugin screen.
564 if ( ! filter_has_var( INPUT_GET, 'page' ) ) {
565 return $text;
566 }
567 $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
568 if ( strpos( $page, $this->plugin->name ) === false ) {
569 return $text;
570 }
571
572 // Return review request text.
573 return sprintf(
574 /* translators: %1$s: Plugin Name, %2$s: Five Star Link to Review URL, %3$s: Link to Review URL, %4$s: Plugin Name */
575 __( 'Please rate %1$s %2$s on %3$s to help us grow %4$s. Thanks!', 'wp-to-buffer' ),
576 '<strong>' . $this->plugin->displayName . '</strong>',
577 '<a href="' . $this->get_review_url() . '" target="_blank">&#9733;&#9733;&#9733;&#9733;&#9733;</a>',
578 '<a href="' . $this->get_review_url() . '" target="_blank">WordPress.org</a>',
579 $this->plugin->displayName
580 );
581
582 }
583
584 /**
585 * Flag to indicate whether a review has been requested.
586 *
587 * @since 1.0.0
588 *
589 * @return bool Review Requested
590 */
591 public function requested_review() {
592
593 // If the review request is disabled, bail.
594 if ( ! $this->show_review_request ) {
595 return false;
596 }
597
598 $time = get_option( $this->plugin->review_name . '-review-request' );
599 if ( empty( $time ) ) {
600 return false;
601 }
602
603 // Check the current date and time matches or is later than the above value.
604 $now = time();
605 if ( $now >= ( $time + ( 3 * DAY_IN_SECONDS ) ) ) {
606 return true;
607 }
608
609 // We're not yet ready to show this review.
610 return false;
611
612 }
613
614 /**
615 * Requests a review notification, which is displayed on subsequent page loads.
616 *
617 * @since 1.0.0
618 */
619 public function request_review() {
620
621 // If the review request is disabled, bail.
622 if ( ! $this->show_review_request ) {
623 return;
624 }
625
626 // If a review has already been requested, bail.
627 $time = get_option( $this->plugin->review_name . '-review-request' );
628 if ( ! empty( $time ) ) {
629 return;
630 }
631
632 // Request a review, setting the value to the date and time now.
633 update_option( $this->plugin->review_name . '-review-request', time() );
634
635 }
636
637 /**
638 * Flag to indicate whether a review request has been dismissed by the user.
639 *
640 * @since 1.0.0
641 *
642 * @return bool Review Dismissed.
643 */
644 public function dismissed_review() {
645
646 return get_option( $this->plugin->review_name . '-review-dismissed' );
647
648 }
649
650 /**
651 * Dismisses the review notification, so it isn't displayed again.
652 *
653 * @since 1.0.0
654 */
655 public function dismiss_review() {
656
657 // Check nonce.
658 check_ajax_referer( 'wpzinc_admin_review_notice_dismiss_review', 'nonce' );
659
660 // Mark review as dismissed.
661 update_option( $this->plugin->review_name . '-review-dismissed', 1 );
662
663 // Send success response.
664 wp_send_json_success( 1 );
665
666 }
667
668 /**
669 * Returns the Review URL for this Plugin.
670 *
671 * @since 1.0.0
672 *
673 * @return string Review URL
674 */
675 public function get_review_url() {
676
677 $url = 'https://wordpress.org/support/plugin/' . $this->plugin->review_name . '/reviews/?filter=5#new-post';
678
679 return $url;
680
681 }
682
683 /**
684 * Returns the Upgrade URL for this Plugin.
685 *
686 * Adds Google Analytics UTM tracking, and optional coupon flag.
687 *
688 * @since 1.0.0
689 *
690 * @param string $utm_content UTM Content Value.
691 * @return mixed false | Upgrade URL
692 */
693 public function get_upgrade_url( $utm_content = '' ) {
694
695 // Bail if no Upgrade URL specified by the Plugin.
696 if ( ! isset( $this->plugin->upgrade_url ) ) {
697 return false;
698 }
699
700 // Return upgrade URL with UTM parameters appended.
701 return $this->append_utm_params_to_url( $this->plugin->upgrade_url, $utm_content );
702
703 }
704
705 /**
706 * Appends UTM parameters to a given URL.
707 *
708 * @since 1.0.0
709 *
710 * @param string $url URL to append UTM parameters to.
711 * @param string $utm_content UTM Content Value.
712 * @return string
713 */
714 public function append_utm_params_to_url( $url, $utm_content = '' ) {
715
716 return add_query_arg(
717 array(
718 'utm_source' => $this->plugin->name,
719 'utm_medium' => 'link',
720 'utm_content' => $utm_content,
721 'utm_campaign' => 'general',
722 ),
723 $url
724 );
725
726 }
727
728 /**
729 * Import / Export Screen.
730 *
731 * @since 1.0.0
732 */
733 public function import_export_screen() {
734
735 // Check nonce.
736 if ( isset( $_POST[ $this->plugin->name . '_nonce' ] ) && wp_verify_nonce( sanitize_key( $_POST[ $this->plugin->name . '_nonce' ] ), $this->plugin->name ) ) {
737 // Import if requested.
738 if ( isset( $_POST['import'] ) ) {
739 // Import JSON.
740 $this->import();
741 }
742 }
743
744 /**
745 * Filter the import sources.
746 *
747 * @since 1.0.0
748 *
749 * @param array $import_sources Import Sources.
750 */
751 $import_sources = apply_filters( str_replace( '-', '_', $this->plugin->name ) . '_import_sources', array() ); // phpcs:ignore WordPress.NamingConventions.ValidHookName
752
753 // Output view.
754 include_once $this->dashboard_folder . '/views/import-export.php';
755
756 }
757
758 /**
759 * Import JSON file upload that confirms to our standards.
760 *
761 * @since 1.0.0
762 */
763 private function import() {
764
765 // Check nonce.
766 if ( ! isset( $_POST[ $this->plugin->name . '_nonce' ] ) ) {
767 // Missing nonce.
768 return;
769 }
770
771 if ( ! wp_verify_nonce( sanitize_key( $_POST[ $this->plugin->name . '_nonce' ] ), $this->plugin->name ) ) {
772 // Invalid nonce.
773 return;
774 }
775
776 if ( ! is_array( $_FILES ) ) {
777 $this->error_message = __( 'No file was uploaded', 'wp-to-buffer' );
778 return;
779 }
780 if ( ! isset( $_FILES['import']['type'] ) || ! isset( $_FILES['import']['tmp_name'] ) || ! isset( $_FILES['import']['size'] ) ) {
781 $this->error_message = __( 'Could not determine file type', 'wp-to-buffer' );
782 return;
783 }
784
785 if ( isset( $_FILES['import']['error'] ) && $_FILES['import']['error'] !== 0 ) {
786 $this->error_message = __( 'Error when uploading file.', 'wp-to-buffer' );
787 return;
788 }
789
790 // Determine if the file is JSON or ZIP.
791 switch ( $_FILES['import']['type'] ) {
792 /**
793 * ZIP File
794 */
795 case 'application/zip':
796 // Open ZIP file.
797 $zip = new \ZipArchive();
798 if ( $zip->open( sanitize_text_field( wp_unslash( $_FILES['import']['tmp_name'] ) ) ) !== true ) {
799 $this->error_message = __( 'Could not extract the supplied ZIP file.', 'wp-to-buffer' );
800 return;
801 }
802
803 // Extract and close.
804 $zip->extractTo( sys_get_temp_dir() );
805 $zip->close();
806
807 // Read JSON file.
808 // phpcs:disable WordPress.WP.AlternativeFunctions
809 $handle = fopen( sys_get_temp_dir() . '/export.json', 'r' );
810 $json = fread( $handle, filesize( sys_get_temp_dir() . '/export.json' ) );
811 fclose( $handle );
812 // phpcs:enable
813 break;
814
815 default:
816 // Read file.
817 // phpcs:disable WordPress.WP.AlternativeFunctions
818 $handle = fopen( sanitize_text_field( wp_unslash( $_FILES['import']['tmp_name'] ) ), 'r' );
819 $json = fread( $handle, sanitize_text_field( wp_unslash( $_FILES['import']['size'] ) ) );
820 fclose( $handle );
821 // phpcs:enable
822
823 }
824
825 // Remove UTF8 BOM chars.
826 $bom = pack( 'H*', 'EFBBBF' );
827 $json = preg_replace( "/^$bom/", '', $json );
828
829 // Decode.
830 $import = json_decode( $json, true );
831
832 // Check data is an array.
833 if ( ! is_array( $import ) ) {
834 $this->error_message = __( 'Supplied file is not a valid JSON settings file, or has become corrupt.', 'wp-to-buffer' );
835 return;
836 }
837
838 // Allow Plugin to run its Import Routine using the supplied data now.
839 $result = true;
840 $result = apply_filters( str_replace( '-', '_', $this->plugin->name ) . '_import', $result, $import ); // phpcs:ignore WordPress.NamingConventions.ValidHookName
841
842 // Bail if an error occured.
843 if ( is_wp_error( $result ) ) {
844 $this->error_message = $result->get_error_message();
845 return;
846 }
847
848 $this->message = __( 'Settings imported.', 'wp-to-buffer' );
849
850 }
851
852 /**
853 * Support Screen
854 *
855 * @since 1.0.0
856 */
857 public function support_screen() {
858 // We never reach here, as we redirect earlier in the process.
859 }
860
861 /**
862 * About Section
863 *
864 * @since 1.0.0
865 */
866 public function about_section() {
867
868 // Define products.
869 $products = array(
870 array(
871 'name' => 'Page Generator Pro',
872 'url' => $this->append_utm_params_to_url( 'https://www.wpzinc.com/plugins/page-generator-pro/' ),
873 'icon' => 'https://www.wpzinc.com/wp-content/uploads/2025/01/page-generator-pro-logo-256x256-1.png',
874 'description' => 'Automatically mass build local SEO, programmatic SEO, GEO sites, directories or content at scale with one-click deployment. Save 40 hours per site.',
875 'price' => 99,
876 ),
877 array(
878 'name' => 'Social Post Flow',
879 'url' => $this->append_utm_params_to_url( 'https://www.socialpostflow.com' ),
880 'install_url' => admin_url(
881 add_query_arg(
882 array(
883 'tab' => 'search',
884 'type' => 'term',
885 's' => 'socialpostflow',
886 ),
887 'plugin-install.php'
888 )
889 ),
890 'icon' => 'https://www.socialpostflow.com/wp-content/uploads/2025/05/logo.png',
891 'description' => 'Automatically send content to your Social Post Flow account for scheduled publishing to Facebook, X/Twitter, Threads, Instagram, LinkedIn, Pinterest, Mastodon and Bluesky.',
892 'price' => 49,
893 ),
894 array(
895 'name' => 'WordPress to Buffer Pro',
896 'url' => $this->append_utm_params_to_url( 'https://www.wpzinc.com/plugins/wordpress-to-buffer-pro/' ),
897 'icon' => 'https://www.wpzinc.com/wp-content/uploads/2025/11/buffer-square.png',
898 'description' => 'Automatically send content to your Buffer account for scheduled publishing to Facebook, X, Instagram, Threads, LinkedIn, Pinterest, Mastodon, Bluesky, TikTok and Google Business.',
899 'price' => 39,
900 ),
901 array(
902 'name' => 'WordPress to Postiz Pro',
903 'url' => $this->append_utm_params_to_url( 'https://www.wpzinc.com/plugins/wordpress-to-postiz-pro/' ),
904 'icon' => 'https://www.wpzinc.com/wp-content/uploads/2026/08/postiz.png',
905 'description' => 'Automatically send content to your Postiz account for scheduled publishing to Facebook, Twitter, Instagram, Pinterest, LinkedIn and more.',
906 'price' => 39,
907 ),
908 array(
909 'name' => 'WordPress to Hootsuite Pro',
910 'url' => $this->append_utm_params_to_url( 'https://www.wpzinc.com/plugins/wordpress-to-hootsuite-pro/' ),
911 'icon' => 'https://www.wpzinc.com/wp-content/uploads/2018/03/hootsuite-logo-1.png',
912 'description' => 'Automatically send content to your Hootsuite account for scheduled publishing to Facebook, X / Twitter, LinkedIn, Pinterest and Threads.',
913 'price' => 39,
914 ),
915 array(
916 'name' => 'WordPress to SocialPilot Pro',
917 'url' => $this->append_utm_params_to_url( 'https://www.wpzinc.com/plugins/wordpress-to-socialpilot-pro/' ),
918 'icon' => 'https://www.wpzinc.com/wp-content/uploads/2019/05/socialpilot-logo.png',
919 'description' => 'Automatically send content to your SocialPilot account for scheduled publishing to Facebook, Twitter, Instagram, Pinterest, LinkedIn and more.',
920 'price' => 39,
921 ),
922 );
923
924 // Load view.
925 include $this->dashboard_folder . '/views/about.php';
926
927 }
928
929 /**
930 * If we have requested the export JSON, force a file download
931 *
932 * @since 1.0.0
933 */
934 public function export() {
935
936 // Check nonce.
937 if ( ! isset( $_POST[ $this->plugin->name . '_nonce' ] ) ) {
938 // Missing nonce.
939 return;
940 }
941
942 if ( ! wp_verify_nonce( sanitize_key( $_POST[ $this->plugin->name . '_nonce' ] ), $this->plugin->name ) ) {
943 // Invalid nonce.
944 return;
945 }
946
947 // Bail if no POST data.
948 if ( empty( $_POST ) ) {
949 return;
950 }
951
952 // Bail if not exporting.
953 if ( ! isset( $_POST['export'] ) ) {
954 return;
955 }
956
957 // Bail if no format specified.
958 if ( ! isset( $_POST['format'] ) ) {
959 return;
960 }
961
962 // Define the array to hold the export data.
963 $data = array();
964
965 /**
966 * Defines the data to include in the export file. Plugins hook into this
967 * to define the data.
968 *
969 * @since 1.0.0
970 *
971 * @param array $data Data.
972 * @param array $_POST POST Data.
973 */
974 $data = apply_filters( str_replace( '-', '_', $this->plugin->name ) . '_export', $data, $_POST );
975
976 // Force a file download, depending on the export format.
977 switch ( sanitize_text_field( wp_unslash( $_POST['format'] ) ) ) {
978 /**
979 * JSON, Zipped.
980 */
981 case 'zip':
982 $this->force_zip_file_download(
983 wp_json_encode(
984 array(
985 'data' => $data,
986 )
987 )
988 );
989 break;
990
991 /**
992 * JSON.
993 */
994 case 'json':
995 default:
996 $this->force_json_file_download(
997 wp_json_encode(
998 array(
999 'data' => $data,
1000 )
1001 )
1002 );
1003 break;
1004 }
1005
1006 }
1007
1008 /**
1009 * Force a browser download comprising of the given file, zipped.
1010 *
1011 * @since 1.0.0
1012 *
1013 * @param string $json JSON string.
1014 * @param string $filename Filename to Export Data to, excluding extension (default: export).
1015 */
1016 public function force_zip_file_download( $json, $filename = 'export' ) {
1017
1018 // Create new ZIP file.
1019 $zip = new \ZipArchive();
1020 $filename = $filename . '.zip';
1021
1022 // Bail if ZIP file couldn't be created.
1023 if ( $zip->open( $filename, \ZipArchive::CREATE ) !== true ) {
1024 return;
1025 }
1026
1027 // Add JSON data to export.json and close.
1028 $zip->addFromString( $filename . '.json', $json );
1029 $zip->close();
1030
1031 // Initialize WP_Filesystem.
1032 global $wp_filesystem;
1033 if ( empty( $wp_filesystem ) ) {
1034 require_once ABSPATH . '/wp-admin/includes/file.php';
1035 WP_Filesystem();
1036 }
1037
1038 // Read file contents.
1039 $zip_contents = $wp_filesystem->get_contents( $filename );
1040
1041 // Output ZIP data, prompting the browser to auto download as a ZIP file now.
1042 header( 'Content-type: application/zip' );
1043 header( 'Content-Disposition: attachment; filename=' . $filename . '.zip' );
1044 header( 'Pragma: no-cache' );
1045 header( 'Expires: 0' );
1046 echo $zip_contents; // phpcs:ignore WordPress.Security.EscapeOutput
1047
1048 // Delete the temporary file.
1049 $wp_filesystem->delete( $filename );
1050 exit();
1051
1052 }
1053
1054 /**
1055 * Force a browser download comprising of the given JSON data
1056 *
1057 * @since 1.0.0
1058 *
1059 * @param string $json JSON Data for file.
1060 * @param string $filename Filename to Export Data to, excluding extension (default: export).
1061 */
1062 public function force_json_file_download( $json, $filename = 'export' ) {
1063
1064 // Output JSON data, prompting the browser to auto download as a JSON file now.
1065 header( 'Content-type: application/x-msdownload' );
1066 header( 'Content-Disposition: attachment; filename=' . $filename . '.json' );
1067 header( 'Pragma: no-cache' );
1068 header( 'Expires: 0' );
1069 echo $json; // phpcs:ignore WordPress.Security.EscapeOutput
1070 exit();
1071
1072 }
1073
1074 /**
1075 * Force a browser download comprising of the given CSV data
1076 *
1077 * @since 1.0.0
1078 *
1079 * @param string $csv CSV Data for file.
1080 * @param string $filename Filename to Export Data to, excluding extension (default: export).
1081 */
1082 public function force_csv_file_download( $csv, $filename = 'export' ) {
1083
1084 // Output JSON data, prompting the browser to auto download as a JSON file now.
1085 header( 'Content-Type: text/csv; charset=UTF-8' );
1086 header( 'Content-Disposition: attachment; filename=' . $filename . '.csv' );
1087 header( 'Pragma: no-cache' );
1088 header( 'Expires: 0' );
1089 echo $csv; // phpcs:ignore WordPress.Security.EscapeOutput
1090 exit();
1091
1092 }
1093
1094 /**
1095 * If the Support or Upgrade menu item was clicked, redirect.
1096 *
1097 * @since 3.0
1098 */
1099 public function maybe_redirect() {
1100
1101 // Check we requested the support page.
1102 if ( ! filter_has_var( INPUT_GET, 'page' ) ) {
1103 return;
1104 }
1105
1106 // Sanitize page.
1107 $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
1108
1109 // Redirect to Support.
1110 if ( $page === $this->plugin->name . '-support' ) {
1111 wp_safe_redirect( $this->plugin->support_url );
1112 die();
1113 }
1114
1115 // Redirect to Upgrade.
1116 if ( $page === $this->plugin->name . '-upgrade' ) {
1117 wp_safe_redirect( $this->get_upgrade_url( 'menu' ) );
1118 die();
1119 }
1120
1121 }
1122
1123 /**
1124 * Permit wpzinc.com to be redirected to when using wp_safe_redirect().
1125 *
1126 * @since 1.0.0
1127 *
1128 * @param array $hosts Hosts.
1129 * @return array Hosts.
1130 */
1131 public function allowed_redirect_hosts( $hosts ) {
1132
1133 $hosts[] = 'www.wpzinc.com';
1134 $hosts[] = 'www.socialpostflow.com';
1135 $hosts[] = 'app.socialpostflow.com';
1136
1137 return $hosts;
1138
1139 }
1140
1141 }
1142