PluginProbe
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) / 1.8.13
Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) v1.8.13
1.8.13 1.8.12.3 1.8.12.2 1.8.12.1 1.8.12 1.8.11.3 1.8.11.2 1.8.11.1 1.8.11 1.6.6 1.6.60 1.6.7 1.6.8 1.6.9 1.7.0 1.7.0.1 1.7.0.11 1.7.0.12 1.7.0.14 1.7.0.2 1.7.0.3 1.7.0.5 1.7.0.6 1.7.0.7 1.7.0.9 All 211 releases
charitable / includes / admin / plugins / class-charitable-admin-plugins-third-party.php

class-charitable-admin-plugins-third-party.php in Charitable – Donation & Fundraising Platform (Donation Forms, Recurring Donations & Fundraising Campaigns) 1.8.13, at includes/admin/plugins/class-charitable-admin-plugins-third-party.php

1,563 lines 57.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * This class is responsible for interactions (downloading/installing) addons and third-party addons, and recommendations.
4 *
5 * @package Charitable/Classes/Charitable_Admin_Plugins_Third_Party
6 * @author David Bisset
7 * @copyright Copyright (c) 2023, WP Charitable LLC
8 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
9 * @since 1.8.1
10 */
11
12 // Exit if accessed directly.
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 if ( ! class_exists( 'Charitable_Admin_Plugins_Third_Party' ) ) :
18
19 /**
20 * Charitable_Admin_Analytics
21 *
22 * @since 1.8.1
23 */
24 final class Charitable_Admin_Plugins_Third_Party {
25
26 /**
27 * The name of our database table
28 *
29 * @since 1.8.1
30 *
31 * @var string
32 */
33 public $table_name;
34
35 /**
36 * General storage for analytic data
37 *
38 * @since 1.8.1
39 *
40 * @var array
41 */
42 public $analytics;
43
44 /**
45 * The single instance of this class.
46 *
47 * @var Charitable_Admin_Plugins_Third_Party|null
48 */
49 private static $instance = null;
50
51
52 /**
53 * Create class object.
54 *
55 * @since 1.8.1
56 */
57 public function __construct() {
58
59 $this->init();
60 }
61
62 /**
63 * Init class.
64 *
65 * @since 1.8.1
66 */
67 public function init() {
68
69 add_action( 'wp_ajax_charitable_dismiss_suggestion', array( $this, 'charitable_dismiss_suggestion' ) );
70 }
71
72 /**
73 * Dismiss a suggestion via AJAX.
74 *
75 * @since 1.8.1.5
76 *
77 * @return void
78 */
79 public function charitable_dismiss_suggestion() {
80
81 check_ajax_referer( 'charitable-admin', 'nonce' );
82
83 $post_data = sanitize_post( $_POST, 'raw' );
84
85 $slug = isset( $post_data['slug'] ) ? sanitize_text_field( wp_unslash( $post_data['slug'] ) ) : false;
86 $type = isset( $post_data['type'] ) ? sanitize_text_field( wp_unslash( $post_data['type'] ) ) : false;
87
88 if ( ! $slug ) {
89 wp_send_json(
90 array(
91 'message' => esc_html__( 'Missing plugin name for dismiss.', 'charitable' ),
92 )
93 );
94 }
95
96 if ( ! $type ) {
97 wp_send_json(
98 array(
99 'message' => esc_html__( 'Missing plugin type for dismiss.', 'charitable' ),
100 )
101 );
102 }
103
104 if ( 'addon' === $type ) {
105
106 $user_meta_key = 'charitable_dismissed_addons';
107
108 } elseif ( 'partner' === $type ) {
109
110 $user_meta_key = 'charitable_dismissed_partners';
111
112 } else {
113 wp_send_json(
114 array(
115 'message' => esc_html__( 'Invalid plugin type for dismiss.', 'charitable' ),
116 )
117 );
118 }
119
120 $dismissed = (array) get_user_meta( get_current_user_id(), $user_meta_key, true );
121
122 if ( ! in_array( $slug, $dismissed, true ) ) {
123 $dismissed[] = $slug;
124 }
125
126 // remove blank values.
127 $dismissed = array_filter( $dismissed );
128
129 // update user meta.
130 update_user_meta( get_current_user_id(), $user_meta_key, $dismissed );
131
132 wp_send_json_success(
133 array(
134 'dismissed' => $dismissed,
135 ),
136 200
137 );
138
139 wp_die();
140 }
141
142 /**
143 * Install plugins which are not Charitable addons.
144 *
145 * @since 1.8.1
146 *
147 * @return void
148 */
149 public function install_plugin() {
150
151 check_admin_referer( 'charitable-admin', 'nonce' );
152
153 $post_data = sanitize_post( $_POST, 'raw' );
154
155 // Permission check.
156 if ( ! current_user_can( 'install_plugins' ) ) {
157 wp_send_json(
158 array(
159 'error' => esc_html__( 'Plugin install is disabled for you on this site.', 'charitable' ),
160 )
161 );
162
163 wp_send_json_error( esc_html__( 'Install error', 'charitable' ) );
164 }
165
166 $slug = isset( $post_data['slug'] ) ? sanitize_text_field( wp_unslash( $post_data['slug'] ) ) : false;
167
168
169 if ( ! $slug ) {
170 wp_send_json(
171 array(
172 'message' => esc_html__( 'Missing plugin name for install.', 'charitable' ),
173 )
174 );
175 }
176
177 include_once ABSPATH . 'wp-admin/includes/plugin-install.php';
178 $api = plugins_api(
179 'plugin_information',
180 array(
181 'slug' => $slug,
182 'fields' => array(
183 'short_description' => false,
184 'sections' => false,
185 'requires' => false,
186 'rating' => false,
187 'ratings' => false,
188 'downloaded' => false,
189 'last_updated' => false,
190 'added' => false,
191 'tags' => false,
192 'compatibility' => false,
193 'homepage' => false,
194 'donate_link' => false,
195 ),
196 )
197 );
198
199 if ( is_wp_error( $api ) ) {
200 wp_send_json(
201 array(
202 'error' => $api->get_error_message(),
203 )
204 );
205 if ( charitable_is_debug() ) :
206 error_log( print_r( $api->get_error_message(), true ) ); // phpcs:ignore
207 endif;
208 die();
209 }
210
211 $download_url = $api->download_link;
212
213 $method = '';
214 $url = add_query_arg(
215 array(
216 'page' => 'charitable_settings',
217 ),
218 admin_url( 'admin.php' )
219 );
220 $url = esc_url( $url );
221
222 ob_start();
223 if ( false === ( $creds = request_filesystem_credentials( $url, $method, false, false, null ) ) ) { // phpcs:ignore
224 $form = ob_get_clean();
225
226 wp_send_json( array( 'form' => $form ) );
227 }
228
229 // If we are not authenticated, make it happen now.
230 if ( ! WP_Filesystem( $creds ) ) {
231 ob_start();
232 request_filesystem_credentials( $url, $method, true, false, null );
233 $form = ob_get_clean();
234 wp_send_json( array( 'form' => $form ) );
235 die();
236 }
237
238 // Prevent language upgrade in ajax calls.
239 remove_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );
240
241 // We do not need any extra credentials if we have gotten this far, so let's install the plugin.
242 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
243 require_once plugin_dir_path( CHARITABLE_DIRECTORY_PATH ) . 'charitable/includes/utilities/Skin.php';
244
245 // Create the plugin upgrader with our custom skin.
246 $skin = new Charitable_Skin();
247 $installer = new Plugin_Upgrader( $skin );
248 $installer->install( $download_url );
249
250 // Flush the cache and return the newly installed plugin basename.
251 wp_cache_flush();
252
253 // send json success with array.
254 $basename = $this->get_basename_from_slug( $slug );
255
256 wp_send_json_success(
257 array(
258 'basename' => $basename,
259 ),
260 200
261 );
262
263 wp_die();
264 }
265
266 /**
267 * Get plugin basename from slug.
268 *
269 * @param string $slug The plugin slug.
270 */
271 public function get_basename_from_slug( $slug = false ) {
272
273 if ( false === $slug ) {
274 return;
275 }
276
277 $basename = '';
278 $plugins = $this->get_plugins( false );
279 if ( charitable_is_debug() ) :
280 error_log( print_r( $plugins, true ) ); // phpcs:ignore
281 endif;
282 if ( ! empty( $plugins ) ) :
283 foreach ( $plugins as $nice_name => $plugin ) {
284 if ( charitable_is_debug() ) :
285 error_log( print_r( $plugin, true ) ); // phpcs:ignore
286 endif;
287 if ( ! empty( $plugin['slug'] ) && ( $slug === $plugin['slug'] || $slug === $nice_name ) && isset( $plugin['basename'] ) ) {
288 $basename = $plugin['basename'];
289 }
290 }
291 endif;
292
293 return $basename;
294 }
295
296 /**
297 * Activate plugin.
298 *
299 * @since 1.8.1
300 * @version 1.8.4
301 *
302 * @return void
303 */
304 public function activate_plugin() {
305
306 check_ajax_referer( 'charitable-admin', 'nonce' );
307
308 $post_data = sanitize_post( $_POST, 'raw' );
309
310 if ( ! current_user_can( 'install_plugins' ) ) {
311 wp_send_json(
312 array(
313 'error' => esc_html__( 'You are not allowed to install plugins', 'charitable' ),
314 )
315 );
316 }
317
318 $basename = isset( $post_data['basename'] ) ? sanitize_text_field( wp_unslash( $post_data['basename'] ) ) : false;
319
320 if ( ! $basename ) {
321 wp_send_json(
322 array(
323 'message' => esc_html__( 'Missing plugin basename.', 'charitable' ),
324 )
325 );
326 }
327
328 $success = activate_plugin( $basename, '', false );
329
330 // Disable MonsterInsights redirect.
331 if ( strstr( $basename, 'google-analytics-for-wordpress' ) ) {
332 if ( charitable_is_debug() ) :
333 error_log( print_r( 'MonsterInsights activated, deleting transient/updating option to prevent redirect.', true ) ); // phpcs:ignore
334 endif;
335 delete_transient( '_monsterinsights_activation_redirect' );
336 }
337 // Disable Exactmetrics redirect.
338 if ( strstr( $basename, 'google-analytics-dashboard-for-wp' ) ) {
339 if ( charitable_is_debug() ) :
340 error_log( print_r( 'Exactmetrics activated, deleting transient/updating option to prevent redirect.', true ) ); // phpcs:ignore
341 endif;
342 delete_transient( '_exactmetrics_activation_redirect' );
343 }
344 // Disable WP Mail SMTP redirect.
345 if ( strstr( $basename, 'wp-mail-smtp' ) ) {
346 if ( charitable_is_debug() ) :
347 error_log( print_r( 'WP Mail SMTP activated, deleting transient/updating option to prevent redirect.', true ) ); // phpcs:ignore
348 endif;
349 delete_transient( 'wp_mail_smtp_activation_redirect' );
350 }
351 // Disable Rafflepress redirect.
352 if ( strstr( $basename, 'rafflepress' ) ) {
353 if ( charitable_is_debug() ) :
354 error_log( print_r( 'Rafflepress activated, deleting transient/updating option to prevent redirect.', true ) ); // phpcs:ignore
355 endif;
356 delete_transient( '_rafflepress_welcome_screen_activation_redirect' );
357 }
358 // Disable seedprod redirect.
359 if ( strstr( $basename, 'seedprod' ) ) {
360 if ( charitable_is_debug() ) :
361 error_log( print_r( 'SeedProd activated, deleting transient/updating option to prevent redirect.', true ) ); // phpcs:ignore
362 endif;
363 delete_transient( '_seedprod_welcome_screen_activation_redirect' );
364 }
365 // Disable instagram-feed redirect.
366 if ( strstr( $basename, 'instagram-feed' ) ) {
367 if ( charitable_is_debug() ) :
368 error_log( print_r( 'Instagram Feed activated, deleting transient/updating option to prevent redirect.', true ) ); // phpcs:ignore
369 endif;
370 delete_option( 'sbi_plugin_do_activation_redirect' );
371 }
372 // Disable facebook-feed redirect.
373 if ( strstr( $basename, 'facebook-feed' ) ) {
374 if ( charitable_is_debug() ) :
375 error_log( print_r( 'Facebook Feed activated, deleting transient/updating option to prevent redirect.', true ) ); // phpcs:ignore
376 endif;
377 delete_option( 'cff_plugin_do_activation_redirect' );
378 }
379 // Disable trustpulse redirect.
380 if ( strstr( $basename, 'trustpulse' ) ) {
381 if ( charitable_is_debug() ) :
382 error_log( print_r( 'TrustPulse activated, deleting transient/updating option to prevent redirect.', true ) ); // phpcs:ignore
383 endif;
384 delete_option( 'trustpulse_api_plugin_do_activation_redirect' );
385 }
386 // Disable searchwp-live-ajax-search redirect.
387 if ( strstr( $basename, 'searchwp-live-ajax-search' ) ) {
388 if ( charitable_is_debug() ) :
389 error_log( print_r( 'SearchWP Live Search activated, deleting transient/updating option to prevent redirect.', true ) ); // phpcs:ignore
390 endif;
391 delete_transient( 'searchwp_live_search_activation_redirect' );
392 }
393 // Disable duplicator redirect.
394 if ( strstr( $basename, 'duplicator' ) ) {
395 if ( charitable_is_debug() ) :
396 error_log( print_r( 'Duplicator activated, deleting transient/updating option to prevent redirect.', true ) ); // phpcs:ignore
397 endif;
398 update_option( 'duplicator_redirect_to_welcome', false );
399 }
400 // Disable pushengage redirect.
401 if ( strstr( $basename, 'pushengage' ) ) {
402 if ( charitable_is_debug() ) :
403 error_log( print_r( 'PushEngage activated, deleting transient/updating option to prevent redirect.', true ) ); // phpcs:ignore
404 endif;
405 delete_transient( 'pushengage_activation_redirect' );
406 }
407
408 /*
409 * Record that Charitable drove this WPVibe install, for cross-brand
410 * attribution. The option pair is UNPREFIXED on purpose: whichever
411 * Awesome Motive plugin installs the promoted plugin writes its own
412 * name into `<plugin>_source`, and each brand's own check-in claims
413 * only the installs whose source names IT. The key is `wpvibe_source`,
414 * the plugin's published `vibe-ai` slug notwithstanding, because that
415 * is the key every brand agrees to read - WPForms uses the identical
416 * pair for the same plugin. Guarded so a value another AM plugin
417 * already wrote is never overwritten: the option records who FIRST
418 * drove the install. This method is reached only through Charitable's
419 * own AJAX installer, so the attribution is never claimed for an
420 * activation the user made from the Plugins screen directly.
421 *
422 * Written as a fixed 'Charitable Lite', not a charitable_is_pro()
423 * ternary: this file ships in the Lite plugin, so the driver is
424 * always Charitable Lite. Pro's own copy of this method (Charitable
425 * Pro is a separate, standalone plugin - it never runs alongside
426 * Lite) writes 'Charitable Pro'. Both strings contain 'Charitable',
427 * which is all a receiving check-in matches on.
428 *
429 * Autoload explicitly OFF (fix round 2, ITEM 2): Pro's own copy of
430 * this method omits the third argument, which defaults an option
431 * to autoloaded. Both of these are read only from this one admin
432 * screen and from a weekly check-in - never on the front end, never
433 * on most admin requests - so there is no reason to load either of
434 * them into memory on every request the way autoloaded options are.
435 * Deliberately NOT matching Pro here.
436 *
437 * @since 1.8.13
438 */
439 if ( strstr( $basename, 'vibe-ai' ) && ! get_option( 'wpvibe_source' ) ) {
440 update_option( 'wpvibe_source', 'Charitable Lite', false );
441 update_option( 'wpvibe_date', time(), false );
442 }
443
444 if ( is_wp_error( $success ) ) {
445 wp_send_json_error(
446 array(
447 'error' => $success->get_error_message(),
448 )
449 );
450 wp_die();
451 }
452
453 $setup = $this->get_setup_screen_for_plugin( $basename );
454
455 if ( $setup ) :
456
457 wp_send_json_success(
458 array(
459 'setup' => $setup,
460 ),
461 200
462 );
463 wp_die();
464
465 endif;
466
467 $settings = $this->get_settings_screen_for_plugin( $basename );
468
469 if ( $settings ) :
470
471 wp_send_json_success(
472 array(
473 'settings' => $settings,
474 ),
475 200
476 );
477 wp_die();
478
479 endif;
480
481 wp_die();
482 }
483
484 /**
485 * Checks if plugin is installed.
486 *
487 * @param string $plugin The plugin slug.
488 */
489 public function is_plugin_installed( $plugin = '' ) {
490
491 if ( empty( $plugin ) ) {
492 return false;
493 }
494
495 $plugins = $this->get_plugins( false );
496
497 if ( ! empty( $plugins[ $plugin ] ) && ! empty( $plugins[ $plugin ]['installed'] ) ) {
498 return (bool) $plugins[ $plugin ]['installed'];
499 }
500
501 return false;
502 }
503
504 /**
505 * Checks if plugin is activated.
506 *
507 * @param string $plugin The plugin slug.
508 */
509 public function is_plugin_activated( $plugin = '' ) {
510
511 if ( empty( $plugin ) ) {
512 return false;
513 }
514
515 $plugins = $this->get_plugins( false );
516
517 if ( ! empty( $plugins[ $plugin ] ) && ! empty( $plugins[ $plugin ]['active'] ) ) {
518 return (bool) $plugins[ $plugin ]['active'];
519 }
520
521 return false;
522 }
523
524 /**
525 * Get plugin basename.
526 *
527 * @param string $plugin The plugin slug.
528 */
529 public function get_basename( $plugin = '' ) {
530
531 if ( empty( $plugin ) ) {
532 return false;
533 }
534
535 $plugins = $this->get_plugins( false );
536
537 if ( ! empty( $plugins[ $plugin ] ) && ! empty( $plugins[ $plugin ]['active'] ) ) {
538 return $plugins[ $plugin ]['basename'];
539 }
540
541 return false;
542 }
543
544 /**
545 * Get plugin setup url.
546 *
547 * @param string $slug_or_basename The plugin slug.
548 */
549 public function get_setup_screen_for_plugin( $slug_or_basename = false ) {
550
551 if ( false === $slug_or_basename ) {
552 return;
553 }
554
555 $setup = '';
556 $plugins = $this->get_plugins( false );
557 if ( ! empty( $plugins ) ) :
558 foreach ( $plugins as $plugin_slug => $plugin_info ) {
559 if ( ! empty( $plugin_info['setup'] ) && ( $plugin_slug === $slug_or_basename || $plugin_info['basename'] === $slug_or_basename ) ) {
560 $setup = $plugin_info['setup'];
561 }
562 }
563 endif;
564
565 return $setup;
566 }
567
568 /**
569 * Get plugin settings url.
570 *
571 * @param string $slug_or_basename The plugin slug.
572 */
573 public function get_settings_screen_for_plugin( $slug_or_basename = false ) {
574
575 if ( false === $slug_or_basename ) {
576 return;
577 }
578
579 $setup = '';
580 $plugins = $this->get_plugins( false );
581 if ( ! empty( $plugins ) ) :
582 foreach ( $plugins as $plugin_slug => $plugin_info ) {
583 if ( ! empty( $plugin_info['settings'] ) && ( $plugin_slug === $slug_or_basename || $plugin_info['basename'] === $slug_or_basename ) ) {
584 $setup = $plugin_info['settings'];
585 }
586 }
587 endif;
588
589 return $setup;
590 }
591
592 /**
593 * Get plugin learn more button.
594 *
595 * @param string $plugin_slug The plugin slug.
596 * @param string $button_text The button text.
597 * @param string $css The button css.
598 */
599 public function get_learn_more_button_html( $plugin_slug = false, $button_text = 'Learn More', $css = '' ) {
600
601 if ( false === $plugin_slug ) {
602 return;
603 }
604
605 $plugins = $this->get_plugins( false );
606
607 if ( ! isset( $plugins[ $plugin_slug ] ) ) {
608 return;
609 }
610
611 $plugin = $plugins[ $plugin_slug ];
612
613 if ( ! $plugin || ! isset( $plugin['slug'] ) ) {
614 return;
615 }
616
617 $button_css = 'charitable-button button-link charitable-button-learn-more';
618
619 if ( $css !== '' ) {
620 $button_css .= ' ' . $css;
621 }
622
623 if ( false === $button_text ) {
624 $button_text = esc_html__( 'Learn More', 'charitable' );
625 }
626
627 $url = ! empty( $plugin['gt_learn'] ) ? esc_url( $plugin['gt_learn'] ) : false;
628
629 if ( ! $url ) {
630 return;
631 }
632
633 $button = '<a href="' . $url . '" target=="_blank" class="' . $button_css . '" data-charitable-third-party-plugin="' . esc_attr( $plugin['slug'] ) . '">' . $button_text . '</a>';
634
635 return $button;
636 }
637
638 /**
639 * Get plugin install button.
640 *
641 * @param string $plugin_slug The plugin slug.
642 * @param string $button_text The button text.
643 * @param string $css The button css.
644 */
645 public function get_install_button_html( $plugin_slug = false, $button_text = 'Install', $css = '' ) {
646
647 if ( false === $plugin_slug ) {
648 return;
649 }
650
651 $plugins = $this->get_plugins( false );
652
653 if ( ! isset( $plugins[ $plugin_slug ] ) ) {
654 return;
655 }
656
657 $plugin = $plugins[ $plugin_slug ];
658
659 if ( ! $plugin || ! isset( $plugin['slug'] ) ) {
660 return;
661 }
662
663 $button_css = 'charitable-button button-link charitable-button-install';
664
665 if ( $css !== '' ) {
666 $button_css .= ' ' . $css;
667 }
668
669 if ( false === $button_text ) {
670 $button_text = esc_html__( 'Install', 'charitable' );
671 }
672
673 $button = '<a href="#" class="' . $button_css . '" data-charitable-third-party-plugin="' . esc_attr( $plugin['slug'] ) . '">' . $button_text . '</a>';
674
675 return $button;
676 }
677
678 /**
679 * Get plugin activation button.
680 *
681 * @param string $plugin_slug The plugin slug.
682 * @param string $button_text The button text.
683 * @param string $css The button css.
684 */
685 public function get_activation_button_html( $plugin_slug = false, $button_text = 'Activate', $css = '' ) {
686
687 if ( false === $plugin_slug ) {
688 return;
689 }
690
691 $plugins = $this->get_plugins( false );
692
693 if ( ! isset( $plugins[ $plugin_slug ] ) ) {
694 return;
695 }
696
697 $plugin = $plugins[ $plugin_slug ];
698
699 if ( ! $plugin || ! isset( $plugin['basename'] ) ) {
700 return;
701 }
702
703 $button_css = 'charitable-button button-link charitable-button-activate';
704
705 if ( $css !== '' ) {
706 $button_css .= ' ' . $css;
707 $button_css = str_replace( 'install', 'activate', $button_css );
708 }
709
710 if ( false === $button_text ) {
711 $button_text = esc_html__( 'Activate', 'charitable' );
712 }
713
714 $button = '<a href="#" class="' . $button_css . '" data-basename="' . $plugin['basename'] . '">' . $button_text . '</a>';
715
716 return $button;
717 }
718
719 /**
720 * Get plugin setup html link/button.
721 *
722 * @param string $plugin_slug The plugin slug.
723 * @param string $button_text The button text.
724 * @param string $css The button css.
725 * @param string $setup_link The setup link.
726 */
727 public function get_setup_button_html( $plugin_slug = false, $button_text = 'Activate', $css = '', $setup_link = '' ) {
728
729 if ( false === $plugin_slug ) {
730 return;
731 }
732
733 $plugins = $this->get_plugins( false );
734
735 if ( ! isset( $plugins[ $plugin_slug ] ) ) {
736 return;
737 }
738
739 $plugin = $plugins[ $plugin_slug ];
740
741 if ( ! $plugin || ! isset( $plugin['basename'] ) || ! isset( $plugin['setup'] ) ) {
742 return;
743 }
744
745 $setup_link = isset( $plugin['setup'] ) ? esc_url( $plugin['setup'] ) : esc_url( admin_url() );
746
747 $button_css = 'charitable-button button-link charitable-button-setup';
748
749 if ( $css !== '' ) {
750 $button_css .= ' ' . $css;
751 $button_css = str_replace( 'install', 'setup', $button_css );
752 $button_css = str_replace( 'activate', 'setup', $button_css );
753 }
754
755 if ( false === $button_text ) {
756 $button_text = esc_html__( 'Setup', 'charitable' );
757 }
758
759 $button = '<a href="' . esc_url( $setup_link ) . '" class="' . $button_css . '" data-basename="' . $plugin['basename'] . '">' . $button_text . '</a>';
760
761 return $button;
762 }
763
764 /**
765 * Get plugin button html.
766 *
767 * @since 1.8.1.5
768 *
769 * @param string $plugin_slug The plugin slug.
770 * @param string $button_text The button text.
771 * @param string $css The button css.
772 *
773 * @return string
774 */
775 public function get_plugin_button_html( $plugin_slug = false, $button_text = false, $css = false ) {
776
777 if ( false === $plugin_slug ) {
778 return;
779 }
780
781 if ( $this->is_plugin_learn_more( $plugin_slug ) ) {
782 return $this->get_learn_more_button_html( $plugin_slug, false, $css );
783 }
784
785 $is_installed = $this->is_plugin_installed( $plugin_slug );
786 $is_active = $this->is_plugin_activated( $plugin_slug );
787
788 if ( ! $is_installed ) {
789 return $this->get_install_button_html( $plugin_slug, $button_text, $css );
790 }
791
792 if ( ! $is_active ) {
793 return $this->get_activation_button_html( $plugin_slug, $button_text, $css );
794 }
795
796 return $this->get_setup_button_html( $plugin_slug, $button_text, $css );
797 }
798
799
800 /**
801 * Check if plugin has a learn more link.
802 *
803 * @since 1.8.1.6
804 *
805 * @param string $plugin_slug The plugin slug.
806 *
807 * @return boolean
808 */
809 public function is_plugin_learn_more( $plugin_slug = false ) {
810
811 if ( false === $plugin_slug ) {
812 return;
813 }
814
815 $plugins = $this->get_plugins( false );
816
817 if ( ! isset( $plugins[ $plugin_slug ] ) ) {
818 return;
819 }
820
821 $plugin = $plugins[ $plugin_slug ];
822
823 if ( ! $plugin || ! isset( $plugin['slug'] ) ) {
824 return;
825 }
826
827 $learn = ! empty( $plugin['gt_learn'] ) ? esc_url( $plugin['gt_learn'] ) : false;
828
829 if ( $learn ) {
830 return true;
831 }
832
833 return false;
834 }
835
836
837 /**
838 * Get the recommended plugins.
839 *
840 * @since 1.8.1
841 * @version 1.8.8
842 *
843 * @param boolean $return_json Whether to return the plugins as JSON or an array.
844 *
845 * @return array
846 */
847 public function get_plugins( $return_json = true ) {
848
849 if ( ! function_exists( 'get_plugins' ) ) {
850 require_once ABSPATH . 'wp-admin/includes/plugin.php';
851 }
852
853 $includes_path = charitable()->get_path( 'includes' );
854 require_once $includes_path . 'utilities/charitable-utility-functions.php';
855
856 $installed_plugins = get_plugins();
857
858 $plugins = array();
859
860 // Monsterinsights.
861 $plugins['monsterinsights'] = array(
862 'active' => function_exists( 'monsterinsights' ),
863 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/mi.png',
864 'title' => 'MonsterInsights',
865 'excerpt' => __( 'The leading WordPress analytics plugin that shows you how people find and use your website, so you can make data driven decisions to grow your business. Properly set up Google Analytics without writing code.', 'charitable' ),
866 'why' => __( 'Analytics plugins can help you determine how people are finding your campaigns, and which of your public campaigns are getting viewed the most.', 'charitable' ),
867 'what' => __( 'an analytics plugin', 'charitable' ),
868 'installed' => array_key_exists( 'google-analytics-for-wordpress/googleanalytics.php', $installed_plugins ) || array_key_exists( 'google-analytics-premium/googleanalytics-premium.php', $installed_plugins ),
869 'basename' => 'google-analytics-for-wordpress/googleanalytics.php',
870 'slug' => 'google-analytics-for-wordpress',
871 'settings' => admin_url( 'admin.php?page=monsterinsights-settings' ),
872 'setup' => admin_url( 'index.php?page=monsterinsights-onboarding' ),
873 'id' => 'mi',
874 'gt_section' => 'traffic',
875 );
876
877 // WPForms.
878 $plugins['wpforms-lite'] = array(
879 'active' => function_exists( 'wpforms' ),
880 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/wpforms.png',
881 'title' => 'WPForms',
882 'excerpt' => __( 'The best drag & drop WordPress form builder. Easily create beautiful contact forms, surveys, payment forms, and more with our 1000+ form templates. Trusted by over 6 million websites as the best forms plugin.', 'charitable' ),
883 'why' => __( 'Form plugins can help you get real feedback such as campaign recommendations or ideas for different payment options.', 'charitable' ),
884 'what' => __( 'a form plugin', 'charitable' ),
885 'installed' => array_key_exists( 'wpforms-lite/wpforms.php', $installed_plugins ),
886 'basename' => 'wpforms-lite/wpforms.php',
887 'slug' => 'wpforms-lite',
888 'settings' => admin_url( 'admin.php?page=wpforms-settings' ),
889 'setup' => admin_url( 'admin.php?page=wpforms-settings' ),
890 'id' => 'wpforms',
891 'gt_section' => 'engagement',
892 );
893
894 // AIOSEO.
895 $plugins['aioseo'] = array(
896 'active' => function_exists( 'aioseo' ),
897 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/all-in-one-seo.png',
898 'title' => 'AIOSEO',
899 'excerpt' => __( 'The original WordPress SEO plugin and toolkit that improves your website’s search rankings. Comes with all the SEO features like Local SEO, WooCommerce SEO, sitemaps, SEO optimizer, schema, and more.', 'charitable' ),
900 'why' => __( 'Using an SEO plugin helps you make sure your campaigns and causes are findable on the web.', 'charitable' ),
901 'what' => __( 'an SEO plugin', 'charitable' ),
902 'installed' => array_key_exists( 'all-in-one-seo-pack/all_in_one_seo_pack.php', $installed_plugins ),
903 'basename' => ( charitable_is_installed_aioseo_pro() ) ? 'all-in-one-seo-pack-pro/all_in_one_seo_pack.php' : 'all-in-one-seo-pack/all_in_one_seo_pack.php',
904 'slug' => 'all-in-one-seo-pack',
905 'settings' => admin_url( 'admin.php?page=aioseo' ),
906 'setup' => admin_url( 'admin.php?page=aioseo' ),
907 'id' => 'aioseo',
908 'gt_section' => 'traffic',
909 );
910
911 // OptinMonster.
912 $plugins['optinmonster'] = array(
913 'active' => class_exists( 'OMAPI' ),
914 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/om.png',
915 'title' => 'OptinMonster',
916 'excerpt' => __( 'Instantly get more subscribers, leads, and sales with the #1 conversion optimization toolkit. Create high converting popups, announcement bars, spin a wheel, and more with smart targeting and personalization.', 'charitable' ),
917 'why' => __( 'Marketing plugins that offer exit-intent technology, page targeting, and A/B testing can help you keep potential donors on your site.', 'charitable' ),
918 'what' => __( 'particular marketing plugins', 'charitable' ),
919 'installed' => array_key_exists( 'optinmonster/optin-monster-wp-api.php', $installed_plugins ),
920 'basename' => 'optinmonster/optin-monster-wp-api.php',
921 'slug' => 'optinmonster',
922 'settings' => admin_url( 'admin.php?page=optin-monster-dashboard' ),
923 'setup' => admin_url( 'admin.php?page=optin-monster-dashboard' ),
924 'id' => 'optinmonster',
925 'gt_section' => 'engagement',
926 );
927
928 // RafflePress.
929 $plugins['rafflepress'] = array(
930 'active' => defined( 'RAFFLEPRESS_VERSION' ),
931 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/rafflepress.png',
932 'title' => 'RafflePress',
933 'excerpt' => __( 'Turn your website visitors into brand ambassadors! Easily grow your email list, website traffic, and social media followers with the most powerful giveaways & contests plugin for WordPress.', 'charitable' ),
934 'why' => __( 'Offering giveaways and contests can help strengthen your overall cause and particular campaigns.', 'charitable' ),
935 'what' => __( 'particular marketing plugins', 'charitable' ),
936 'installed' => array_key_exists( 'rafflepress/rafflepress.php', $installed_plugins ),
937 'basename' => 'rafflepress/rafflepress.php',
938 'slug' => 'rafflepress',
939 'settings' => admin_url( 'admin.php?page=rafflepress_lite' ),
940 'setup' => admin_url( 'admin.php?page=rafflepress_lite' ),
941 'id' => 'rafflepress',
942 'gt_section' => 'traffic',
943 );
944
945 // SeedProd.
946 $plugins['coming-soon'] = array(
947 'active' => defined( 'SEEDPROD_VERSION' ),
948 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/seedprod.png',
949 'title' => 'SeedProd',
950 'excerpt' => __( 'Use the best drag-and-drop landing page builder for WordPress to instantly build coming soon pages, sales pages, opt-in pages, webinar pages, maintenance pages, and more. Includes 100+ free templates.', 'charitable' ),
951 'why' => __( 'Build landing pages for your general causes while showcasing testimonials form donors and campaign benefactors.', 'charitable' ),
952 'what' => __( 'a page builder plugin', 'charitable' ),
953 'installed' => array_key_exists( 'coming-soon/coming-soon.php', $installed_plugins ),
954 'basename' => 'coming-soon/coming-soon.php',
955 'slug' => 'coming-soon',
956 'settings' => admin_url( 'admin.php?page=seedprod_lite' ),
957 'setup' => admin_url( 'admin.php?page=seedprod_lite' ),
958 'id' => 'seedprod',
959 'gt_section' => 'revenue',
960 );
961
962 // WP Mail Smtp.
963 $plugins['wp-mail-smtp'] = array(
964 'active' => function_exists( 'wp_mail_smtp' ),
965 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/smtp.png',
966 'title' => 'WP Mail SMTP',
967 'excerpt' => __( 'Improve your WordPress email deliverability and make sure that your website emails reach user’s inbox with the #1 SMTP plugin for WordPress. Over 3 million websites use it to fix WordPress email issues.', 'charitable' ),
968 'why' => __( 'Sending reliable emails to donors after they have donated is vital, along with making sure admins get email notifications setup in Charitable.', 'charitable' ),
969 'what' => __( 'a SMTP / email plugin', 'charitable' ),
970 'installed' => array_key_exists( 'wp-mail-smtp/wp_mail_smtp.php', $installed_plugins ),
971 'basename' => 'wp-mail-smtp/wp_mail_smtp.php',
972 'slug' => 'wp-mail-smtp',
973 'settings' => admin_url( 'admin.php?page=wp-mail-smtp' ),
974 'setup' => admin_url( 'admin.php?page=wp-mail-smtp' ),
975 'id' => 'wpmailsmtp',
976 'gt_section' => 'engagement',
977 );
978
979 // EDD.
980 $plugins['easy-digital-downloads'] = array(
981 'active' => class_exists( 'Easy_Digital_Downloads' ),
982 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/edd.png',
983 'title' => 'Easy Digital Downloads',
984 'excerpt' => __( 'The best WordPress eCommerce plugin for selling digital downloads. Start selling eBooks, software, music, digital art, and more within minutes. Accept payments, manage subscriptions, advanced access control, and more.', 'charitable' ),
985 'installed' => array_key_exists( 'easy-digital-downloads/easy-digital-downloads.php', $installed_plugins ),
986 'basename' => 'easy-digital-downloads/easy-digital-downloads.php',
987 'slug' => 'easy-digital-downloads',
988 'setup' => admin_url( 'edit.php?post_type=download&page=edd-settings' ),
989 'settings' => admin_url( 'edit.php?post_type=download&page=edd-settings' ),
990 'id' => 'edd',
991 'gt_section' => 'revenue',
992 );
993
994 // PrettyLinks.
995 $plugins['pretty-link'] = array(
996 'active' => function_exists( 'prli_plugin_info' ),
997 'icon' => false,
998 'title' => 'Pretty Links',
999 'excerpt' => __( 'Automatically monetize your website content with affiliate links added automatically to your content.', 'charitable' ),
1000 'installed' => array_key_exists( 'pretty-link/pretty-link.php', $installed_plugins ),
1001 'basename' => 'pretty-link/pretty-link.php',
1002 'slug' => 'pretty-link',
1003 'setup' => admin_url( 'edit.php?post_type=pretty-link' ),
1004 'settomgs' => admin_url( 'edit.php?post_type=pretty-link' ),
1005 'id' => 'prettylinks',
1006 'gt_section' => 'revenue',
1007 );
1008
1009 // Smash Balloon (Instagram).
1010 $plugins['smash-balloon-instagram'] = array(
1011 'active' => defined( 'SBIVER' ),
1012 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/sb-instagram.png',
1013 'title' => 'Smash Balloon Instagram Feeds',
1014 'excerpt' => __( 'Easily display Instagram content on your WordPress site without writing any code. Comes with multiple templates, ability to show content from multiple accounts, hashtags, and more. Trusted by 1 million websites.', 'charitable' ),
1015 'installed' => array_key_exists( 'instagram-feed/instagram-feed.php', $installed_plugins ),
1016 'basename' => 'instagram-feed/instagram-feed.php',
1017 'slug' => 'instagram-feed',
1018 'setup' => admin_url( 'admin.php?page=sbi-settings' ),
1019 'settings' => admin_url( 'admin.php?page=sbi-settings' ),
1020 'id' => 'smashballoon',
1021 'gt_section' => 'engagement',
1022 );
1023
1024 // Smash Balloon (Facebook).
1025 $plugins['smash-balloon-facebook'] = array(
1026 'active' => defined( 'CFFVER' ),
1027 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/sb-facebook.png',
1028 'title' => 'Smash Balloon Facebook Feeds',
1029 'excerpt' => __( 'Easily display Facebook content on your WordPress site without writing any code. Comes with multiple templates, ability to embed albums, group content, reviews, live videos, comments, and reactions.', 'charitable' ),
1030 'installed' => array_key_exists( 'custom-facebook-feed/custom-facebook-feed.php', $installed_plugins ),
1031 'basename' => 'custom-facebook-feed/custom-facebook-feed.php',
1032 'slug' => 'custom-facebook-feed',
1033 'setup' => admin_url( 'admin.php?page=cff-setup' ),
1034 'settings' => admin_url( 'admin.php?page=cff-setup' ),
1035 'id' => 'smashballoon',
1036 'gt_section' => 'engagement',
1037 );
1038
1039 // Smash Balloon (YouTube).
1040 $plugins['smash-balloon-youtube'] = array(
1041 'active' => defined( 'SBYVER' ),
1042 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/sb-youtube.png',
1043 'title' => 'Smash Balloon YouTube Feeds',
1044 'excerpt' => __( 'Easily display YouTube videos on your WordPress site without writing any code. Comes with multiple layouts, ability to embed live streams, video filtering, ability to combine multiple channel videos, and more.', 'charitable' ),
1045 'installed' => array_key_exists( 'feeds-for-youtube/youtube-feed.php', $installed_plugins ),
1046 'basename' => 'feeds-for-youtube/youtube-feed.php',
1047 'slug' => 'feeds-for-youtube',
1048 'setup' => admin_url( 'admin.php?page=sby-feed-builder' ),
1049 'settings' => admin_url( 'admin.php?page=sby-feed-builder' ),
1050 );
1051
1052 // Smash Balloon (Twitter).
1053 $plugins['smash-balloon-twitter'] = array(
1054 'active' => defined( 'CTF_VERSION' ),
1055 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/sb-twitter.png',
1056 'title' => 'Smash Balloon Twitter Feeds',
1057 'excerpt' => __( 'Easily display Twitter content in WordPress without writing any code. Comes with multiple layouts, ability to combine multiple Twitter feeds, Twitter card support, tweet moderation, and more.', 'charitable' ),
1058 'installed' => array_key_exists( 'custom-twitter-feeds/custom-twitter-feed.php', $installed_plugins ),
1059 'basename' => 'custom-twitter-feeds/custom-twitter-feed.php',
1060 'slug' => 'custom-twitter-feeds',
1061 'setup' => admin_url( 'admin.php?page=ctf-feed-builder' ),
1062 'settings' => admin_url( 'admin.php?page=ctf-feed-builder' ),
1063 );
1064
1065 // TrustPulse.
1066 $plugins['trustpulse'] = array(
1067 'active' => defined( 'TRUSTPULSE_PLUGIN_VERSION' ),
1068 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/trustpulse.png',
1069 'title' => 'TrustPulse',
1070 'excerpt' => __( 'Boost your sales and conversions by up to 15% with real-time social proof notifications. TrustPulse helps you show live user activity and purchases to help convince other users to purchase.', 'charitable' ),
1071 'installed' => array_key_exists( 'trustpulse-api/trustpulse.php', $installed_plugins ),
1072 'basename' => 'trustpulse-api/trustpulse.php',
1073 'slug' => 'trustpulse-api',
1074 'setup' => admin_url( 'admin.php?page=trustpulse' ),
1075 'settings' => admin_url( 'admin.php?page=trustpulse' ),
1076 );
1077
1078 // SearchWP.
1079 $plugins['searchwp'] = array(
1080 'active' => defined( 'SEARCHWP_LIVE_SEARCH_VERSION' ),
1081 'icon' => false,
1082 'title' => 'SearchWP',
1083 'excerpt' => __( 'The most advanced WordPress search plugin. Customize your WordPress search algorithm, reorder search results, track search metrics, and everything you need to leverage search to grow your business.', 'charitable' ),
1084 'why' => __( 'Unlock better search results for your website. Perfect for any information or eCommerce store to help users find exactly what content and products they’re looking for.', 'charitable' ),
1085 'what' => __( 'a search plugin', 'charitable' ),
1086 'installed' => false,
1087 'basename' => false,
1088 'slug' => 'searchwp-live-ajax-search',
1089 'settings' => admin_url( 'admin.php?page=searchwp-live-search' ),
1090 'id' => 'searchwp',
1091 'gt_section' => 'revenue',
1092 'gt_learn' => 'https://www.wpcharitable.com/refer/searchwp?utm_source=charitableplugin&utm_medium=link&utm_campaign=CharitableGrowthTools&utm_content=' . charitable()->get_version(),
1093
1094 );
1095
1096 // AffiliateWP.
1097 $plugins['affiliatewp'] = array(
1098 'active' => class_exists( 'AffiliateWP_Requirements_Check' ),
1099 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/affiliate-wp.png',
1100 'title' => 'AffiliateWP',
1101 'excerpt' => __( 'The #1 affiliate management plugin for WordPress. Easily create an affiliate program for your eCommerce store or membership site within minutes and start growing your sales with the power of referral marketing.', 'charitable' ),
1102 'installed' => array_key_exists( 'affiliate-wp/affiliate-wp.php', $installed_plugins ),
1103 'basename' => 'affiliate-wp/affiliate-wp.php',
1104 'slug' => 'affiliate-wp',
1105 'setup' => admin_url(),
1106 'settings' => admin_url(),
1107 'redirect' => 'https://affiliatewp.com',
1108 );
1109
1110 // WP Simple Pay.
1111 $plugins['wpsimplepay'] = array(
1112 'active' => defined( 'SIMPLE_PAY_VERSION' ),
1113 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/wp-simple-pay.png',
1114 'title' => 'WP Simple Pay',
1115 'excerpt' => __( 'The #1 Stripe payments plugin for WordPress. Start accepting one-time and recurring payments on your WordPress site without setting up a shopping cart. No code required.', 'charitable' ),
1116 'installed' => array_key_exists( 'stripe/stripe-checkout.php', $installed_plugins ),
1117 'basename' => 'stripe/stripe-checkout.php',
1118 'slug' => 'stripe',
1119 'setup' => admin_url( 'edit.php?post_type=simple-pay&page=simpay_settings' ),
1120 'settings' => admin_url( 'edit.php?post_type=simple-pay&page=simpay_settings' ),
1121 );
1122
1123 // Sugar Calendar.
1124 $plugins['sugarcalendar'] = array(
1125 'active' => class_exists( 'Sugar_Calendar\\Requirements_Check' ),
1126 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/sugar-calendar.png',
1127 'title' => 'Sugar Calendar',
1128 'excerpt' => __( 'A simple & powerful event calendar plugin for WordPress that comes with all the event management features including payments, scheduling, timezones, ticketing, recurring events, and more.', 'charitable' ),
1129 'installed' => array_key_exists( 'sugar-calendar-lite/sugar-calendar-lite.php', $installed_plugins ),
1130 'basename' => 'sugar-calendar-lite/sugar-calendar-lite.php',
1131 'slug' => 'sugar-calendar-lite',
1132 'settings' => admin_url( 'admin.php?page=sugar-calendar' ),
1133 );
1134
1135 // WPCode.
1136 $plugins['wpcode'] = array(
1137 'active' => function_exists( 'WPCode' ),
1138 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/wpcode.png',
1139 'title' => 'WPCode',
1140 'excerpt' => __( 'Future proof your WordPress customizations with the most popular code snippet management plugin for WordPress. Trusted by over 1,500,000+ websites for easily adding code to WordPress right from the admin area.', 'charitable' ),
1141 'installed' => array_key_exists( 'insert-headers-and-footers/ihaf.php', $installed_plugins ),
1142 'basename' => 'insert-headers-and-footers/ihaf.php',
1143 'slug' => 'insert-headers-and-footers',
1144 'settings' => admin_url( 'admin.php?page=wpcode-settings' ),
1145 'setup' => admin_url( 'admin.php?page=wpcode-settings' ),
1146 );
1147
1148 // Duplicator.
1149 $plugins['duplicator'] = array(
1150 'active' => defined( 'DUPLICATOR_VERSION' ),
1151 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/duplicator.png',
1152 'title' => 'Duplicator',
1153 'excerpt' => __( 'Leading WordPress backup & site migration plugin. Over 1,500,000+ smart website owners use Duplicator to make reliable and secure WordPress backups to protect their websites. It also makes website migration really easy.', 'charitable' ),
1154 'installed' => array_key_exists( 'duplicator/duplicator.php', $installed_plugins ),
1155 'basename' => 'duplicator/duplicator.php',
1156 'slug' => 'duplicator',
1157 'settings' => admin_url( 'admin.php?page=duplicator-settings' ),
1158 );
1159
1160 // PushEngage.
1161 $plugins['pushengage'] = array(
1162 'active' => defined( 'PUSHENGAGE_VERSION' ),
1163 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/pushengage.png',
1164 'title' => 'PushEngage',
1165 'excerpt' => __( 'Connect with your visitors after they leave your website with the leading web push notification software. Over 10,000+ businesses worldwide use PushEngage to send 15 billion notifications each month.', 'charitable' ),
1166 'why' => __( 'Use push notifications to notify donors or potential donors that a campaign is about to end, or that a campaign has not reached it\'s goal yet.', 'charitable' ),
1167 'what' => __( 'particular marketing plugins', 'charitable' ),
1168 'installed' => array_key_exists( 'pushengage/main.php', $installed_plugins ),
1169 'basename' => 'pushengage/main.php',
1170 'slug' => 'pushengage',
1171 'setup' => admin_url( 'admin.php?page=pushengage#/settings/site-details' ),
1172 'settings' => admin_url( 'admin.php?page=pushengage#/settings/site-details' ),
1173 'id' => 'pushengage',
1174 'gt_section' => 'traffic',
1175 );
1176
1177 // Uncanny Automator.
1178 $plugins['uncanny-automator'] = array(
1179 'active' => function_exists( 'automator_get_recipe_id' ),
1180 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/uncanny-automator.png',
1181 'title' => 'Uncanny Automator',
1182 'excerpt' => __( 'Automate everything with the #1 no-code Automation tool for WordPress. Use data from donors, donation submissions, activities and anything else in your campaign.', 'charitable' ),
1183 'installed' => array_key_exists( 'uncanny-automator/uncanny-automator.php', $installed_plugins ),
1184 'basename' => 'uncanny-automator/uncanny-automator.php',
1185 'slug' => 'uncanny-automator',
1186 'setup_complete' => (bool) get_option( 'automator_reporting', false ),
1187 'setup' => admin_url( 'edit.php?post_type=uo-recipe&page=uncanny-automator-setup-wizard' ),
1188 'settings' => admin_url( 'edit.php?post_type=uo-recipe&page=uncanny-automator-setup-wizard' ),
1189 'id' => 'uncanny-automator',
1190 'gt_section' => 'engagement',
1191 );
1192
1193 // Envira Gallery.
1194 $plugins['envira-gallery'] = array(
1195 'active' => class_exists( 'Envira_Gallery_Lite' ),
1196 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/envira-gallery.png',
1197 'title' => 'Envira Gallery Lite',
1198 'excerpt' => __( 'Add a photo gallery to your campaign pages with this fast and powerful gallery plugin.', 'charitable' ),
1199 'why' => __( 'Showing photos in an attractive gallery will add more credentiality to your campaigns.', 'charitable' ),
1200 'installed' => array_key_exists( 'envira-gallery-lite/envira-gallery-lite.php', $installed_plugins ),
1201 'basename' => 'envira-gallery-lite/envira-gallery-lite.php',
1202 'slug' => 'envira-gallery-lite',
1203 'setup' => admin_url( 'edit.php?post_type=envira&page=envira-gallery-lite-get-started' ),
1204 'id' => 'envira',
1205 'gt_section' => 'engagement',
1206 );
1207
1208 // Constant Contact.
1209 $plugins['constant-contact'] = array(
1210 'active' => class_exists( 'ConstantContact' ), // todo: update.
1211 'icon' => charitable()->get_path( 'directory', false ) . 'assets/images/plugins/third-party/constant-contact.png',
1212 'title' => 'Constant Contact',
1213 'excerpt' => __( 'Create amazing email marketing campaigns with drag and drop simplicity. <span>Exclusive Offer: Save 20%.</span>', 'charitable' ),
1214 'why' => false,
1215 'slug' => 'constantcontact',
1216 'setup' => false,
1217 'id' => 'constantcontact',
1218 'gt_section' => 'traffic',
1219 'gt_learn' => 'https://www.wpcharitable.com/refer/constant-contact/?utm_source=charitableplugin&utm_medium=link&utm_campaign=CharitableGrowthTools&utm_content=' . charitable()->get_version(),
1220 );
1221
1222 // SEMRUSH.
1223 $plugins['semrush'] = array(
1224 'active' => class_exists( 'SEMRUSH' ), // todo: update.
1225 'icon' => false,
1226 'title' => 'SEMRUSH',
1227 'excerpt' => __( 'Perform SEO and content marketing research, track keywords, and much more. <span>Special Offer: First 14 Days Free.</span>', 'charitable' ),
1228 'why' => false,
1229 'slug' => 'semrush',
1230 'setup' => false,
1231 'id' => 'semrush',
1232 'gt_section' => 'traffic',
1233 'gt_learn' => 'https://www.wpcharitable.com/refer/semrush?utm_source=charitableplugin&utm_medium=link&utm_campaign=CharitableGrowthTools&utm_content=' . charitable()->get_version(),
1234 );
1235
1236 // MemberPress.
1237 $plugins['memberpress'] = array(
1238 'active' => false,
1239 'icon' => false,
1240 'title' => 'MemberPress',
1241 'excerpt' => __( 'Create a membership website.', 'charitable' ),
1242 'installed' => false,
1243 'basename' => false,
1244 'why' => __( 'Creating a community can help boost returning donations. You can offer exclusive content and discussion, especially for donors or campaign creators.', 'charitable' ),
1245 'what' => __( 'a membership plugin', 'charitable' ),
1246 'slug' => 'memberpress',
1247 'setup' => false,
1248 'id' => 'memberpress',
1249 'gt_section' => 'revenue',
1250 'gt_learn' => 'https://www.wpcharitable.com/refer/memberpress/?utm_source=charitableplugin&utm_medium=link&utm_campaign=CharitableGrowthTools&utm_content=' . charitable()->get_version(),
1251 );
1252
1253 // Easy Affiliate.
1254 $plugins['easy-affiliate'] = array(
1255 'active' => false,
1256 'icon' => false,
1257 'title' => 'Easy Affiliate',
1258 'excerpt' => __( 'Launch, grow, and manage an affiliate program, all right from your WordPress dashboard.', 'charitable' ),
1259 'installed' => false,
1260 'basename' => false,
1261 'slug' => 'easy-affiliate',
1262 'setup' => false,
1263 'id' => 'easyaffiliate',
1264 'gt_section' => 'revenue',
1265 'gt_learn' => 'https://www.wpcharitable.com/refer/easy-affiliate/?utm_source=charitableplugin&utm_medium=link&utm_campaign=CharitableGrowthTools&utm_content=' . charitable()->get_version(),
1266 );
1267
1268 // Formidable Forms.
1269 $plugins['formidable'] = array(
1270 'active' => function_exists( 'load_formidable_forms' ),
1271 'icon' => false,
1272 'title' => 'Formidable Forms',
1273 'excerpt' => __( 'Formidable Forms is the best WordPress forms plugin. Over 300,000 professionals use our WordPress form builder to create contact forms, surveys, calculators, and other WP forms.', 'charitable' ),
1274 'why' => __( 'Form plugins can help you get real feedback such as campaign recommendations or ideas for different payment options.', 'charitable' ),
1275 'what' => __( 'a form plugin', 'charitable' ),
1276 'installed' => array_key_exists( 'formidable/formidable.php', $installed_plugins ),
1277 'basename' => 'formidable/formidable.php',
1278 'slug' => 'formidable',
1279 'settings' => admin_url( 'admin.php?page=formidable-dashboard' ),
1280 'setup' => admin_url( 'admin.php?page=formidable-dashboard' ),
1281 'id' => 'formidableforms',
1282 'gt_section' => 'engagement',
1283 );
1284
1285 // WPConsent.
1286 $plugins['wpconsent'] = array(
1287 'active' => function_exists( 'wpconsent' ),
1288 'icon' => false,
1289 'title' => 'WPConsent',
1290 'excerpt' => __( 'WPConsent is the best privacy compliance plugin for WordPress. It helps you comply with GDPR, CCPA, and other privacy regulations.', 'charitable' ),
1291 'why' => __( 'Privacy compliance plugins can help you comply with GDPR, CCPA, and other privacy regulations.', 'charitable' ),
1292 'what' => __( 'a privacy compliance plugin', 'charitable' ),
1293 'installed' => array_key_exists( 'wpconsent-cookies-banner-privacy-suite/wpconsent.php', $installed_plugins ),
1294 'basename' => 'wpconsent-cookies-banner-privacy-suite/wpconsent.php',
1295 'slug' => 'wpconsent-cookies-banner-privacy-suite',
1296 'settings' => admin_url( 'admin.php?page=wpconsent-cookies' ),
1297 'setup' => admin_url( 'admin.php?page=wpconsent-cookies' ),
1298 'id' => 'wpconsent',
1299 'gt_section' => 'privacy',
1300 'gt_learn' => 'https://wordpress.org/plugins/wpconsent-cookies-banner-privacy-suite/',
1301 );
1302
1303 $plugins['guide-coming-soon'] = array(
1304 'title' => __( 'Dedicated guides and resources will be coming soon.', 'charitable' ),
1305 'id' => 'guide',
1306 'gt_section' => 'guides',
1307 'coming_soon' => true,
1308 );
1309
1310 if ( $return_json ) {
1311 wp_send_json( $plugins );
1312 } else {
1313 return $plugins;
1314 }
1315 }
1316
1317 /**
1318 * Get the recommended plugins.
1319 *
1320 * @since 1.8.1
1321 *
1322 * @param string $recommendation_type The type of recommendation to get.
1323 * @param int $limit The number of recommendations to get.
1324 *
1325 * @return array
1326 */
1327 public function get_recommendations( $recommendation_type = 'campaign', $limit = 3 ) {
1328
1329 $recommended_addons = $this->get_recommended_addons( $recommendation_type, $limit );
1330 $recommended_partners = $this->get_recommended_partners( $recommendation_type, $limit );
1331
1332 // merge the two arrays.
1333 $recommended = array_merge( $recommended_addons, $recommended_partners );
1334
1335 if ( count( $recommended_addons ) + count( $recommended_partners ) > $limit ) {
1336 $recommended = array_merge( $recommended_addons, $recommended_partners );
1337
1338 if ( ! empty( $recommended ) ) {
1339 // randomly remove elements from the array until the total count of the array equals the limit.
1340 $recommended_count = count( $recommended );
1341 while ( $recommended_count > $limit ) {
1342 $random_key = array_rand( $recommended );
1343 unset( $recommended[ $random_key ] );
1344 $recommended_count = count( $recommended );
1345 }
1346 }
1347 }
1348
1349 return $recommended;
1350 }
1351
1352
1353 /**
1354 * Get the recommended partners / third party items.
1355 *
1356 * @since 1.8.1.5
1357 *
1358 * @param string $recommendation_type The type of recommendation to get.
1359 * @param int $limit The number of recommendations to get.
1360 *
1361 * @return array
1362 */
1363 public function get_recommended_partners( $recommendation_type = 'campaign', $limit = 3 ) {
1364 /*
1365 Recommend at least one Charitable addon.
1366
1367 Rules:
1368 - Must be on the list of preferred partners.
1369 - Must not be installed.
1370 - Must not be dismissed.
1371
1372 */
1373
1374 $partner_list = $this->get_plugins( false );
1375
1376 $preferred_partners = apply_filters(
1377 'charitable_recommended_partners_ ' . $recommendation_type, // @codingStandardsIgnoreLine
1378 array(
1379 'charitable',
1380 'optinmonster',
1381 'wpforms-lite',
1382 )
1383 );
1384
1385 // Remove any installed plugins from the preferred list.
1386 $installed_plugins = get_plugins();
1387
1388 foreach ( $installed_plugins as $file => $plugin ) {
1389 // Get the first part of the string before the /.
1390 $plugin_slug = explode( '/', $file )[0];
1391
1392 if ( in_array( $plugin_slug, $preferred_partners, true ) ) {
1393 unset( $preferred_partners[ array_search( $plugin_slug, $preferred_partners, true ) ] );
1394 }
1395
1396 if ( ! empty( $preferred_partners ) ) {
1397 foreach ( $partner_list as $partner_list_slug => $partner_list_info ) {
1398 if ( ! empty( $partner_list_info ) && isset( $partner_list_info['slug'] ) && $partner_list_info['slug'] === $plugin_slug ) {
1399 unset( $preferred_partners[ array_search( $plugin_slug, $preferred_partners, true ) ] );
1400 }
1401 }
1402 }
1403 }
1404 // Remove any plugins already dismissed from the logged in user.
1405 $dismissed_partners = (array) get_user_meta( get_current_user_id(), 'charitable_dismissed_partners', true );
1406 $dismissed_partners = array_filter( $dismissed_partners );
1407
1408 if ( ! empty( $dismissed_partners ) ) {
1409 foreach ( $dismissed_partners as $dismissed_partner ) {
1410 if ( '' === $dismissed_partner ) {
1411 continue;
1412 }
1413 if ( in_array( $dismissed_partner, $dismissed_partners, true ) ) {
1414 unset( $preferred_partners[ array_search( $dismissed_partner, $preferred_partners, true ) ] );
1415 }
1416 }
1417 }
1418
1419 // Limit the number of addons to return.
1420 $preferred_partners = array_slice( $preferred_partners, 0, $limit );
1421
1422 // For each remaining item in $preferred_partners, get the plugin details from $partner_list.
1423 foreach ( $preferred_partners as $key => $partner ) {
1424 $preferred_partners[ $partner ] = ! empty( $partner_list[ $partner ] ) ? $partner_list[ $partner ] : array();
1425 $preferred_partners[ $partner ]['type'] = 'partner';
1426 unset( $preferred_partners[ $key ] );
1427 }
1428
1429 return $preferred_partners;
1430 }
1431
1432 /**
1433 * Get the recommended addons.
1434 *
1435 * @since 1.8.1.5
1436 *
1437 * @param string $recommendation_type The type of recommendation to get.
1438 * @param int $limit The number of recommendations to get.
1439 *
1440 * @return array
1441 */
1442 public function get_recommended_addons( $recommendation_type = 'campaign', $limit = 3 ) {
1443 /*
1444 Recommend at least one Charitable addon.
1445
1446 Rules:
1447 - Must be a Charitable addon.
1448 - Must not be installed.
1449 - Must not be dismissed.
1450
1451 */
1452
1453 $preferred_addons = apply_filters(
1454 'charitable_recommended_addons_ ' . $recommendation_type, // @codingStandardsIgnoreLine
1455 array(
1456 'charitable-recurring',
1457 'charitable-ambassadors',
1458 'charitable-gift-aid',
1459 'charitable-anonymous-donations',
1460 'charitable-fee-relief',
1461 )
1462 );
1463
1464 // Remove any installed Charitable addons from the preferred list.
1465 $installed_plugins = get_plugins();
1466
1467 foreach ( $installed_plugins as $file => $plugin ) {
1468 // Get the first part of the string before the /.
1469 $plugin_slug = explode( '/', $file )[0];
1470
1471 if ( in_array( $plugin_slug, $preferred_addons, true ) ) {
1472 unset( $preferred_addons[ array_search( $plugin_slug, $preferred_addons, true ) ] );
1473 }
1474 }
1475
1476 // Remove any addons already dismissed from the logged in user.
1477 $dismissed_addons = (array) get_user_meta( get_current_user_id(), 'charitable_dismissed_addons', true );
1478 $dismissed_addons = array_filter( $dismissed_addons );
1479
1480 if ( ! empty( $dismissed_addons ) ) {
1481 foreach ( $dismissed_addons as $dismissed_addon ) {
1482 if ( in_array( $dismissed_addon, $preferred_addons, true ) ) {
1483 unset( $preferred_addons[ array_search( $dismissed_addon, $preferred_addons, true ) ] );
1484 }
1485 }
1486 }
1487
1488 // Limit the number of addons to return.
1489 $preferred_addons_to_compare = array_slice( $preferred_addons, 0, $limit );
1490
1491 // check and see if the slug refers to a Charitable addon first.
1492 $addons = get_transient( '_charitable_addons' ); // @codingStandardsIgnoreLine - testing.
1493
1494 // Get addons data from transient or perform API query if no transient.
1495 if ( false === $addons ) {
1496 $addons = charitable_get_addons_data_from_server();
1497 }
1498
1499 $preferred_addons = array();
1500
1501 if ( ! empty( $addons ) ) {
1502
1503 foreach ( $addons as $addon ) {
1504
1505 if ( ! isset( $addon['slug'] ) || empty( $addon['slug'] ) ) {
1506 continue;
1507 }
1508
1509 if ( in_array( $addon['slug'], $preferred_addons_to_compare, true ) ) {
1510
1511 $sections = ! empty( $addon['sections'] ) ? unserialize( $addon['sections'] ) : array();
1512
1513 $preferred_addons[ $addon['slug'] ]['icon'] = charitable()->get_path( 'directory', false ) . 'assets/images/plugins/charitable/' . $addon['slug'] . '.png';
1514 $preferred_addons[ $addon['slug'] ]['title'] = trim( str_replace( 'Charitable', '', $addon['name'] ) );
1515 $preferred_addons[ $addon['slug'] ]['sections'] = array();
1516 $preferred_addons[ $addon['slug'] ]['description'] = isset( $sections['description'] ) ? wp_strip_all_tags( $sections['description'] ) : '';
1517 $preferred_addons[ $addon['slug'] ]['type'] = 'addon';
1518
1519 }
1520 }
1521
1522 }
1523
1524 return $preferred_addons;
1525 }
1526
1527 /**
1528 * Get a single plugin.
1529 *
1530 * @since 1.8.1.5
1531 *
1532 * @param string $slug The plugin slug.
1533 *
1534 * @return array|null
1535 */
1536 public function get_plugin( $slug ) {
1537 $plugins = $this->get_plugins( false );
1538
1539 if ( ! isset( $plugins[ $slug ] ) ) {
1540 return;
1541 }
1542
1543 return $plugins[ $slug ];
1544 }
1545
1546 /**
1547 * Returns and/or create the single instance of this class.
1548 *
1549 * @since 1.8.1
1550 *
1551 * @return Charitable_Admin_Plugins_Third_Party
1552 */
1553 public static function get_instance() {
1554 if ( is_null( self::$instance ) ) {
1555 self::$instance = new self();
1556 }
1557
1558 return self::$instance;
1559 }
1560 }
1561
1562 endif;
1563