PluginProbe
Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits / trunk
Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits vtrunk
3.2.2 3.2.3 3.2.1 3.2.0 3.1.9 3.1.8 3.1.7 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.9 trunk 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.3 1.1.4 1.1.5 All 174 releases
master-addons / lib / Recommended.php

Recommended.php in Master Addons for Elementor – Elementor Addons, Widgets, Mega Menu Builder, Popup Builder, Widget Builder & Template Kits trunk, at lib/Recommended.php

502 lines 16.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace MasterAddons\Lib;
4
5 // No, Direct access Sir !!!
6 if (!defined('ABSPATH')) {
7 exit;
8 }
9
10 /*
11 * Recommended global class
12 */
13
14 if (!class_exists('Recommended')) {
15
16 /**
17 * Recommended Class
18 *
19 * Jewel Theme <support@jeweltheme.com>
20 */
21 class Recommended
22 {
23
24
25 public $menu_items;
26 public $plugins_list;
27 public $sub_menu;
28 public $menu_order;
29
30
31 /**
32 * Constructor method
33 *
34 * @param integer $menu_order .
35 * @author Jewel Theme <support@jeweltheme.com>
36 */
37 public function __construct($menu_order = 99)
38 {
39 $this->menu_order = $menu_order;
40 $this->menu_items = $this->menu_items();
41 $this->plugins_list = $this->plugins_list();
42
43 $this->includes();
44
45 add_action('admin_menu', array($this, 'admin_menu'), $this->menu_order);
46 add_action('wp_ajax_jltma_recommended_upgrade_plugin', array($this, 'jltma_recommended_upgrade_plugin'));
47 add_action('wp_ajax_jltma_recommended_activate_plugin', array($this, 'jltma_recommended_activate_plugin'));
48 }
49
50 /**
51 * Includes
52 *
53 * @author Jewel Theme <support@jeweltheme.com>
54 */
55 public function includes()
56 {
57 if (!function_exists('install_plugin_install_status')) {
58 require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
59 }
60 }
61
62 /**
63 * Exact allowlist of installed plugin files that belong to our known slugs.
64 *
65 * Returns real plugin basenames (e.g. "elementor/elementor.php") taken from the
66 * actual installed plugin set, filtered to the slugs we manage. Used to validate
67 * any $_POST plugin-file value before it reaches activate_plugin()/upgrade(), so
68 * arbitrary input can never select an unrelated plugin file.
69 *
70 * @return string[]
71 */
72 protected function get_allowed_plugin_files()
73 {
74 if (!function_exists('get_plugins')) {
75 require_once ABSPATH . 'wp-admin/includes/plugin.php';
76 }
77
78 $known_slugs = array_values(wp_list_pluck($this->plugins_list, 'slug'));
79 $allowed = array();
80
81 foreach (array_keys(get_plugins()) as $plugin_file) {
82 if (in_array(dirname($plugin_file), $known_slugs, true)) {
83 $allowed[] = $plugin_file;
84 }
85 }
86
87 return $allowed;
88 }
89
90 /**
91 * Menu Items
92 *
93 * @author Jewel Theme <support@jeweltheme.com>
94 */
95 public function menu_items()
96 {
97 return array();
98 }
99
100 /**
101 * Plugins list
102 *
103 * @author Jewel Theme <support@jeweltheme.com>
104 */
105 public function plugins_list()
106 {
107 return array();
108 }
109
110 /**
111 * Admin submenu
112 */
113 public function admin_menu()
114 {
115 }
116
117 /**
118 * Render recommended plugins body
119 */
120 public function render_recommended_plugins()
121 { ?>
122 <div class='jltma-recommended-wrapper'>
123 <?php $this->header(); ?>
124 <?php $this->body(); ?>
125 </div>
126 <style>
127 /* Hide WordPress default admin notices on this page */
128 .jltma-recommended-wrapper ~ .notice,
129 .jltma-recommended-wrapper ~ .error,
130 .jltma-recommended-wrapper ~ .updated {
131 display: none;
132 }
133 </style>
134 <?php
135 }
136
137 /**
138 * Header
139 */
140 public function header()
141 {
142 ?>
143 <div class='jltma-recommended-header'>
144 <div class='jltma-recommended-header-top'>
145 <div class='jltma-recommended-title'>
146 <h2><?php echo esc_html__('Recommended Plugins', 'master-addons'); ?></h2>
147 <p><?php echo esc_html__('Starter and recommended plugins to extend your WordPress experience.', 'master-addons'); ?></p>
148 </div>
149 <div class='jltma-recommended-search'>
150 <form class="search-form jltma-search-plugins" method="get">
151 <input type="hidden" name="tab" value="search">
152 <label class="screen-reader-text" for="search-plugins">
153 <?php echo esc_html__('Search Plugins', 'master-addons'); ?>
154 </label>
155 <span class="jltma-search-icon">
156 <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
157 </span>
158 <input type="search" name="s" id="search-plugins" value="" class="jltma-search-input" placeholder="<?php echo esc_html__('Search plugins...', 'master-addons'); ?>">
159 </form>
160 </div>
161 </div>
162 <div class='jltma-recommended-tabs'>
163 <ul class="jltma-filter-links">
164 <?php
165 $i = 0;
166 foreach ($this->menu_items as $menu) {
167 $class = str_replace(' ', '-', strtolower($menu['key']));
168 ?>
169 <li>
170 <a href="#" class="jltma-tab-link <?php echo esc_attr(0 === $i ? 'current' : ''); ?>" data-type="<?php echo esc_attr($menu['key']); ?>"><?php echo esc_html($menu['label']); ?></a>
171 </li>
172 <?php
173 $i++;
174 }
175 ?>
176 </ul>
177 </div>
178 </div>
179 <?php
180 }
181
182 /**
183 * Body
184 */
185 public function body()
186 {
187 ?>
188 <div class="jltma-plugins-grid">
189 <?php $this->plugins(); ?>
190 </div>
191 <?php
192 }
193
194 /**
195 * Body
196 */
197 public function plugins()
198 {
199 foreach ($this->plugins_list as $key => $plugin) {
200 $plugin_api = (object) $plugin;
201 if (!isset($plugin_api->version)) {
202 $plugin_api->version = '';
203 }
204 $install_status = \install_plugin_install_status($plugin_api);
205 $classes = implode(' ', $plugin['type']);
206
207 $more_details = self_admin_url(
208 'plugin-install.php?tab=plugin-information&amp;plugin=' . esc_attr($plugin['slug']) .
209 '&amp;TB_iframe=true&amp;width=600&amp;height=550'
210 );
211 ?>
212 <div class="jltma-plugin-card <?php echo esc_attr($classes); ?>" data-plugin="<?php echo esc_attr($key); ?>">
213 <div class="jltma-plugin-card-body">
214 <div class="jltma-plugin-icon">
215 <img src="<?php echo esc_url($plugin['icon']); ?>" alt="<?php echo esc_attr($plugin['name']); ?>">
216 </div>
217 <div class="jltma-plugin-info">
218 <h3 class="jltma-plugin-name">
219 <a href="<?php echo esc_url($more_details); ?>" class="thickbox open-plugin-details-modal"><?php echo esc_html($plugin['name']); ?></a>
220 </h3>
221 <p class="jltma-plugin-desc"><?php echo wp_kses_post($plugin['short_description']); ?></p>
222 </div>
223 </div>
224 <div class="jltma-plugin-card-footer">
225 <span class="jltma-plugin-status">
226 <?php
227 if ('install' === $install_status['status']) {
228 ?>
229 <span class="jltma-status-badge jltma-status-not-installed" data-plugin-url="<?php echo esc_attr($plugin['download_link']); ?>"><?php echo esc_html__('Not Installed', 'master-addons'); ?></span>
230 <?php
231 } elseif ('update_available' === $install_status['status']) {
232 if (is_plugin_active($install_status['file'])) {
233 ?>
234 <span class="jltma-status-badge jltma-status-active"><?php echo esc_html__('Active', 'master-addons'); ?></span>
235 <?php
236 } else {
237 ?>
238 <span class="jltma-status-badge jltma-status-inactive" data-plugin-file="<?php echo esc_attr($install_status['file']); ?>"><?php echo esc_html__('Inactive', 'master-addons'); ?></span>
239 <?php
240 }
241 } elseif (('latest_installed' === $install_status['status']) || ('newer_installed' === $install_status['status'])) {
242 if (is_plugin_active($install_status['file'])) {
243 ?>
244 <span class="jltma-status-badge jltma-status-active"><?php echo esc_html__('Active', 'master-addons'); ?></span>
245 <?php
246 } else {
247 ?>
248 <span class="jltma-status-badge jltma-status-inactive" data-plugin-file="<?php echo esc_attr($install_status['file']); ?>"><?php echo esc_html__('Inactive', 'master-addons'); ?></span>
249 <?php
250 }
251 }
252 ?>
253 </span>
254 <div class="jltma-plugin-action">
255 <?php
256 if ('install' === $install_status['status']) {
257 ?>
258 <button class="install-now jltma-btn jltma-btn-primary" data-install-url="<?php echo esc_attr($plugin['download_link']); ?>">
259 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
260 <?php echo esc_html__('Install', 'master-addons'); ?>
261 </button>
262 <?php
263 } elseif ('update_available' === $install_status['status']) {
264 ?>
265 <button class="update-now jltma-btn jltma-btn-warning" data-plugin="<?php echo esc_attr($install_status['file']); ?>" data-slug="<?php echo esc_attr($plugin['slug']); ?>" data-update-url="<?php echo esc_attr($install_status['url']); ?>">
266 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 2v6h-6"/><path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M3 22v-6h6"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/></svg>
267 <?php echo esc_html__('Update', 'master-addons'); ?>
268 </button>
269 <?php
270 } elseif (('latest_installed' === $install_status['status']) || ('newer_installed' === $install_status['status'])) {
271 if (is_plugin_active($install_status['file'])) {
272 ?>
273 <button type="button" class="jltma-btn jltma-btn-activated" disabled="disabled">
274 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
275 <?php echo esc_html__('Activated', 'master-addons'); ?>
276 </button>
277 <?php
278 } elseif (current_user_can('activate_plugin', $install_status['file'])) {
279 ?>
280 <button class="activate-now jltma-btn jltma-btn-success" data-plugin-file="<?php echo esc_attr($install_status['file']); ?>">
281 <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>
282 <?php echo esc_html__('Activate', 'master-addons'); ?>
283 </button>
284 <?php
285 } else {
286 ?>
287 <button type="button" class="jltma-btn jltma-btn-activated" disabled="disabled">
288 <?php echo esc_html__('Installed', 'master-addons'); ?>
289 </button>
290 <?php
291 }
292 }
293 ?>
294 </div>
295 </div>
296 </div>
297 <?php
298 }
299 }
300
301 /**
302 * Activate Plugins
303 *
304 * @author Jewel Theme <support@jeweltheme.com>
305 */
306 public function jltma_recommended_activate_plugin()
307 {
308 try {
309 if (isset($_POST['file'])) {
310 $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
311
312 if (!wp_verify_nonce($nonce, 'jltma_recommended_nonce')) {
313 wp_send_json_error(array('mess' => __('Nonce is invalid', 'master-addons')));
314 }
315
316 if ((is_multisite() && !is_network_admin()) || !current_user_can('install_plugins')) {
317 wp_send_json_error(array('mess' => __('Invalid access', 'master-addons')));
318 }
319
320 $file = sanitize_text_field(wp_unslash($_POST['file']));
321
322 // Enforce an exact allowlist of real installed plugin files that
323 // belong to our known slugs. Arbitrary input (or a crafted basename
324 // whose dirname happens to match a slug) must never reach
325 // activate_plugin(); only an exact installed plugin file passes.
326 if (!in_array($file, $this->get_allowed_plugin_files(), true)) {
327 wp_send_json_error(array('mess' => __('Invalid plugin', 'master-addons')));
328 }
329
330 $result = activate_plugin($file);
331
332 if (is_wp_error($result)) {
333 wp_send_json_error(
334 array(
335 'mess' => $result->get_error_message(),
336 )
337 );
338 }
339 wp_send_json_success(
340 array(
341 'mess' => __('Activate success', 'master-addons'),
342 )
343 );
344 }
345 } catch (\Exception $ex) {
346 wp_send_json_error(
347 array(
348 'mess' => $ex->getMessage(),
349 )
350 );
351 } catch (\Error $ex) {
352 wp_send_json_error(
353 array(
354 'mess' => $ex->getMessage(),
355 )
356 );
357 }
358 }
359
360 /**
361 * Upgrade Plugins required Libraries
362 *
363 * @author Jewel Theme <support@jeweltheme.com>
364 */
365 public function jltma_recommended_upgrade_plugin()
366 {
367 try {
368 require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
369 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
370 require_once ABSPATH . 'wp-admin/includes/class-wp-ajax-upgrader-skin.php';
371 require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
372
373 if (isset($_POST['plugin'])) {
374 $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
375
376 if (!wp_verify_nonce($nonce, 'jltma_recommended_nonce')) {
377 wp_send_json_error(array('mess' => __('Nonce is invalid', 'master-addons')));
378 }
379
380 if ((is_multisite() && !is_network_admin()) || !current_user_can('install_plugins')) {
381 wp_send_json_error(array('mess' => __('Invalid access', 'master-addons')));
382 }
383
384 $plugin = sanitize_text_field(wp_unslash($_POST['plugin']));
385 $type = isset($_POST['type']) ? sanitize_text_field(wp_unslash($_POST['type'])) : 'install';
386
387 // Validate against an exact allowlist that depends on the operation:
388 // - install: $plugin is a package source; must be exactly one of our
389 // known download links.
390 // - upgrade: $plugin is a plugin file; must be exactly one of the real
391 // installed plugin files under our known slugs.
392 // dirname()-based matching is intentionally NOT used — it would accept a
393 // crafted value whose directory merely resembles a known slug.
394 if ('install' === $type) {
395 $plugin_links = array_values(wp_list_pluck($this->plugins_list, 'download_link'));
396 if (!in_array($plugin, $plugin_links, true)) {
397 wp_send_json_error(array('mess' => __('Invalid plugin', 'master-addons')));
398 }
399 } else {
400 if (!in_array($plugin, $this->get_allowed_plugin_files(), true)) {
401 wp_send_json_error(array('mess' => __('Invalid plugin', 'master-addons')));
402 }
403 }
404
405 $skin = new \WP_Ajax_Upgrader_Skin();
406 $upgrader = new \Plugin_Upgrader($skin);
407
408 if ('install' === $type) {
409 $result = $upgrader->install($plugin);
410
411 if (is_wp_error($result)) {
412 wp_send_json_error(
413 array(
414 'mess' => $result->get_error_message(),
415 )
416 );
417 }
418 $args = array(
419 'slug' => $upgrader->result['destination_name'],
420 'fields' => array(
421 'short_description' => true,
422 'icons' => true,
423 'banners' => false,
424 'added' => false,
425 'reviews' => false,
426 'sections' => false,
427 'requires' => false,
428 'rating' => false,
429 'ratings' => false,
430 'downloaded' => false,
431 'last_updated' => false,
432 'added' => false,
433 'tags' => false,
434 'compatibility' => false,
435 'homepage' => false,
436 'donate_link' => false,
437 ),
438 );
439 $plugin_data = plugins_api('plugin_information', $args);
440
441 if ($plugin_data && !is_wp_error($plugin_data)) {
442 $install_status = \install_plugin_install_status($plugin_data);
443 $active_plugin = activate_plugin($install_status['file']);
444
445 if (is_wp_error($active_plugin)) {
446 wp_send_json_error(
447 array(
448 'mess' => $active_plugin->get_error_message(),
449 )
450 );
451 } else {
452 wp_send_json_success(
453 array(
454 'mess' => __('Install success', 'master-addons'),
455 )
456 );
457 }
458 } else {
459 wp_send_json_error(
460 array(
461 'mess' => 'Error',
462 )
463 );
464 }
465 } else {
466 $is_active = is_plugin_active($plugin);
467 $result = $upgrader->upgrade($plugin);
468
469 if (is_wp_error($result)) {
470 wp_send_json_error(
471 array(
472 'mess' => $result->get_error_message(),
473 )
474 );
475 } else {
476 activate_plugin($plugin);
477 wp_send_json_success(
478 array(
479 'mess' => __('Update success', 'master-addons'),
480 'active' => $is_active,
481 )
482 );
483 }
484 }
485 }
486 } catch (\Exception $ex) {
487 wp_send_json_error(
488 array(
489 'mess' => $ex->getMessage(),
490 )
491 );
492 } catch (\Error $ex) {
493 wp_send_json_error(
494 array(
495 'mess' => $ex->getMessage(),
496 )
497 );
498 }
499 }
500 }
501 }
502