PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 6.2.2
MainWP Dashboard: Self-hosted WordPress Management for Agencies v6.2.2
6.2.3 6.2.2 6.2.1 6.2 6.1.8 6.1.7 6.1.6 6.1.5 6.1.4 6.1.3 6.1.2 6.1.1 6.1 6.0.12 6.0.11 4.6.0.1 5.0 5.0.1 5.0.2 5.0.3 5.0.3.1 5.0.3.2 5.1 5.1.1 5.2 All 156 releases
← All changes | pages/page-mainwp-extensions.php +803 -698 5.0 → 6.2.2 View file →
@@ -6,809 +6,914 @@
6 6 */
7 7
8 8 namespace MainWP\Dashboard;
9 9
10 +// Exit if accessed directly.
11 +if ( ! defined( 'ABSPATH' ) ) {
12 + exit;
13 +}
14 +
10 15 /**
11 16 * Class MainWP_Extensions
12 17 */
13 -class MainWP_Extensions {
18 +class MainWP_Extensions { // phpcs:ignore Generic.Classes.OpeningBraceSameLine.ContentAfterBrace -- NOSONAR.
14 19
15 - /**
16 - * Method get_class_name()
17 - *
18 - * Get Class Name.
19 - *
20 - * @return object Class name.
21 - */
22 - public static function get_class_name() {
23 - return __CLASS__;
24 - }
20 + /**
21 + * Method get_class_name()
22 + *
23 + * Get Class Name.
24 + *
25 + * @return object Class name.
26 + */
27 + public static function get_class_name() {
28 + return __CLASS__;
29 + }
25 30
26 - /**
27 - * Instantiate action hooks.
28 - *
29 - * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::get_class_name()
30 - */
31 - public static function init() {
32 - /**
33 - * This hook allows you to render the Extensions page header via the 'mainwp-pageheader-extensions' action.
34 - *
35 - * @link http://codex.mainwp.com/#mainwp-pageheader-extensions
36 - *
37 - * @see \MainWP_Extensions::render_header
38 - */
39 - add_action( 'mainwp-pageheader-extensions', array( self::get_class_name(), 'render_header' ) ); // @deprecated Use 'mainwp_pageheader_extensions' instead.
40 - add_action( 'mainwp_pageheader_extensions', array( self::get_class_name(), 'render_header' ) );
31 + /**
32 + * Instantiate action hooks.
33 + *
34 + * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::get_class_name()
35 + */
36 + public static function init() {
37 + /**
38 + * This hook allows you to render the Extensions page header via the 'mainwp-pageheader-extensions' action.
39 + *
40 + * @link http://codex.mainwp.com/#mainwp-pageheader-extensions
41 + *
42 + * @see \MainWP_Extensions::render_header
43 + */
44 + add_action( 'mainwp-pageheader-extensions', array( static::get_class_name(), 'render_header' ) ); // @deprecated Use 'mainwp_pageheader_extensions' instead.
45 + add_action( 'mainwp_pageheader_extensions', array( static::get_class_name(), 'render_header' ) );
41 46
42 - /**
43 - * This hook allows you to render the Extensions page footer via the 'mainwp-pagefooter-extensions' action.
44 - *
45 - * @link http://codex.mainwp.com/#mainwp-pagefooter-extensions
46 - *
47 - * @see \MainWP_Extensions::render_footer
48 - */
49 - add_action( 'mainwp-pagefooter-extensions', array( self::get_class_name(), 'render_footer' ) ); // @deprecated Use 'mainwp_pagefooter_extensions' instead.
50 - add_action( 'mainwp_pagefooter_extensions', array( self::get_class_name(), 'render_footer' ) );
47 + /**
48 + * This hook allows you to render the Extensions page footer via the 'mainwp-pagefooter-extensions' action.
49 + *
50 + * @link http://codex.mainwp.com/#mainwp-pagefooter-extensions
51 + *
52 + * @see \MainWP_Extensions::render_footer
53 + */
54 + add_action( 'mainwp-pagefooter-extensions', array( static::get_class_name(), 'render_footer' ) ); // @deprecated Use 'mainwp_pagefooter_extensions' instead.
55 + add_action( 'mainwp_pagefooter_extensions', array( static::get_class_name(), 'render_footer' ) );
51 56
52 - add_action( 'mainwp_help_sidebar_content', array( self::get_class_name(), 'mainwp_help_content' ) );
57 + add_action( 'mainwp_help_sidebar_content', array( static::get_class_name(), 'mainwp_help_content' ) );
53 58
54 - add_filter( 'mainwp-extensions-apigeneratepassword', array( MainWP_Extensions_Handler::get_class_name(), 'gen_api_password' ), 10, 3 );
55 - add_filter( 'mainwp_extensions_apigeneratepassword', array( MainWP_Extensions_Handler::get_class_name(), 'gen_api_password' ), 10, 3 );
56 - }
59 + add_filter( 'mainwp-extensions-apigeneratepassword', array( MainWP_Extensions_Handler::get_class_name(), 'gen_api_password' ), 10, 3 );
60 + add_filter( 'mainwp_extensions_apigeneratepassword', array( MainWP_Extensions_Handler::get_class_name(), 'gen_api_password' ), 10, 3 );
61 + }
57 62
58 - /**
59 - * Method init_menu()
60 - *
61 - * Instantiate Extensions Menu.
62 - *
63 - * @uses \MainWP\Dashboard\MainWP_Api_Manager::get_activation_info()
64 - * @uses \MainWP\Dashboard\MainWP_Extensions_View::init_menu()
65 - * @uses \MainWP\Dashboard\MainWP_Menu::is_disable_menu_item()
66 - * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::polish_ext_name()
67 - * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::added_on_menu()
68 - * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::get_extensions()
69 - * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
70 - */
71 - public static function init_menu() { // phpcs:ignore -- complex function. Current complexity is the only way to achieve desired results, pull request solutions appreciated.
72 - if ( ! MainWP_Menu::is_disable_menu_item( 2, 'Extensions' ) ) {
73 - MainWP_Extensions_View::init_menu();
74 - }
63 + /**
64 + * Method init_menu()
65 + *
66 + * Instantiate Extensions Menu.
67 + *
68 + * @uses \MainWP\Dashboard\MainWP_Api_Manager::get_activation_info()
69 + * @uses \MainWP\Dashboard\MainWP_Extensions_View::init_menu()
70 + * @uses \MainWP\Dashboard\MainWP_Menu::is_disable_menu_item()
71 + * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::polish_ext_name()
72 + * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::added_on_menu()
73 + * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::get_extensions()
74 + * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
75 + */
76 + public static function init_menu() { // phpcs:ignore -- NOSONAR - complex function. Current complexity is the only way to achieve desired results, pull request solutions appreciated.
77 + if ( ! MainWP_Menu::is_disable_menu_item( 2, 'Extensions' ) ) {
78 + MainWP_Extensions_View::init_menu();
79 + }
75 80
76 - $save_extensions = array();
81 + $save_extensions = array();
77 82
78 - /**
79 - * Get extensions
80 - *
81 - * Adds extension to MainWP system.
82 - *
83 - * @since 4.1
84 - */
85 - $init_extensions = array();
86 - $init_extensions = apply_filters_deprecated( 'mainwp-getextensions', array( $init_extensions ), '4.0.7.2', 'mainwp_getextensions' );
87 - $init_extensions = apply_filters( 'mainwp_getextensions', $init_extensions );
83 + /**
84 + * Get extensions
85 + *
86 + * Adds extension to MainWP system.
87 + *
88 + * @since 4.1
89 + */
90 + $init_extensions = array();
91 + $init_extensions = apply_filters_deprecated( 'mainwp-getextensions', array( $init_extensions ), '4.0.7.2', 'mainwp_getextensions' ); // NOSONAR - not IP.
92 + $init_extensions = apply_filters( 'mainwp_getextensions', $init_extensions );
88 93
89 - $all_available_extensions = MainWP_Extensions_View::get_available_extensions( 'all' );
94 + $all_available_extensions = MainWP_Extensions_View::get_available_extensions( 'all' );
90 95
91 - $activations_cached = get_option( 'mainwp_extensions_all_activation_cached', array() );
96 + $activations_cached = get_option( 'mainwp_extensions_all_activation_cached', array() );
92 97
93 - if ( ! is_array( $activations_cached ) ) {
94 - $activations_cached = array();
95 - }
98 + if ( ! is_array( $activations_cached ) ) {
99 + $activations_cached = array();
100 + }
96 101
97 - $is_cached = ! empty( $activations_cached ) ? true : false;
102 + $is_cached = ! empty( $activations_cached ) ? true : false;
98 103
99 - $extraHeaders = array(
100 - 'IconURI' => 'Icon URI',
101 - 'SupportForumURI' => 'Support Forum URI',
102 - 'DocumentationURI' => 'Documentation URI',
103 - );
104 + $extraHeaders = array(
105 + 'IconURI' => 'Icon URI',
106 + 'SupportForumURI' => 'Support Forum URI',
107 + 'DocumentationURI' => 'Documentation URI',
108 + );
104 109
105 - $extsPages = array();
110 + $extsPages = array();
106 111
107 - $compatible_v4_checks = array(
108 - 'advanced-uptime-monitor-extension/advanced-uptime-monitor-extension.php',
109 - 'mainwp-article-uploader-extension/mainwp-article-uploader-extension.php',
110 - 'mainwp-backwpup-extension/mainwp-backwpup-extension.php',
111 - 'boilerplate-extension/boilerplate-extension.php',
112 - 'mainwp-branding-extension/mainwp-branding-extension.php',
113 - 'mainwp-bulk-settings-manager/mainwp-bulk-settings-manager.php',
114 - 'mainwp-clean-and-lock-extension/mainwp-clean-and-lock-extension.php',
115 - 'mainwp-client-reports-extension/mainwp-client-reports-extension.php',
116 - 'mainwp-clone-extension/mainwp-clone-extension.php',
117 - 'mainwp-code-snippets-extension/mainwp-code-snippets-extension.php',
118 - 'mainwp-comments-extension/mainwp-comments-extension.php',
119 - 'mainwp-favorites-extension/mainwp-favorites-extension.php',
120 - 'mainwp-file-uploader-extension/mainwp-file-uploader-extension.php',
121 - 'mainwp-google-analytics-extension/mainwp-google-analytics-extension.php',
122 - 'mainwp-maintenance-extension/mainwp-maintenance-extension.php',
123 - 'mainwp-piwik-extension/mainwp-piwik-extension.php',
124 - 'mainwp-post-dripper-extension/mainwp-post-dripper-extension.php',
125 - 'mainwp-rocket-extension/mainwp-rocket-extension.php',
126 - 'mainwp-sucuri-extension/mainwp-sucuri-extension.php',
127 - 'mainwp-team-control/mainwp-team-control.php',
128 - 'mainwp-updraftplus-extension/mainwp-updraftplus-extension.php',
129 - 'mainwp-url-extractor-extension/mainwp-url-extractor-extension.php',
130 - 'mainwp-woocommerce-shortcuts-extension/mainwp-woocommerce-shortcuts-extension.php',
131 - 'mainwp-woocommerce-status-extension/mainwp-woocommerce-status-extension.php',
132 - 'mainwp-wordfence-extension/mainwp-wordfence-extension.php',
133 - 'wordpress-seo-extension/wordpress-seo-extension.php',
134 - 'mainwp-page-speed-extension/mainwp-page-speed-extension.php',
135 - 'mainwp-ithemes-security-extension/mainwp-ithemes-security-extension.php',
136 - 'mainwp-post-plus-extension/mainwp-post-plus-extension.php',
137 - 'mainwp-staging-extension/mainwp-staging-extension.php',
138 - 'mainwp-custom-post-types/mainwp-custom-post-types.php',
139 - 'mainwp-buddy-extension/mainwp-buddy-extension.php',
140 - 'mainwp-vulnerability-checker-extension/mainwp-vulnerability-checker-extension.php',
141 - 'mainwp-timecapsule-extension/mainwp-timecapsule-extension.php',
142 - 'activity-log-mainwp/activity-log-mainwp.php',
143 - );
144 - include_once ABSPATH . '/wp-admin/includes/plugin.php';
112 + $compatible_v4_checks = array(
113 + 'advanced-uptime-monitor-extension/advanced-uptime-monitor-extension.php',
114 + 'mainwp-article-uploader-extension/mainwp-article-uploader-extension.php',
115 + 'mainwp-backwpup-extension/mainwp-backwpup-extension.php',
116 + 'boilerplate-extension/boilerplate-extension.php',
117 + 'mainwp-branding-extension/mainwp-branding-extension.php',
118 + 'mainwp-bulk-settings-manager/mainwp-bulk-settings-manager.php',
119 + 'mainwp-clean-and-lock-extension/mainwp-clean-and-lock-extension.php',
120 + 'mainwp-client-reports-extension/mainwp-client-reports-extension.php',
121 + 'mainwp-clone-extension/mainwp-clone-extension.php',
122 + 'mainwp-code-snippets-extension/mainwp-code-snippets-extension.php',
123 + 'mainwp-comments-extension/mainwp-comments-extension.php',
124 + 'mainwp-favorites-extension/mainwp-favorites-extension.php',
125 + 'mainwp-file-uploader-extension/mainwp-file-uploader-extension.php',
126 + 'mainwp-google-analytics-extension/mainwp-google-analytics-extension.php',
127 + 'mainwp-maintenance-extension/mainwp-maintenance-extension.php',
128 + 'mainwp-piwik-extension/mainwp-piwik-extension.php',
129 + 'mainwp-post-dripper-extension/mainwp-post-dripper-extension.php',
130 + 'mainwp-rocket-extension/mainwp-rocket-extension.php',
131 + 'mainwp-sucuri-extension/mainwp-sucuri-extension.php',
132 + 'mainwp-team-control/mainwp-team-control.php',
133 + 'mainwp-updraftplus-extension/mainwp-updraftplus-extension.php',
134 + 'mainwp-url-extractor-extension/mainwp-url-extractor-extension.php',
135 + 'mainwp-woocommerce-shortcuts-extension/mainwp-woocommerce-shortcuts-extension.php',
136 + 'mainwp-woocommerce-status-extension/mainwp-woocommerce-status-extension.php',
137 + 'mainwp-wordfence-extension/mainwp-wordfence-extension.php',
138 + 'wordpress-seo-extension/wordpress-seo-extension.php',
139 + 'mainwp-page-speed-extension/mainwp-page-speed-extension.php',
140 + 'mainwp-ithemes-security-extension/mainwp-ithemes-security-extension.php',
141 + 'mainwp-post-plus-extension/mainwp-post-plus-extension.php',
142 + 'mainwp-staging-extension/mainwp-staging-extension.php',
143 + 'mainwp-custom-post-types/mainwp-custom-post-types.php',
144 + 'mainwp-buddy-extension/mainwp-buddy-extension.php',
145 + 'mainwp-vulnerability-checker-extension/mainwp-vulnerability-checker-extension.php',
146 + 'mainwp-timecapsule-extension/mainwp-timecapsule-extension.php',
147 + 'activity-log-mainwp/activity-log-mainwp.php',
148 + );
149 + include_once ABSPATH . '/wp-admin/includes/plugin.php'; // NOSONAR - WP compatible.
145 150
146 - $deactivated_imcompatible = array();
147 - foreach ( $init_extensions as $extension ) {
148 - $slug = plugin_basename( $extension['plugin'] );
149 - $plugin_data = get_plugin_data( $extension['plugin'], true, false );
150 - $file_data = get_file_data( $extension['plugin'], $extraHeaders );
151 + $deactivated_imcompatible = array();
152 + foreach ( $init_extensions as $extension ) {
153 + $slug = plugin_basename( $extension['plugin'] );
154 + $plugin_data = get_plugin_data( $extension['plugin'], true, false );
155 + $file_data = get_file_data( $extension['plugin'], $extraHeaders );
151 156
152 - if ( ! isset( $plugin_data['Name'] ) || ( '' === $plugin_data['Name'] ) ) {
153 - continue;
154 - }
157 + if ( ! isset( $plugin_data['Name'] ) || ( '' === $plugin_data['Name'] ) ) {
158 + continue;
159 + }
155 160
156 - if ( in_array( $slug, $compatible_v4_checks ) ) {
157 - $check_minver = '3.99999';
158 - if ( 'advanced-uptime-monitor-extension/advanced-uptime-monitor-extension.php' === $slug ) {
159 - $check_minver = '4.6.2';
160 - } elseif ( 'activity-log-mainwp/activity-log-mainwp.php' === $slug ) {
161 - $check_minver = '1.0.5';
162 - }
161 + if ( in_array( $slug, $compatible_v4_checks ) ) {
162 + $check_minver = '3.99999';
163 + if ( 'advanced-uptime-monitor-extension/advanced-uptime-monitor-extension.php' === $slug ) {
164 + $check_minver = '4.6.2';
165 + } elseif ( 'activity-log-mainwp/activity-log-mainwp.php' === $slug ) {
166 + $check_minver = '1.0.5';
167 + }
163 168
164 - if ( isset( $plugin_data['Version'] ) && version_compare( $plugin_data['Version'], $check_minver, '<' ) ) {
165 - $deactivated_imcompatible[] = $plugin_data['Name'];
166 - deactivate_plugins( $slug, true );
167 - continue;
168 - }
169 - }
169 + if ( isset( $plugin_data['Version'] ) && version_compare( $plugin_data['Version'], $check_minver, '<' ) ) {
170 + $deactivated_imcompatible[] = $plugin_data['Name'];
171 + deactivate_plugins( $slug, true );
172 + continue;
173 + }
174 + }
170 175
171 - $extension['slug'] = $slug;
176 + $extension['slug'] = $slug;
172 177
173 - if ( ! isset( $extension['name'] ) ) {
174 - $extension['name'] = $plugin_data['Name'];
175 - }
176 - $extension['version'] = $plugin_data['Version'];
177 - $extension['description'] = $plugin_data['Description'];
178 - $extension['author'] = $plugin_data['Author'];
179 - $extension['icon'] = isset( $extension['icon'] ) ? trim( $extension['icon'] ) : '';
180 - $extension['iconURI'] = $file_data['IconURI'];
181 - $extension['SupportForumURI'] = $file_data['SupportForumURI'];
182 - $extension['DocumentationURI'] = $file_data['DocumentationURI'];
183 - $extension['page'] = 'Extensions-' . str_replace( ' ', '-', ucwords( str_replace( '-', ' ', dirname( $slug ) ) ) );
178 + if ( ! isset( $extension['name'] ) ) {
179 + $extension['name'] = $plugin_data['Name'];
180 + }
181 + $extension['version'] = $plugin_data['Version'];
182 + $extension['description'] = $plugin_data['Description'];
183 + $extension['author'] = $plugin_data['Author'];
184 + $extension['icon'] = isset( $extension['icon'] ) ? trim( $extension['icon'] ) : '';
185 + $extension['iconURI'] = $file_data['IconURI'];
186 + $extension['SupportForumURI'] = $file_data['SupportForumURI'];
187 + $extension['DocumentationURI'] = $file_data['DocumentationURI'];
188 + $extension['page'] = 'Extensions-' . str_replace( ' ', '-', ucwords( str_replace( '-', ' ', dirname( $slug ) ) ) );
184 189
185 - if ( isset( $extension['apiManager'] ) && $extension['apiManager'] ) {
190 + if ( isset( $extension['apiManager'] ) && $extension['apiManager'] ) {
186 191
187 - $api_slug = dirname( $slug );
192 + $api_slug = dirname( $slug );
188 193
189 - if ( $is_cached ) {
190 - $options = isset( $activations_cached[ $api_slug ] ) ? $activations_cached[ $api_slug ] : array();
191 - } else {
192 - $options = MainWP_Api_Manager::instance()->get_activation_info( $api_slug );
193 - $activations_cached[ $api_slug ] = $options;
194 - }
194 + if ( $is_cached ) {
195 + $options = isset( $activations_cached[ $api_slug ] ) ? $activations_cached[ $api_slug ] : array();
196 + // MWP-1546 (Codex follow-up): pre-MWP-1546 builds persisted
197 + // the full decrypted activation array (including plaintext
198 + // 'api_key') into mainwp_extensions_all_activation_cached.
199 + // On upgrade those rows survive as long as the cache stays
200 + // populated. Treat any cache-hit entry that still carries
201 + // 'api_key' as untrusted legacy data: strip it, derive
202 + // has_api_key, and rewrite the sanitized entry in the
203 + // cache so the plaintext never sees another disk write.
204 + if ( is_array( $options ) && array_key_exists( 'api_key', $options ) ) {
205 + $had_key = ! empty( $options['api_key'] );
206 + unset( $options['api_key'] );
207 + $options['has_api_key'] = $had_key;
208 + $activations_cached[ $api_slug ] = $options;
209 + // Force the post-loop update_option write below to fire.
210 + $is_cached = false;
211 + }
212 + } else {
213 + $options = MainWP_Api_Manager::instance()->get_activation_info( $api_slug );
214 + if ( ! is_array( $options ) ) {
215 + $options = array();
216 + }
217 + // MWP-1546: the activations_cached option is persisted via
218 + // update_option(). Storing the decrypted api_key here would
219 + // re-leak the plaintext into another database row,
220 + // defeating the at-rest encryption added to set_activation_info().
221 + // Cache only the non-credential fields plus a has_api_key
222 + // boolean so the cache-hit path knows whether a key is
223 + // configured without ever holding the plaintext.
224 + $cached_options = $options;
225 + unset( $cached_options['api_key'] );
226 + $cached_options['has_api_key'] = ! empty( $options['api_key'] );
227 + $activations_cached[ $api_slug ] = $cached_options;
228 + }
195 229
196 - if ( ! is_array( $options ) ) {
197 - $options = array();
198 - }
230 + if ( ! is_array( $options ) ) {
231 + $options = array();
232 + }
199 233
200 - $extension['api_key'] = isset( $options['api_key'] ) ? $options['api_key'] : '';
201 - $extension['activated_key'] = isset( $options['activated_key'] ) ? $options['activated_key'] : 'Deactivated';
202 - $extension['deactivate_checkbox'] = isset( $options['deactivate_checkbox'] ) ? $options['deactivate_checkbox'] : 'off';
203 - $extension['product_id'] = isset( $options['product_id'] ) ? $options['product_id'] : '';
204 - $extension['instance_id'] = isset( $options['instance_id'] ) ? $options['instance_id'] : '';
205 - $extension['software_version'] = isset( $options['software_version'] ) ? $options['software_version'] : '';
206 - $extension['mainwp_version'] = isset( $options['mainwp_version'] ) ? $options['mainwp_version'] : '';
234 + // MWP-1546: stop persisting the per-extension license key
235 + // into the aggregated mainwp_extensions option. The original
236 + // 'api_key' field on $extension was a plaintext string sourced
237 + // from get_activation_info(); render code that needs to know
238 + // "is a key configured?" should consult 'has_api_key' instead.
239 + // The deactivate flow uses a server-side sentinel-resolution
240 + // path (see MainWP_Post_Extension_Handler::deactivate_extension)
241 + // that fetches the real key from the per-slug option at the
242 + // moment of use, never via the aggregate.
243 + //
244 + // The cache-hit path stores has_api_key directly (see above);
245 + // the fresh-load path infers it from the decrypted plaintext.
246 + $extension['has_api_key'] = isset( $options['has_api_key'] ) ? (bool) $options['has_api_key'] : ! empty( $options['api_key'] );
247 + $extension['activated_key'] = isset( $options['activated_key'] ) ? $options['activated_key'] : 'Deactivated';
248 + $extension['deactivate_checkbox'] = isset( $options['deactivate_checkbox'] ) ? $options['deactivate_checkbox'] : 'off';
249 + $extension['product_id'] = isset( $options['product_id'] ) ? $options['product_id'] : '';
250 + $extension['instance_id'] = isset( $options['instance_id'] ) ? $options['instance_id'] : '';
251 + $extension['software_version'] = isset( $options['software_version'] ) ? $options['software_version'] : '';
252 + $extension['mainwp_version'] = isset( $options['mainwp_version'] ) ? $options['mainwp_version'] : '';
207 253
208 - if ( isset( $options['product_item_id'] ) ) {
209 - $extension['product_item_id'] = $options['product_item_id'];
210 - }
211 - }
254 + if ( isset( $options['product_item_id'] ) ) {
255 + $extension['product_item_id'] = $options['product_item_id'];
256 + }
257 + }
212 258
213 - $ext_slug = dirname( $slug );
214 - if ( isset( $all_available_extensions[ $ext_slug ] ) ) {
215 - $extension['type'] = $all_available_extensions[ $ext_slug ]['type']; // to fix.
216 - }
259 + $ext_slug = dirname( $slug );
260 + if ( isset( $all_available_extensions[ $ext_slug ] ) ) {
261 + $extension['type'] = $all_available_extensions[ $ext_slug ]['type']; // to fix.
262 + }
217 263
218 - $save_extensions[] = $extension;
219 - if ( mainwp_current_user_have_right( 'extension', dirname( $slug ) ) ) {
220 - $callback = isset( $extension['callback'] ) ? $extension['callback'] : '';
221 - $menu_name = MainWP_Extensions_Handler::polish_ext_name( $extension );
222 - if ( MainWP_Extensions_Handler::added_on_menu( $slug ) ) {
223 - $_page = add_submenu_page( 'mainwp_tab', $extension['name'], $menu_name, 'read', $extension['page'], $callback );
224 - } else {
225 - $_page = add_submenu_page( 'mainwp_tab', $extension['name'], '<div class="mainwp-hidden">' . $extension['name'] . '</div>', 'read', $extension['page'], $callback );
226 - }
264 + $save_extensions[] = $extension;
265 + if ( \mainwp_current_user_can( 'extension', dirname( $slug ) ) ) {
266 + $callback = isset( $extension['callback'] ) ? $extension['callback'] : '';
267 + $menu_name = MainWP_Extensions_Handler::polish_ext_name( $extension );
268 + if ( MainWP_Extensions_Handler::added_on_menu( $slug ) ) {
269 + $_page = add_submenu_page( 'mainwp_tab', $extension['name'], $menu_name, 'read', $extension['page'], $callback );
270 + } else {
271 + $_page = add_submenu_page( 'mainwp_tab', $extension['name'], '<div class="mainwp-hidden">' . $extension['name'] . '</div>', 'read', $extension['page'], $callback );
272 + }
227 273
228 - if ( isset( $extension['on_load_callback'] ) && ! empty( $extension['on_load_callback'] ) ) {
229 - add_action( 'load-' . $_page, $extension['on_load_callback'] );
230 - }
274 + if ( isset( $extension['on_load_callback'] ) && ! empty( $extension['on_load_callback'] ) ) {
275 + add_action( 'load-' . $_page, $extension['on_load_callback'] );
276 + }
231 277
232 - $_item = array(
233 - 'title' => $menu_name,
234 - 'slug' => $extension['page'],
235 - 'href' => isset( $extension['href'] ) ? $extension['href'] : '',
236 - );
278 + $_item = array(
279 + 'title' => $menu_name,
280 + 'slug' => $extension['page'],
281 + 'href' => isset( $extension['href'] ) ? $extension['href'] : '',
282 + );
237 283
238 - $extsPages[] = $_item;
239 - }
240 - }
284 + $extsPages[] = $_item;
285 + }
286 + }
241 287
242 - if ( ! empty( $deactivated_imcompatible ) ) {
243 - set_transient( 'mainwp_transient_deactivated_incomtible_exts', $deactivated_imcompatible );
244 - }
288 + if ( ! empty( $deactivated_imcompatible ) ) {
289 + set_transient( 'mainwp_transient_deactivated_incomtible_exts', $deactivated_imcompatible );
290 + }
245 291
246 - MainWP_Utility::update_option( 'mainwp_extensions', $save_extensions );
247 - MainWP_Extensions_Handler::get_extensions( true ); // forced reload.
292 + MainWP_Utility::update_option( 'mainwp_extensions', $save_extensions );
293 + MainWP_Extensions_Handler::get_extensions( true ); // forced reload.
248 294
249 - if ( ! $is_cached ) {
250 - update_option( 'mainwp_extensions_all_activation_cached', $activations_cached );
251 - }
252 - self::init_left_menu( $extsPages );
253 - }
295 + if ( ! $is_cached ) {
296 + update_option( 'mainwp_extensions_all_activation_cached', $activations_cached );
297 + }
298 + static::init_left_menu( $extsPages );
299 + }
254 300
255 - /**
256 - * Method init_left_menu()
257 - *
258 - * Initiate top level Extensions Menues.
259 - *
260 - * @param array $extPages List of extension pages.
261 - * @uses \MainWP\Dashboard\MainWP_Menu::is_disable_menu_item()
262 - * @uses \MainWP\Dashboard\MainWP_Menu::add_left_menu()
263 - * @uses \MainWP\Dashboard\MainWP_Menu::init_subpages_left_menu()
264 - */
265 - public static function init_left_menu( $extPages ) {
266 - $subPages = array();
267 - if ( ! MainWP_Menu::is_disable_menu_item( 2, 'Extensions' ) ) {
268 - MainWP_Menu::add_left_menu(
269 - array(
270 - 'title' => esc_html__( 'Extensions', 'mainwp' ),
271 - 'parent_key' => 'mainwp_tab',
272 - 'slug' => 'Extensions',
273 - 'href' => 'admin.php?page=Extensions',
274 - 'icon' => '<i class="puzzle piece icon"></i>',
275 - 'id' => 'menu-item-extensions',
276 - ),
277 - 0
278 - );
301 + /**
302 + * Method init_left_menu()
303 + *
304 + * Initiate top level Extensions Menues.
305 + *
306 + * @param array $extPages List of extension pages.
307 + * @uses \MainWP\Dashboard\MainWP_Menu::is_disable_menu_item()
308 + * @uses \MainWP\Dashboard\MainWP_Menu::add_left_menu()
309 + * @uses \MainWP\Dashboard\MainWP_Menu::init_subpages_left_menu()
310 + */
311 + public static function init_left_menu( $extPages ) {
312 + $subPages = array();
313 + if ( ! MainWP_Menu::is_disable_menu_item( 2, 'Extensions' ) ) {
314 + MainWP_Menu::add_left_menu(
315 + array(
316 + 'title' => esc_html__( 'Add-ons', 'mainwp' ),
317 + 'parent_key' => 'mainwp_tab',
318 + 'slug' => 'Extensions',
319 + 'href' => 'admin.php?page=Extensions',
320 + 'icon' => '<i class="box icon"></i>',
321 + ),
322 + 0
323 + );
279 324
280 - $init_sub_subleftmenu = array(
281 - array(
282 - 'title' => esc_html__( 'Manage Extensions', 'mainwp' ),
283 - 'parent_key' => 'Extensions',
284 - 'href' => 'admin.php?page=Extensions',
285 - 'slug' => 'Extensions',
286 - 'right' => '',
287 - ),
288 - );
325 + $init_sub_subleftmenu = array(
326 + array(
327 + 'title' => esc_html__( 'Manage Add-ons', 'mainwp' ),
328 + 'parent_key' => 'Extensions',
329 + 'href' => 'admin.php?page=Extensions',
330 + 'slug' => 'Extensions',
331 + 'right' => '',
332 + ),
333 + );
289 334
290 - MainWP_Menu::init_subpages_left_menu( $subPages, $init_sub_subleftmenu, 'Extensions', 'Extensions' );
335 + MainWP_Menu::init_subpages_left_menu( $subPages, $init_sub_subleftmenu, 'Extensions', 'Extensions' );
291 336
292 - foreach ( $init_sub_subleftmenu as $item ) {
293 - if ( MainWP_Menu::is_disable_menu_item( 3, $item['slug'] ) ) {
294 - continue;
295 - }
296 - MainWP_Menu::add_left_menu( $item, 2 );
297 - }
337 + foreach ( $init_sub_subleftmenu as $item ) {
338 + if ( MainWP_Menu::is_disable_menu_item( 3, $item['slug'] ) ) {
339 + continue;
340 + }
341 + MainWP_Menu::add_left_menu( $item, 2 );
342 + }
298 343
299 - if ( 0 < count( $extPages ) ) {
344 + if ( ! empty( $extPages ) ) {
300 345
301 - $init_sub_subleftmenu = array();
302 - $slug = '';
303 - MainWP_Menu::init_subpages_left_menu( $extPages, $init_sub_subleftmenu, 'Extensions', $slug );
346 + $init_sub_subleftmenu = array();
347 + $slug = '';
348 + MainWP_Menu::init_subpages_left_menu( $extPages, $init_sub_subleftmenu, 'Extensions', $slug );
304 349
305 - foreach ( $init_sub_subleftmenu as $item ) {
306 - if ( MainWP_Menu::is_disable_menu_item( 3, $item['slug'] ) ) {
307 - continue;
308 - }
309 - MainWP_Menu::add_left_menu( $item, 2 );
310 - }
311 - }
312 - }
313 - }
350 + foreach ( $init_sub_subleftmenu as $item ) {
351 + if ( MainWP_Menu::is_disable_menu_item( 3, $item['slug'] ) ) {
352 + continue;
353 + }
354 + MainWP_Menu::add_left_menu( $item, 2 );
355 + }
356 + }
357 + }
358 + }
314 359
315 - /**
316 - * Method init_subpages_menu()
317 - *
318 - * Initiate Extensions Subpage Menu.
319 - *
320 - * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::get_extensions()
321 - * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::added_on_menu()
322 - * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::polish_ext_name()
323 - */
324 - public static function init_subpages_menu() {
325 - $exts = MainWP_Extensions_Handler::get_extensions();
326 - if ( empty( $exts ) ) {
327 - return;
328 - }
329 - $html = '';
330 - foreach ( $exts as $extension ) {
331 - if ( defined( 'MWP_TEAMCONTROL_PLUGIN_SLUG' ) && ( MWP_TEAMCONTROL_PLUGIN_SLUG === $extension['slug'] ) && ! mainwp_current_user_have_right( 'extension', dirname( MWP_TEAMCONTROL_PLUGIN_SLUG ) ) ) {
332 - continue;
333 - }
334 - if ( MainWP_Extensions_Handler::added_on_menu( $extension['slug'] ) ) {
335 - continue;
336 - }
337 - $menu_name = MainWP_Extensions_Handler::polish_ext_name( $extension );
360 + /**
361 + * Method init_subpages_menu()
362 + *
363 + * Initiate Extensions Subpage Menu.
364 + *
365 + * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::get_extensions()
366 + * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::added_on_menu()
367 + * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::polish_ext_name()
368 + */
369 + public static function init_subpages_menu() {
370 + $exts = MainWP_Extensions_Handler::get_extensions();
371 + if ( empty( $exts ) ) {
372 + return;
373 + }
374 + $html = '';
375 + foreach ( $exts as $extension ) {
376 + if ( defined( 'MWP_TEAMCONTROL_PLUGIN_SLUG' ) && ( MWP_TEAMCONTROL_PLUGIN_SLUG === $extension['slug'] ) && ! \mainwp_current_user_can( 'extension', dirname( MWP_TEAMCONTROL_PLUGIN_SLUG ) ) ) {
377 + continue;
378 + }
379 + if ( MainWP_Extensions_Handler::added_on_menu( $extension['slug'] ) ) {
380 + continue;
381 + }
382 + $menu_name = MainWP_Extensions_Handler::polish_ext_name( $extension );
338 383
339 - if ( isset( $extension['direct_page'] ) ) {
340 - $html .= '<a href="' . esc_url( admin_url( 'admin.php?page=' . $extension['direct_page'] ) ) . '" class="mainwp-submenu">' . $menu_name . '</a>';
341 - } else {
342 - $html .= '<a href="' . esc_url( admin_url( 'admin.php?page=' . $extension['page'] ) ) . '" class="mainwp-submenu">' . $menu_name . '</a>';
343 - }
344 - }
345 - if ( empty( $html ) ) {
346 - return;
347 - }
348 - ?>
349 - <div id="menu-mainwp-Extensions" class="mainwp-submenu-wrapper" xmlns="http://www.w3.org/1999/html">
350 - <div class="wp-submenu sub-open" style="">
351 - <div class="mainwp_boxout mainwp-submenu-wide">
352 - <div class="mainwp_boxoutin"></div>
353 - <?php echo $html; // phpcs:ignore WordPress.Security.EscapeOutput ?>
354 - </div>
355 - </div>
356 - </div>
357 - <?php
358 - }
384 + if ( isset( $extension['direct_page'] ) ) {
385 + $html .= '<a href="' . esc_url( admin_url( 'admin.php?page=' . $extension['direct_page'] ) ) . '" class="mainwp-submenu">' . $menu_name . '</a>';
386 + } else {
387 + $html .= '<a href="' . esc_url( admin_url( 'admin.php?page=' . $extension['page'] ) ) . '" class="mainwp-submenu">' . $menu_name . '</a>';
388 + }
389 + }
390 + if ( empty( $html ) ) {
391 + return;
392 + }
393 + ?>
394 + <div id="menu-mainwp-Extensions" class="mainwp-submenu-wrapper" xmlns="http://www.w3.org/1999/html">
395 + <div class="wp-submenu sub-open" style="">
396 + <div class="mainwp_boxout mainwp-submenu-wide">
397 + <div class="mainwp_boxoutin"></div>
398 + <?php echo $html; // phpcs:ignore WordPress.Security.EscapeOutput ?>
399 + </div>
400 + </div>
401 + </div>
402 + <?php
403 + }
359 404
360 405
361 - /**
362 - * Method ajax_get_purchased_extensions()
363 - *
364 - * Get purchased MainWP Extensions.
365 - *
366 - * @uses \MainWP\Dashboard\MainWP_Api_Manager::get_purchased_extension()
367 - * @uses \MainWP\Dashboard\MainWP_Api_Manager::check_response_for_intall_errors()
368 - * @uses \MainWP\Dashboard\MainWP_Extensions_View::get_available_extensions()
369 - * @uses \MainWP\Dashboard\MainWP_Extensions_View::get_extension_groups()
370 - * @uses \MainWP\Dashboard\MainWP_Post_Handler::secure_request()
371 - * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::get_extensions()
372 - * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
373 - */
374 - public static function ajax_get_purchased_extensions() { // phpcs:ignore -- complex function. Current complexity is the only way to achieve desired results, pull request solutions appreciated.
406 + /**
407 + * Method ajax_get_purchased_extensions()
408 + *
409 + * Get purchased MainWP Extensions.
410 + *
411 + * @uses \MainWP\Dashboard\MainWP_Api_Manager::get_purchased_extension()
412 + * @uses \MainWP\Dashboard\MainWP_Api_Manager::check_response_for_intall_errors()
413 + * @uses \MainWP\Dashboard\MainWP_Extensions_View::get_available_extensions()
414 + * @uses \MainWP\Dashboard\MainWP_Extensions_View::get_extension_groups()
415 + * @uses \MainWP\Dashboard\MainWP_Post_Handler::secure_request()
416 + * @uses \MainWP\Dashboard\MainWP_Extensions_Handler::get_extensions()
417 + * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
418 + */
419 + public static function ajax_get_purchased_extensions() { // phpcs:ignore -- NOSONAR - complex function. Current complexity is the only way to achieve desired results, pull request solutions appreciated.
375 420
376 - MainWP_Post_Handler::instance()->secure_request( 'mainwp_extension_getpurchased' );
421 + MainWP_Post_Handler::instance()->secure_request( 'mainwp_extension_getpurchased' );
377 422
378 - $api_key = isset( $_POST['api_key'] ) ? trim( wp_unslash( $_POST['api_key'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
423 + $api_key = isset( $_POST['api_key'] ) ? trim( wp_unslash( $_POST['api_key'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
379 424
380 - $all_available_extensions_compatible_api_response = array();
381 - $all_free_pro_exts = array();
382 - $all_org_exts = array();
383 - $map_extensions_group = array();
384 - $purchased_data = array();
425 + // MWP-1547: the Extensions page renders the sentinel placeholder
426 + // when a master key is already stored. The browser submits whatever
427 + // value is in #mainwp_com_api_key, which is the sentinel for
428 + // remembered-license dashboards. Resolve to the stored decrypted
429 + // master key server-side rather than sending the placeholder
430 + // upstream.
431 + if ( MainWP_Credential_Render::is_sentinel( $api_key ) ) {
432 + $api_key = MainWP_Api_Manager_Key::instance()->get_decrypt_master_api_key();
433 + }
385 434
386 - $all_groups = MainWP_Extensions_View::get_extension_groups();
435 + $all_available_extensions_compatible_api_response = array();
436 + $all_free_pro_exts = array();
437 + $all_org_exts = array();
438 + $map_extensions_group = array();
439 + $purchased_data = array();
387 440
388 - $grouped_exts = array(
389 - 'others' => '',
390 - 'all' => '',
391 - );
441 + $all_groups = MainWP_Extensions_View::get_extension_groups();
392 442
393 - foreach ( MainWP_Extensions_View::get_available_extensions( 'all' ) as $ext ) {
394 - $all_available_extensions_compatible_api_response[ $ext['product_id'] ] = $ext;
395 - $map_extensions_group[ $ext['product_id'] ] = current( $ext['group'] );
396 - if ( 'free' === $ext['type'] || 'pro' === $ext['type'] ) {
397 - $all_free_pro_exts[ $ext['product_id'] ] = $ext['product_id'];
398 - } elseif ( 'org' === $ext['type'] ) {
399 - $all_org_exts[ $ext['product_id'] ] = $ext['product_id'];
400 - }
401 - }
443 + $grouped_exts = array(
444 + 'others' => '',
445 + 'all' => '',
446 + );
402 447
403 - $extensions = MainWP_Extensions_Handler::get_extensions();
404 - $installed_softwares = array();
448 + foreach ( MainWP_Extensions_View::get_available_extensions( 'all' ) as $ext ) {
449 + $all_available_extensions_compatible_api_response[ $ext['product_id'] ] = $ext;
450 + $map_extensions_group[ $ext['product_id'] ] = current( $ext['group'] );
451 + if ( 'free' === $ext['type'] || 'pro' === $ext['type'] ) {
452 + $all_free_pro_exts[ $ext['product_id'] ] = $ext['product_id'];
453 + } elseif ( 'org' === $ext['type'] ) {
454 + $all_org_exts[ $ext['product_id'] ] = $ext['product_id'];
455 + }
456 + }
405 457
406 - foreach ( $extensions as $extension ) {
407 - if ( isset( $extension['type'] ) ) {
408 - if ( 'free' === $extension['type'] || 'pro' === $extension['type'] ) {
409 - if ( isset( $extension['product_id'] ) && ! empty( $extension['product_id'] ) ) {
410 - $installed_softwares[ $extension['product_id'] ] = $extension['product_id'];
411 - }
412 - } elseif ( 'org' === $extension['type'] ) {
413 - $ext_slug = dirname( $extension['slug'] );
414 - $installed_softwares[ $ext_slug ] = $ext_slug;
415 - }
416 - }
417 - }
458 + $extensions = MainWP_Extensions_Handler::get_extensions();
459 + $installed_softwares = array();
418 460
419 - $all_disabled_extensions = MainWP_Extensions_Handler::get_extensions_disabled( true );
461 + foreach ( $extensions as $extension ) {
462 + if ( isset( $extension['type'] ) ) {
463 + if ( 'free' === $extension['type'] || 'pro' === $extension['type'] ) {
464 + if ( isset( $extension['product_id'] ) && ! empty( $extension['product_id'] ) ) {
465 + $installed_softwares[ $extension['product_id'] ] = $extension['product_id'];
466 + }
467 + } elseif ( 'org' === $extension['type'] ) {
468 + $ext_slug = dirname( $extension['slug'] );
469 + $installed_softwares[ $ext_slug ] = $ext_slug;
470 + }
471 + }
472 + }
420 473
421 - foreach ( $all_disabled_extensions as $ext ) {
422 - $installed_softwares[ $ext['product_id'] ] = $ext['product_id'];
423 - }
474 + $all_disabled_extensions = MainWP_Extensions_Handler::get_extensions_disabled( true );
424 475
425 - $not_purchased_exts = $all_free_pro_exts;
426 - $not_installed_org_exts = array_diff_key( $all_org_exts, $installed_softwares );
427 - $installing_exts = $not_installed_org_exts;
476 + foreach ( $all_disabled_extensions as $ext ) {
477 + $installed_softwares[ $ext['product_id'] ] = $ext['product_id'];
478 + }
428 479
429 - if ( ! empty( $api_key ) ) {
480 + $not_purchased_exts = $all_free_pro_exts;
481 + $not_installed_org_exts = array_diff_key( $all_org_exts, $installed_softwares );
482 + $installing_exts = $not_installed_org_exts;
430 483
431 - $data = MainWP_Api_Manager::instance()->get_purchased_extension( $api_key );
484 + if ( ! empty( $api_key ) ) {
432 485
433 - $result = json_decode( $data, true );
434 - $return = array();
486 + $data = MainWP_Api_Manager::instance()->get_purchased_extension( $api_key );
435 487
436 - if ( is_array( $result ) ) {
437 - if ( isset( $result['success'] ) && $result['success'] ) {
438 - $purchased_data = ( isset( $result['purchased_data'] ) && is_array( $result['purchased_data'] ) ) ? $result['purchased_data'] : array();
439 - $not_purchased_exts = array_diff_key( $all_free_pro_exts, $purchased_data );
440 - $installing_exts = array_diff_key( $purchased_data, $installed_softwares );
441 - $installing_exts = array_merge( $installing_exts, $not_installed_org_exts );
442 - } elseif ( isset( $result['error'] ) ) {
443 - $return = array( 'error' => $result['error'] );
444 - }
445 - } else {
446 - $apisslverify = get_option( 'mainwp_api_sslVerifyCertificate' );
447 - if ( 1 === $apisslverify ) {
448 - MainWP_Utility::update_option( 'mainwp_api_sslVerifyCertificate', 0 );
449 - $return['retry_action'] = 1;
450 - }
451 - }
488 + $result = json_decode( $data, true );
489 + $return = array();
452 490
453 - if ( ! empty( $return ) ) {
454 - wp_send_json( $return );
455 - }
456 - }
491 + if ( is_array( $result ) ) {
492 + if ( isset( $result['success'] ) && $result['success'] ) {
493 + $purchased_data = ( isset( $result['purchased_data'] ) && is_array( $result['purchased_data'] ) ) ? $result['purchased_data'] : array();
494 + $not_purchased_exts = array_diff_key( $all_free_pro_exts, $purchased_data );
495 + $installing_exts = array_diff_key( $purchased_data, $installed_softwares );
496 + $installing_exts = array_merge( $installing_exts, $not_installed_org_exts );
497 + } elseif ( isset( $result['error'] ) ) {
498 + $return = array( 'error' => $result['error'] );
499 + }
500 + } else {
501 + $apisslverify = get_option( 'mainwp_api_sslVerifyCertificate' );
502 + if ( 1 === $apisslverify ) {
503 + MainWP_Utility::update_option( 'mainwp_api_sslVerifyCertificate', 0 );
504 + $return['retry_action'] = 1;
505 + }
506 + }
457 507
458 - foreach ( $all_available_extensions_compatible_api_response as $product_id => $ext ) {
508 + if ( ! empty( $return ) ) {
509 + wp_send_json( $return );
510 + }
511 + }
459 512
460 - $item_html = '';
461 - $error = '';
462 - $ext_source_label = '';
463 - $type = '';
464 - $notice = '';
465 - $integration_type = '';
466 - $pri = (int) $ext['privacy'];
513 + foreach ( $all_available_extensions_compatible_api_response as $product_id => $ext ) {
467 514
468 - if ( 0 === $pri ) {
469 - $integration_type = 'standalone-extension';
470 - } elseif ( 1 === $pri ) {
471 - $integration_type = 'api-extension';
472 - } elseif ( 2 === $pri ) {
473 - $integration_type = 'plugin-extension';
474 - }
515 + $item_html = '';
516 + $error = '';
517 + $ext_source_label = '';
518 + $type = '';
519 + $notice = '';
520 + $add_on_model = '';
521 + $model = $ext['model'];
475 522
476 - $item_slug = MainWP_Utility::get_dir_slug( $ext['slug'] );
523 + if ( 'extension' === $model ) {
524 + $add_on_model = 'addon-extension';
525 + } elseif ( 'integration' === $model ) {
526 + $add_on_model = 'addon-integration';
527 + }
477 528
478 - $privacy = '<a href="#" class="extension-privacy-info-link" base-slug="' . esc_attr( $item_slug ) . '" style="text-decoration:none"> <i class="shield alternate small icon"></i></a>';
529 + $item_slug = MainWP_Utility::get_dir_slug( $ext['slug'] );
479 530
480 - $new = '';
531 + $privacy = '<a href="#" class="extension-privacy-info-link" base-slug="' . esc_attr( $item_slug ) . '" style="text-decoration:none"> <i class="fingerprint small icon"></i></a>';
481 532
482 - $software_title = MainWP_Extensions_Handler::polish_string_name( $ext['title'] );
533 + $new = '';
483 534
484 - if ( ! empty( $ext['type'] ) ) {
485 - $type = $ext['type'];
486 - if ( 'free' === $type ) {
487 - $ext_source_label = '<span class="ui mini green label">FREE</span>';
488 - } elseif ( 'pro' === $type ) {
489 - $ext_source_label = '<span class="ui mini blue label">PRO</span>';
490 - } elseif ( 'org' === $type ) {
491 - $ext_source_label = '<span class="ui mini grey label">.ORG</span>';
492 - }
493 - }
535 + $software_title = MainWP_Extensions_Handler::polish_string_name( $ext['title'] );
494 536
495 - if ( isset( $ext['release_date'] ) && ( time() - $ext['release_date'] < MONTH_IN_SECONDS ) ) {
496 - $new = '<span class="ui mini green label">NEW!</span>';
497 - }
537 + if ( ! empty( $ext['type'] ) ) {
538 + $type = $ext['type'];
539 + if ( 'free' === $type ) {
540 + $ext_source_label = '<span class="ui mini green label">FREE</span>';
541 + } elseif ( 'pro' === $type ) {
542 + $ext_source_label = '<span class="ui mini blue label">PRO</span>';
543 + } elseif ( 'org' === $type ) {
544 + $ext_source_label = '<span class="ui mini grey label">.ORG</span>';
545 + }
546 + }
498 547
499 - if ( 'MainWP WordPress SEO Extension' === $product_id || 'seopress-for-mainwp' === $product_id ) {
500 - $notice = ' <i class="info circle small icon"></i>';
501 - }
548 + if ( isset( $ext['release_date'] ) && ( time() - $ext['release_date'] < MONTH_IN_SECONDS ) ) {
549 + $new = '<span class="ui mini green label">NEW!</span>';
550 + }
502 551
503 - $ext_source_label .= '&nbsp;';
552 + if ( 'MainWP WordPress SEO Extension' === $product_id || 'seopress-for-mainwp' === $product_id ) {
553 + $notice = ' <i class="info circle small icon"></i>';
554 + }
504 555
505 - if ( isset( $installing_exts[ $product_id ] ) ) {
556 + $ext_source_label .= '&nbsp;';
506 557
507 - $product_info = isset( $installing_exts[ $product_id ] ) ? $installing_exts[ $product_id ] : array();
508 - if ( ! is_array( $product_info ) ) {
509 - $product_info = array();
510 - }
558 + if ( isset( $installing_exts[ $product_id ] ) ) {
511 559
512 - if ( 'free' === $type || 'pro' === $type ) {
560 + $product_info = isset( $installing_exts[ $product_id ] ) ? $installing_exts[ $product_id ] : array();
561 + if ( ! is_array( $product_info ) ) {
562 + $product_info = array();
563 + }
513 564
514 - if ( $product_info && isset( $product_info['package'] ) && ! empty( $product_info['package'] ) ) {
565 + if ( 'free' === $type || 'pro' === $type ) {
515 566
516 - /**
517 - * API Manager Upgrade URL
518 - *
519 - * Filters the Upgrade URL for extensions.
520 - *
521 - * @since Unknown
522 - * @ignore
523 - */
524 - $package_url = apply_filters( 'mainwp_api_manager_upgrade_package_url', $product_info['package'], $product_info );
567 + if ( $product_info && isset( $product_info['package'] ) && ! empty( $product_info['package'] ) ) {
525 568
526 - $item_html = '
527 - <div class="item extension extension-to-install ' . esc_attr( $integration_type ) . '" download-link="' . esc_url( $package_url ) . '" plugin-slug="" product-id="' . esc_attr( $product_id ) . '" slug="' . esc_attr( $ext['slug'] ) . '">
528 - <div class="ui stackable grid">
529 - <div class="two column row">
530 - <div class="column"><span class="ui checkbox"><input type="checkbox" status="queue"><label>' . $ext_source_label . '<strong><a href="' . esc_url( $ext['link'] ) . '" target="_blank">' . esc_html( $software_title ) . '</a>' . $privacy . ' ' . $notice . ' ' . $new . '</strong></label></span></div>
531 - <div class="right aligned column"><span class="installing-extension" status="queue"></span></div>
532 - </div>
533 - </div>
534 - </div>';
569 + /**
570 + * API Manager Upgrade URL
571 + *
572 + * Filters the Upgrade URL for extensions.
573 + *
574 + * @since Unknown
575 + * @ignore
576 + */
577 + $package_url = apply_filters( 'mainwp_api_manager_upgrade_package_url', $product_info['package'], $product_info );
535 578
536 - } elseif ( isset( $product_info['error'] ) && ! empty( $product_info['error'] ) ) {
537 - $error = MainWP_Api_Manager::instance()->check_response_for_intall_errors( $product_info, $software_title );
538 - } else {
539 - $error = esc_html__( 'Undefined error occurred. Please try again.', 'mainwp' );
540 - }
579 + $item_html = '
580 + <div class="item extension extension-to-install ' . esc_attr( $add_on_model ) . '" download-link="' . esc_url( $package_url ) . '" plugin-slug="" product-id="' . esc_attr( $product_id ) . '" software-title="' . esc_attr( $software_title ) . '" slug="' . esc_attr( $ext['slug'] ) . '">
581 + <div class="ui stackable grid">
582 + <div class="two column row">
583 + <div class="column"><span class="ui checkbox"><input type="checkbox" status="queue"><label>' . $ext_source_label . '<strong><a href="' . esc_url( $ext['link'] ) . '" target="_blank">' . esc_html( $software_title ) . '</a>' . $privacy . ' ' . $notice . ' ' . $new . '</strong></label></span></div>
584 + <div class="right aligned column"><span class="installing-extension" status="queue"></span></div>
585 + </div>
586 + </div>
587 + </div>';
541 588
542 - if ( ! empty( $error ) ) {
543 - $item_html = '
544 - <div class="item extension ' . esc_attr( $integration_type ) . '" product-id="' . esc_attr( $product_id ) . '">
545 - <div class="ui stackable grid">
546 - <div class="two column row">
547 - <div class="column"><span class="ui checkbox"><input type="checkbox" disabled="disabled"><label>' . $ext_source_label . ' <a href="' . esc_url( $ext['link'] ) . '" target="_blank">' . esc_html( $software_title ) . '</a>' . $privacy . ' ' . $notice . ' ' . $new . '</label></span></div>
548 - <div class="right aligned column"><span data-tooltip="' . $error . '" data-inverted="" data-position="left center"><i class="times red icon"></i></span></div>
549 - </div>
550 - </div>
551 - </div>';
552 - }
553 - } elseif ( 'org' === $type ) {
554 - $item_html = '
555 - <div class="item extension extension-to-install ' . esc_attr( $integration_type ) . '" download-link="" plugin-slug="' . esc_attr( $ext['slug'] ) . '" product-id="' . esc_attr( $product_id ) . '" slug="' . esc_attr( $ext['slug'] ) . '">
556 - <div class="ui stackable grid">
557 - <div class="two column row">
558 - <div class="column"><span class="ui checkbox"><input type="checkbox" status="queue"><label>' . $ext_source_label . '<strong><a href="' . esc_url( $ext['link'] ) . '" target="_blank">' . esc_html( $software_title ) . '</a>' . $privacy . ' ' . $notice . ' ' . $new . '</strong></label></span></div>
559 - <div class="right aligned column"><span class="installing-extension" status="queue"></span></div>
560 - </div>
561 - </div>
562 - </div>';
563 - }
564 - } elseif ( isset( $not_purchased_exts[ $product_id ] ) ) {
565 - if ( 'free' === $type || 'pro' === $type ) {
566 - $item_html = '
567 - <div class="item extension ' . esc_attr( $integration_type ) . '" product-id="' . esc_attr( $product_id ) . '" slug="' . esc_attr( $ext['slug'] ) . '">
568 - <div class="ui stackable grid">
569 - <div class="two column row">
570 - <div class="column"><span class="ui checkbox"><input type="checkbox" disabled="disabled"><label>' . $ext_source_label . ' <a href="' . esc_url( $ext['link'] ) . '" target="_blank">' . esc_html( $software_title ) . '</a>' . $privacy . ' ' . $notice . ' ' . $new . '</label></span></div>
571 - <div class="right aligned column"><a href="' . $ext['link'] . '" target="_blank" data-tooltip="' . esc_html__( 'Extension not purchased. Click to find out more.', 'mainwp' ) . '" data-position="left center" data-inverted=""><i class="info blue icon"></i></a></div>
572 - </div>
573 - </div>
574 - </div>';
575 - } elseif ( 'org' === $type ) {
576 - $item_html = '
577 - <div class="item extension ' . esc_attr( $integration_type ) . '" product-id="' . esc_attr( $product_id ) . '" slug="' . esc_attr( $ext['slug'] ) . '">
578 - <div class="ui stackable grid">
579 - <div class="two column row">
580 - <div class="column"><span class="ui checkbox"><input type="checkbox" disabled="disabled"><label>' . $ext_source_label . ' <a href="' . esc_url( $ext['link'] ) . '" target="_blank">' . esc_html( $software_title ) . '</a>' . $privacy . ' ' . $notice . ' ' . $new . '</label></span></div>
581 - <div class="right aligned column"><a href="' . $ext['url'] . '" target="_blank" data-tooltip="' . esc_html__( 'Extension not installed. Click to find out more.', 'mainwp' ) . '" data-position="left center" data-inverted=""><i class="info blue icon"></i></a></div>
582 - </div>
583 - </div>
584 - </div>';
585 - }
586 - } elseif ( isset( $installed_softwares[ $product_id ] ) ) {
587 - $item_html = '
588 - <div class="item extension ' . esc_attr( $integration_type ) . '" product-id="' . esc_attr( $product_id ) . '" slug="' . esc_attr( $ext['slug'] ) . '">
589 - <div class="ui stackable grid">
590 - <div class="two column row">
591 - <div class="column"><span class="ui checkbox"><input type="checkbox" disabled="disabled"><label>' . $ext_source_label . ' <a href="' . esc_url( $ext['link'] ) . '" target="_blank">' . esc_html( $software_title ) . '</a> ' . $notice . '</label></span>' . $privacy . ' ' . $new . '</div>
592 - <div class="right aligned column">Installed</div>
593 - </div>
594 - </div>
595 - </div>';
596 - }
589 + } elseif ( isset( $product_info['error'] ) && ! empty( $product_info['error'] ) ) {
590 + $error = MainWP_Api_Manager::instance()->check_response_for_intall_errors( $product_info, $software_title );
591 + } else {
592 + $error = esc_html__( 'Undefined error occurred. Please try again.', 'mainwp' );
593 + }
597 594
598 - $group_id = isset( $map_extensions_group[ $product_id ] ) ? $map_extensions_group[ $product_id ] : false;
599 - if ( ! empty( $group_id ) && isset( $all_groups[ $group_id ] ) ) {
600 - if ( isset( $grouped_exts[ $group_id ] ) ) {
601 - $grouped_exts[ $group_id ] .= $item_html;
602 - } else {
603 - $grouped_exts[ $group_id ] = $item_html;
604 - }
605 - } else {
606 - $grouped_exts['others'] .= $item_html;
607 - }
608 - $grouped_exts['all'] .= $item_html;
609 - }
595 + if ( ! empty( $error ) ) {
596 + $item_html = '
597 + <div class="item extension ' . esc_attr( $add_on_model ) . '" product-id="' . esc_attr( $product_id ) . '" software-title="' . esc_attr( $software_title ) . '">
598 + <div class="ui stackable grid">
599 + <div class="two column row">
600 + <div class="column"><span class="ui checkbox"><input type="checkbox" disabled="disabled"><label>' . $ext_source_label . ' <a href="' . esc_url( $ext['link'] ) . '" target="_blank">' . esc_html( $software_title ) . '</a>' . $privacy . ' ' . $notice . ' ' . $new . '</label></span></div>
601 + <div class="right aligned column"><span data-tooltip="' . $error . '" data-inverted="" data-position="left center"><i class="times red icon"></i></span></div>
602 + </div>
603 + </div>
604 + </div>';
605 + }
606 + } elseif ( 'org' === $type ) {
607 + $item_html = '
608 + <div class="item extension extension-to-install ' . esc_attr( $add_on_model ) . '" download-link="" plugin-slug="' . esc_attr( $ext['slug'] ) . '" product-id="' . esc_attr( $product_id ) . '" software-title="' . esc_attr( $software_title ) . '" slug="' . esc_attr( $ext['slug'] ) . '">
609 + <div class="ui stackable grid">
610 + <div class="two column row">
611 + <div class="column"><span class="ui checkbox"><input type="checkbox" status="queue"><label>' . $ext_source_label . '<strong><a href="' . esc_url( $ext['link'] ) . '" target="_blank">' . esc_html( $software_title ) . '</a>' . $privacy . ' ' . $notice . ' ' . $new . '</strong></label></span></div>
612 + <div class="right aligned column"><span class="installing-extension" status="queue"></span></div>
613 + </div>
614 + </div>
615 + </div>';
616 + }
617 + } elseif ( isset( $not_purchased_exts[ $product_id ] ) ) {
618 + if ( 'free' === $type || 'pro' === $type ) {
619 + $item_html = '
620 + <div class="item extension ' . esc_attr( $add_on_model ) . '" product-id="' . esc_attr( $product_id ) . '" software-title="' . esc_attr( $software_title ) . '" slug="' . esc_attr( $ext['slug'] ) . '">
621 + <div class="ui stackable grid">
622 + <div class="two column row">
623 + <div class="column"><span class="ui checkbox"><input type="checkbox" disabled="disabled"><label>' . $ext_source_label . ' <a href="' . esc_url( $ext['link'] ) . '" target="_blank">' . esc_html( $software_title ) . '</a>' . $privacy . ' ' . $notice . ' ' . $new . '</label></span></div>
624 + <div class="right aligned column"><a href="' . $ext['link'] . '" target="_blank" data-tooltip="' . esc_html__( 'Add-on not purchased. Click to find out more.', 'mainwp' ) . '" data-position="left center" data-inverted=""><i class="info blue icon"></i></a></div>
625 + </div>
626 + </div>
627 + </div>';
628 + } elseif ( 'org' === $type ) {
629 + $item_html = '
630 + <div class="item extension ' . esc_attr( $add_on_model ) . '" product-id="' . esc_attr( $product_id ) . '" software-title="' . esc_attr( $software_title ) . '" slug="' . esc_attr( $ext['slug'] ) . '">
631 + <div class="ui stackable grid">
632 + <div class="two column row">
633 + <div class="column"><span class="ui checkbox"><input type="checkbox" disabled="disabled"><label>' . $ext_source_label . ' <a href="' . esc_url( $ext['link'] ) . '" target="_blank">' . esc_html( $software_title ) . '</a>' . $privacy . ' ' . $notice . ' ' . $new . '</label></span></div>
634 + <div class="right aligned column"><a href="' . $ext['url'] . '" target="_blank" data-tooltip="' . esc_attr__( 'Add-on not installed. Click to find out more.', 'mainwp' ) . '" data-position="left center" data-inverted=""><i class="info blue icon"></i></a></div>
635 + </div>
636 + </div>
637 + </div>';
638 + }
639 + } elseif ( isset( $installed_softwares[ $product_id ] ) ) {
640 + $item_html = '
641 + <div class="item extension ' . esc_attr( $add_on_model ) . '" product-id="' . esc_attr( $product_id ) . '" software-title="' . esc_attr( $software_title ) . '" slug="' . esc_attr( $ext['slug'] ) . '">
642 + <div class="ui stackable grid">
643 + <div class="two column row">
644 + <div class="column"><span data-tooltip="' . esc_attr__( 'Already installed', 'mainwp' ) . '" data-inverted="" data-position="right center"><span class="ui checkbox"><input type="checkbox" disabled="disabled"><label>' . $ext_source_label . ' <a href="' . esc_url( $ext['link'] ) . '" target="_blank">' . esc_html( $software_title ) . '</a> ' . $notice . '</label></label></span>' . $privacy . ' ' . $new . '</div>
645 + <div class="right aligned column"><span data-tooltip="' . esc_attr__( 'Already installed', 'mainwp' ) . '" data-inverted="" data-position="left center"><i class="grey box icon"></i></span></div>
646 + </div>
647 + </div>
648 + </div>';
649 + }
610 650
611 - $html = '<div class="mainwp-installing-extensions">';
651 + $group_id = isset( $map_extensions_group[ $product_id ] ) ? $map_extensions_group[ $product_id ] : false;
652 + if ( ! empty( $group_id ) && isset( $all_groups[ $group_id ] ) ) {
653 + if ( isset( $grouped_exts[ $group_id ] ) ) {
654 + $grouped_exts[ $group_id ] .= $item_html;
655 + } else {
656 + $grouped_exts[ $group_id ] = $item_html;
657 + }
658 + } else {
659 + $grouped_exts['others'] .= $item_html;
660 + }
661 + $grouped_exts['all'] .= $item_html;
662 + }
612 663
613 - if ( empty( $installing_exts ) && count( $purchased_data ) === count( $all_free_pro_exts ) ) {
614 - $html .= '<div class="ui message yellow">' . esc_html__( 'All purchased extensions already installed.', 'mainwp' ) . '</div>';
615 - } else {
616 - if ( isset( $not_purchased_exts ) && ! empty( $not_purchased_exts ) ) {
617 - $html .= '<div class="ui message info">' . esc_html__( 'You have access to all our Free and third-party Extensions on WP.org and any that you have registered for, but you DO NOT need to install them. ', 'mainwp' );
618 - $html .= '<br /><br />';
619 - $html .= esc_html__( 'To avoid information overload, we highly recommend adding Extensions one at a time and as you need them. Skip any Extension you do not want to install at this time.', 'mainwp' );
620 - $html .= '<br /><br />';
621 - $html .= sprintf( esc_html__( 'After installing all your selected Extensions, close the modal by clicking the Close button and %1$sactivate Extensions API license%2$s.', 'mainwp' ), '<a href="https://kb.mainwp.com/docs/activate-extensions-api/" target="_blank">', '</a> <i class="external alternate icon"></i>' ) . '</div>';
622 - } else {
623 - $html .= '<div class="ui message info">' . esc_html__( 'You have access to the MainWP Pro plan, which gives you access to all MainWP-created Extensions, but you DO NOT need to install all of them.', 'mainwp' );
624 - $html .= '<br /><br />';
625 - $html .= esc_html__( 'To avoid information overload, we highly recommend adding Extensions one at a time and as you need them. Skip any Extension you do not want to install at this time.', 'mainwp' );
626 - $html .= '<br /><br />';
627 - $html .= sprintf( esc_html__( 'After installing all your selected Extensions, close the modal by clicking the Close button and %1$sactivate Extensions API license%2$s.', 'mainwp' ), '<a href="https://kb.mainwp.com/docs/activate-extensions-api/" target="_blank">', '</a> <i class="external alternate icon"></i>' ) . '</div>';
628 - }
664 + $html = '<div class="mainwp-installing-extensions">';
629 665
630 - $html .= '<div id="mainwp-bulk-activating-extensions-status" class="ui message" style="display:none;"></div>';
666 + if ( empty( $installing_exts ) && count( $purchased_data ) === count( $all_free_pro_exts ) ) {
667 + $html .= '<div class="ui message">' . esc_html__( 'All purchased add-ons already installed.', 'mainwp' ) . '</div>';
668 + } else {
669 + $html .= '<div class="ui icon message">';
670 + $html .= '<em data-emoji=":bulb:" class="medium"></em>';
671 + $html .= '<div class="content">';
672 + $html .= '<div class="header">' . esc_html__( 'Install Only What You Need', 'mainwp' ) . '</div>';
673 + $html .= '<p>';
674 + $html .= esc_html__( 'For a cleaner dashboard and better focus, start with only the add-ons you need right now. You can always install more later.', 'mainwp' );
675 + $html .= '</p>';
676 + $html .= '</div>';
677 + $html .= '</div>';
631 678
632 - $html .= '<div class="ui secondary green pointing tabular stackable menu" id="mainwp-install-extensions-menu">';
633 - foreach ( $all_groups as $gr_id => $gr_name ) {
634 - if ( isset( $grouped_exts[ $gr_id ] ) ) {
635 - $html .= '<a class="item" data-tab="' . $gr_id . '">' . $gr_name . '</a>';
636 - }
637 - }
679 + $html .= '<div class="ui hidden divider"></div>';
638 680
639 - if ( isset( $grouped_exts['others'] ) && ! empty( $grouped_exts['others'] ) ) {
640 - $html .= '<a class="item" data-tab="other">' . esc_html__( 'Other', 'mainwp' ) . '</a>';
641 - }
681 + $html .= '<div id="mainwp-bulk-activating-extensions-status" class="ui message" style="display:none;"></div>';
642 682
643 - $html .= '<a class="item" data-tab="search"><i class="search icon"></i></a>';
683 + $html .= '<div class="ui secondary green pointing tabular stackable menu" id="mainwp-install-extensions-menu">';
684 + foreach ( $all_groups as $gr_id => $gr_name ) {
685 + if ( isset( $grouped_exts[ $gr_id ] ) ) {
686 + $html .= '<a class="item" data-tab="' . $gr_id . '">' . $gr_name . '</a>';
687 + }
688 + }
644 689
645 - $html .= '</div>';
690 + if ( isset( $grouped_exts['others'] ) && ! empty( $grouped_exts['others'] ) ) {
691 + $html .= '<a class="item" data-tab="other">' . esc_html__( 'Other', 'mainwp' ) . '</a>';
692 + }
646 693
647 - foreach ( $all_groups as $gr_id => $gr_name ) {
648 - if ( isset( $grouped_exts[ $gr_id ] ) && 'all' !== $gr_id ) {
649 - $html .= '<div class="ui tab" data-tab="' . $gr_id . '">';
650 - $html .= '<div class="ui hidden divider"></div>';
651 - $html .= '<h3>' . $gr_name . '</h3>';
652 - $html .= '<div class="ui hidden divider"></div>';
653 - $html .= '<div class="ui relaxed divided list">';
654 - $html .= $grouped_exts[ $gr_id ];
655 - $html .= '</div>';
656 - $html .= '</div>';
657 - }
658 - }
694 + $html .= '</div>';
659 695
660 - if ( isset( $grouped_exts['others'] ) && ! empty( $grouped_exts['others'] ) ) {
661 - $html .= '<div class="ui tab" data-tab="other">';
662 - $html .= '<h3>Other</h3>';
663 - $html .= '<div class="ui relaxed divided list">';
664 - $html .= $grouped_exts['others'];
665 - $html .= '</div>';
666 - $html .= '</div>';
667 - }
696 + $html .= '<div class="ui grid">';
697 + $html .= '<div class="eight wide left aligned middle aligned column">';
698 + $html .= esc_html__( 'Show: ', 'mainwp' );
699 + $html .= '<div class="ui checkbox"><input type="checkbox" checked="" id="mainwp-standalone-extensions-filer" name="mainwp-standalone-extensions-filer"><label><strong>' . esc_html__( 'Extensions', 'mainwp' ) . '</label></div>';
700 + $html .= '&nbsp;&nbsp; <div class="ui checkbox"><input type="checkbox" checked="" id="mainwp-api-extensions-filer" name="mainwp-api-extensions-filer"><label>' . esc_html__( 'Integrations', 'mainwp' ) . '</label></div>';
701 + $html .= '&nbsp;&nbsp;&nbsp;&nbsp;<span class="ui small grey text" data-tooltip="' . esc_attr__( 'Extensions add Dashboard features without third-party dependencies. Integrations connect your Dashboard to third-party tools you use.', 'mainwp' ) . '" data-position="right center" data-inverted=""><i class="question circle icon"></i> ' . esc_html__( 'What\'s the difference?', 'mainwp' ) . '</span>';
702 + $html .= '</div>';
703 + $html .= '<div class="eight wide right aligned middle aligned column">';
704 + $html .= '<div id="mainwp-search-extensions-install" class="ui fluid search">
705 + <div class="ui icon mini input">
706 + <input class="prompt" id="mainwp-search-extensions-install-input" type="text" placeholder="' . esc_attr__( 'Find add-on...', 'mainwp' ) . '">
707 + <i class="search icon"></i>
708 + </div>
709 + </div>';
710 + $html .= '</div>';
711 + $html .= '</div>';
668 712
669 - $html .= '<div class="ui tab" data-tab="search">';
670 - $html .= '<h3>Search Extensions</h3>';
671 - $html .= '<div id="mainwp-search-extensions-install" class="ui fluid search">
672 - <div class="ui icon fluid input">
673 - <input class="prompt" id="mainwp-search-extensions-install-input" type="text" placeholder="Find extension...">
674 - <i class="search icon"></i>
675 - </div>
676 - </div>';
677 - $html .= '<div class="ui relaxed divided list" id="mainwp-extensions-to-install-list">';
678 - $html .= $grouped_exts['all'];
679 - $html .= '</div>';
680 - $html .= '</div>';
713 + $html .= '<div class="ui divider"></div>';
681 714
682 - }
683 - $html .= '<div class="ui hidden divider"></div>';
684 - $html .= '<div class="ui secondary segment">';
685 - $html .= '<div class="ui checkbox"><input type="checkbox" checked="" id="mainwp-standalone-extensions-filer" name="mainwp-standalone-extensions-filer"><label>' . esc_html__( 'Show standalone extensions', 'mainwp' ) . '</label></div><br/>';
686 - $html .= '<div class="ui checkbox"><input type="checkbox" checked="" id="mainwp-api-extensions-filer" name="mainwp-api-extensions-filer"><label>' . esc_html__( 'Show extensions that integrate with 3rd party API', 'mainwp' ) . '</label></div><br/>';
687 - $html .= '<div class="ui checkbox"><input type="checkbox" checked="" id="mainwp-plugin-extensions-filer" name="mainwp-plugin-extensions-filer"><label>' . esc_html__( 'Show extensions that integrate with 3rd party plugin', 'mainwp' ) . '</label></div>';
688 - $html .= '</div>';
689 - $html .= '<div class="ui hidden divider"></div>';
690 - $html .= '<div class="ui secondary segment">';
691 - $html .= '<span class="ui mini green label">FREE</span> - ' . esc_html__( 'Free extension developed by MainWP', 'mainwp' ) . '<br/>';
692 - $html .= '<span class="ui mini blue label">PRO</span> - ' . esc_html__( 'Premium extension developed by MainWP', 'mainwp' ) . '<br/>';
693 - $html .= '<span class="ui mini grey label">.ORG</span> - ' . esc_html__( 'Free extension developed by 3rd party author, available on WordPress.org', 'mainwp' );
694 - $html .= '<div class="ui hidden fitted divider"></div>';
695 - $html .= '<i class="info circle icon"></i> ' . esc_html__( 'Extension requires the corresponding plugin on your MainWP Dashboard site too.', 'mainwp' ) . '<br/>';
696 - $html .= '<i class="shield alternate icon"></i> ' . esc_html__( 'Shows the extension privacy info.', 'mainwp' ) . '<br/>';
697 - $html .= '</div>';
715 + $html .= '<div id="mainwp-extensions-search-results" style="display:none;">';
716 + $html .= '<div class="ui middle aligned divided list">';
717 + $html .= $grouped_exts['all'];
718 + $html .= '</div>';
719 + $html .= '</div>';
698 720
699 - $html .= '<script>jQuery( "#mainwp-install-extensions-menu .item" ).tab();</script>';
700 - $html .= '<script type="text/javascript">
701 - jQuery( document ).ready( function () {
702 - jQuery( "#mainwp-search-extensions-install-input" ).on( "keyup", function () {
703 - var searchQuery = jQuery( this ).val().toLowerCase();
704 - var extensions = jQuery( "#mainwp-extensions-to-install-list" ).find( ".item.extension" );
705 - for ( var i = 0; i < extensions.length; i++ ) {
706 - var currentExtension = jQuery( extensions[i] );
707 - var extensionTitle = jQuery( currentExtension ).attr( "product-id" ).toLowerCase();
708 - if ( extensionTitle.indexOf( searchQuery ) > -1 ) {
709 - currentExtension.show();
710 - } else {
711 - currentExtension.hide();
712 - }
713 - }
714 - } );
715 - jQuery( "#mainwp-standalone-extensions-filer" ).on( "change", function () {
716 - jQuery( "#mainwp-get-purchased-extensions-modal .ui.relaxed.divided.list .item.extension.standalone-extension" ).toggle( 200 );
717 - } );
718 - jQuery( "#mainwp-api-extensions-filer" ).on( "change", function () {
719 - jQuery( "#mainwp-get-purchased-extensions-modal .ui.relaxed.divided.list .item.extension.api-extension" ).toggle( 200 );
720 - } );
721 - jQuery( "#mainwp-plugin-extensions-filer" ).on( "change", function () {
722 - jQuery( "#mainwp-get-purchased-extensions-modal .ui.relaxed.divided.list .item.extension.plugin-extension" ).toggle( 200 );
723 - } );
724 - } );
725 - </script>';
721 + foreach ( $all_groups as $gr_id => $gr_name ) {
722 + if ( isset( $grouped_exts[ $gr_id ] ) && 'all' !== $gr_id ) {
723 + $html .= '<div class="ui tab" data-tab="' . $gr_id . '">';
724 + $html .= '<div class="ui middle aligned divided list">';
725 + $html .= $grouped_exts[ $gr_id ];
726 + $html .= '</div>';
727 + $html .= '</div>';
728 + }
729 + }
726 730
727 - if ( ! empty( $installing_exts ) ) {
728 - $html .= '<p>
729 - <span class="extension_api_loading">
730 - <i class="ui active inline loader tiny" style="display: none;"></i><span class="status hidden"></span>
731 - </span>
732 - </p> ';
733 - }
731 + if ( isset( $grouped_exts['others'] ) && ! empty( $grouped_exts['others'] ) ) {
732 + $html .= '<div class="ui tab" data-tab="other">';
733 + $html .= '<div class="ui middle aligned divided list">';
734 + $html .= $grouped_exts['others'];
735 + $html .= '</div>';
736 + $html .= '</div>';
737 + }
738 + }
734 739
735 - $html .= '</div>';
736 - $return = array(
737 - 'result' => 'SUCCESS',
738 - 'data' => $html,
739 - );
740 + $html .= '<div class="ui hidden divider"></div>';
740 741
741 - wp_send_json( $return );
742 - }
742 + $html .= '<div class="ui secondary vertically fitted segment">';
743 + $html .= '<div class="ui horizontal mini list">';
744 + $html .= '<div class="item"><span class="ui mini green label">FREE</span> ' . esc_html__( 'Free add-on by MainWP', 'mainwp' ) . '</div>';
745 + $html .= '<div class="item"><span class="ui mini blue label">PRO</span> ' . esc_html__( 'Premium add-on by MainWP', 'mainwp' ) . '</div>';
746 + $html .= '<div class="item"><span class="ui mini grey label">.ORG</span> ' . esc_html__( 'Free add-on by a third party (WP.org)', 'mainwp' ) . '</div>';
747 + $html .= '<div class="item"><i class="info circle icon"></i> ' . esc_html__( 'Requires the matching plugin on too.', 'mainwp' ) . '</div>';
748 + $html .= '<div class="item"><i class="fingerprint icon"></i> ' . esc_html__( 'Add-on privacy info.', 'mainwp' ) . '</div>';
749 + $html .= '</div>';
750 + $html .= '</div>';
743 751
744 - /**
745 - * Method render_header()
746 - *
747 - * Render page header.
748 - *
749 - * @param string $shownPage The page slug shown at this moment.
750 - *
751 - * @uses \MainWP\Dashboard\MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook()
752 - * @uses \MainWP\Dashboard\MainWP_Extensions_View::render_header()
753 - */
754 - public static function render_header( $shownPage = '' ) {
755 - MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook();
756 - MainWP_Extensions_View::render_header( $shownPage );
757 - }
752 + $html .= '<script>jQuery( "#mainwp-install-extensions-menu .item" ).tab();</script>';
753 + $html .= '<script type="text/javascript">
754 + jQuery( document ).ready( function () {
755 + let $menu = jQuery( "#mainwp-install-extensions-menu" );
756 + let $modal = jQuery( "#mainwp-get-purchased-extensions-modal" );
757 + let $searchInput = jQuery( "#mainwp-search-extensions-install-input" );
758 + let $searchResults = jQuery( "#mainwp-extensions-search-results" );
759 + let $tabsContainer = $modal.find( ".ui.tab[data-tab]" );
758 760
759 - /**
760 - * Method render_footer()
761 - *
762 - * Render page footer.
763 - *
764 - * @param string $shownPage The page slug shown at this moment.
765 - *
766 - * @uses \MainWP\Dashboard\MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook()
767 - * @uses \MainWP\Dashboard\MainWP_Extensions_View::render_footer()
768 - */
769 - public static function render_footer( $shownPage ) {
770 - MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook();
771 - MainWP_Extensions_View::render_footer( $shownPage );
772 - }
761 + $searchResults.find( "input[type=\"checkbox\"]" ).removeAttr( "status" );
773 762
774 - /**
775 - * Method render()
776 - *
777 - * Render page content.
778 - *
779 - * @uses \MainWP\Dashboard\MainWP_Extensions_View::render()
780 - * @uses \MainWP\Dashboard\MainWP_UI::render_top_header()
781 - */
782 - public static function render() {
763 + function syncToTabs( productId, checked ) {
764 + $tabsContainer.find( ".extension-to-install[product-id=\"" + productId + "\"] input[type=\"checkbox\"]" ).prop( "checked", checked );
765 + }
783 766
784 - $params = array(
785 - 'title' => esc_html__( 'Extensions', 'mainwp' ),
786 - );
787 - MainWP_UI::render_top_header( $params );
767 + function syncToSearch( productId, checked ) {
768 + $searchResults.find( ".extension-to-install[product-id=\"" + productId + "\"] input[type=\"checkbox\"]" ).prop( "checked", checked );
769 + }
788 770
789 - MainWP_Extensions_View::render();
790 - echo '</div>';
791 - }
771 + $searchResults.on( "change", "input[type=\"checkbox\"]", function () {
772 + let productId = jQuery( this ).closest( ".extension-to-install" ).attr( "product-id" );
773 + syncToTabs( productId, jQuery( this ).prop( "checked" ) );
774 + } );
792 775
793 - /**
794 - * Method mainwp_help_content()
795 - *
796 - * Create the MainWP Help Document List for the help component in the sidebar.
797 - */
798 - public static function mainwp_help_content() {
799 - if ( isset( $_GET['page'] ) && 'Extensions' === $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
800 - ?>
801 - <p><?php esc_html_e( 'If you need help with your MainWP Extensions, please review following help documents', 'mainwp' ); ?></p>
802 - <div class="ui relaxed bulleted list">
803 - <div class="item"><a href="https://kb.mainwp.com/docs/what-are-mainwp-extensions/" target="_blank"><i class="fa fa-book"></i> What are the MainWP Extensions</a> <i class="external alternate icon"></i></div>
804 - <div class="item"><a href="https://kb.mainwp.com/docs/order-extensions/" target="_blank"><i class="fa fa-book"></i> Order Extension(s)</a> <i class="external alternate icon"></i></div>
805 - <div class="item"><a href="https://kb.mainwp.com/docs/my-downloads-and-api-keys/" target="_blank"><i class="fa fa-book"></i> My Downloads and API Keys</a> <i class="external alternate icon"></i></div>
806 - <div class="item"><a href="https://kb.mainwp.com/docs/install-extensions/" target="_blank"><i class="fa fa-book"></i> Install Extension(s)</a> <i class="external alternate icon"></i></div>
807 - <div class="item"><a href="https://kb.mainwp.com/docs/activate-extensions-api/" target="_blank"><i class="fa fa-book"></i> Activate Extension(s) API</a> <i class="external alternate icon"></i></div>
808 - <div class="item"><a href="https://kb.mainwp.com/docs/updating-extensions/" target="_blank"><i class="fa fa-book"></i> Updating Extension(s)</a> <i class="external alternate icon"></i></div>
809 - <div class="item"><a href="https://kb.mainwp.com/docs/remove-extensions/" target="_blank"><i class="fa fa-book"></i> Remove Extension(s)</a> <i class="external alternate icon"></i></div>
810 - </div>
811 - <?php
812 - }
813 - }
776 + $tabsContainer.on( "change", "input[type=\"checkbox\"]", function () {
777 + let productId = jQuery( this ).closest( ".extension-to-install" ).attr( "product-id" );
778 + syncToSearch( productId, jQuery( this ).prop( "checked" ) );
779 + } );
780 +
781 + function exitSearchMode() {
782 + $searchResults.hide();
783 + $searchResults.find( ".item.extension" ).show();
784 + $tabsContainer.css( "display", "" );
785 + $menu.find( ".item" ).first().trigger( "click" );
786 + }
787 +
788 + $searchInput.on( "keyup", function () {
789 + let searchQuery = jQuery( this ).val().toLowerCase();
790 +
791 + if ( searchQuery.length > 0 ) {
792 + $menu.find( ".item.active" ).removeClass( "active" );
793 + $tabsContainer.css( "display", "none" );
794 + $searchResults.show();
795 + $searchResults.find( ".item.extension" ).each( function () {
796 + let extensionTitle = jQuery( this ).attr( "software-title" ).toLowerCase();
797 + jQuery( this ).toggle( extensionTitle.indexOf( searchQuery ) > -1 );
798 + } );
799 + } else {
800 + exitSearchMode();
801 + }
802 + } );
803 +
804 + $menu.on( "click", ".item", function () {
805 + if ( $searchResults.is( ":visible" ) ) {
806 + $searchInput.val( "" );
807 + $searchResults.hide();
808 + $searchResults.find( ".item.extension" ).show();
809 + $tabsContainer.css( "display", "" );
810 + }
811 + } );
812 + jQuery( "#mainwp-standalone-extensions-filer" ).on( "change", function () {
813 + jQuery( "#mainwp-get-purchased-extensions-modal .ui.list .item.extension.addon-extension" ).toggle( 200 );
814 + } );
815 + jQuery( "#mainwp-api-extensions-filer" ).on( "change", function () {
816 + jQuery( "#mainwp-get-purchased-extensions-modal .ui.list .item.extension.addon-integration" ).toggle( 200 );
817 + } );
818 + } );
819 + </script>';
820 +
821 + if ( ! empty( $installing_exts ) ) {
822 + $html .= '<p>
823 + <span class="extension_api_loading">
824 + <i class="ui active inline loader tiny" style="display: none;"></i><span class="status hidden"></span>
825 + </span>
826 + </p> ';
827 + }
828 +
829 + $html .= '</div>';
830 + $return = array(
831 + 'result' => 'SUCCESS',
832 + 'data' => $html,
833 + );
834 +
835 + wp_send_json( $return );
836 + }
837 +
838 + /**
839 + * Method render_header()
840 + *
841 + * Render page header.
842 + *
843 + * @param string $shownPage The page slug shown at this moment.
844 + *
845 + * @uses \MainWP\Dashboard\MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook()
846 + * @uses \MainWP\Dashboard\MainWP_Extensions_View::render_header()
847 + */
848 + public static function render_header( $shownPage = '' ) {
849 + MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook();
850 + MainWP_Extensions_View::render_header( $shownPage );
851 + }
852 +
853 + /**
854 + * Method render_footer()
855 + *
856 + * Render page footer.
857 + *
858 + * @param string $shownPage The page slug shown at this moment.
859 + *
860 + * @uses \MainWP\Dashboard\MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook()
861 + * @uses \MainWP\Dashboard\MainWP_Extensions_View::render_footer()
862 + */
863 + public static function render_footer( $shownPage ) {
864 + MainWP_Deprecated_Hooks::maybe_handle_deprecated_hook();
865 + MainWP_Extensions_View::render_footer( $shownPage );
866 + }
867 +
868 + /**
869 + * Method render()
870 + *
871 + * Render page content.
872 + *
873 + * @uses \MainWP\Dashboard\MainWP_Extensions_View::render()
874 + * @uses \MainWP\Dashboard\MainWP_UI::render_top_header()
875 + */
876 + public static function render() {
877 +
878 + $params = array(
879 + 'title' => esc_html__( 'Add-ons', 'mainwp' ),
880 + );
881 + MainWP_UI::render_top_header( $params );
882 +
883 + MainWP_Extensions_View::render();
884 + echo '</div>';
885 + }
886 +
887 + /**
888 + * Method mainwp_help_content()
889 + *
890 + * Creates the MainWP Help Documentation List for the help component in the sidebar.
891 + */
892 + public static function mainwp_help_content() {
893 + if ( isset( $_GET['page'] ) && 'Extensions' === $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
894 + ?>
895 + <p><?php esc_html_e( 'If you need help with your MainWP Add-ons, please review following help documents', 'mainwp' ); ?></p>
896 + <div class="ui list">
897 + <div class="item"><i class="external alternate icon"></i> <a href="https://docs.mainwp.com/dashboard/overview/manage-extensions" target="_blank"><i class="fa fa-book"></i> What are the MainWP Add-ons</a></div> <?php // NOSONAR - noopener - open safe. ?>
898 + <div class="item"><i class="external alternate icon"></i> <a href="https://docs.mainwp.com/dashboard/overview/manage-extensions#order-add-ons" target="_blank"><i class="fa fa-book"></i> Order Add-on(s)</a></div> <?php // NOSONAR - noopener - open safe. ?>
899 + <div class="item"><i class="external alternate icon"></i> <a href="https://docs.mainwp.com/dashboard/overview/manage-extensions#install-add-ons" target="_blank"><i class="fa fa-book"></i> Install Add-on(s)</a></div> <?php // NOSONAR - noopener - open safe. ?>
900 + <div class="item"><i class="external alternate icon"></i> <a href="https://docs.mainwp.com/dashboard/overview/manage-extensions#activate-add-ons" target="_blank"><i class="fa fa-book"></i> Activate Add-on(s) API</a></div> <?php // NOSONAR - noopener - open safe. ?>
901 + <div class="item"><i class="external alternate icon"></i> <a href="https://docs.mainwp.com/dashboard/overview/manage-extensions#update-add-ons" target="_blank"><i class="fa fa-book"></i> Updating Add-on(s)</a></div> <?php // NOSONAR - noopener - open safe. ?>
902 + <div class="item"><i class="external alternate icon"></i> <a href="https://docs.mainwp.com/dashboard/overview/manage-extensions#remove-unneeded-add-ons" target="_blank"><i class="fa fa-book"></i> Remove Add-on(s)</a></div> <?php // NOSONAR - noopener - open safe. ?>
903 + </div>
904 + <?php
905 + /**
906 + * Action: mainwp_extensions_help_item
907 + *
908 + * Fires at the bottom of the help articles list in the Help sidebar on the Extensions page.
909 + *
910 + * Suggested HTML markup:
911 + *
912 + * <div class="item"><a href="Your custom URL">Your custom text</a></div>
913 + *
914 + * @since 5.2
915 + */
916 + do_action( 'mainwp_extensions_help_item' );
917 + }
918 + }
814 919 }