PluginProbe
Social Media Auto Poster – Schedule & Publish to Buffer / 6.0.7
Social Media Auto Poster – Schedule & Publish to Buffer v6.0.7
6.2.5 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 All 126 releases
wp-to-buffer / _modules / dashboard / class-wpzincdashboardwidget.php

class-wpzincdashboardwidget.php in Social Media Auto Poster – Schedule & Publish to Buffer 6.0.7, at _modules/dashboard/class-wpzincdashboardwidget.php

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