PluginProbe ʕ •ᴥ•ʔ
Spider Elements – Premium Elementor Widgets & Addons Library / 1.5.0
Spider Elements – Premium Elementor Widgets & Addons Library v1.5.0
trunk 1.0.0 1.1.0 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.7.0 1.8.0 1.9.0
spider-elements / includes / freemius / templates / add-ons.php
spider-elements / includes / freemius / templates Last commit date
account 1 year ago checkout 1 year ago connect 1 year ago debug 1 year ago forms 1 year ago js 1 year ago partials 1 year ago plugin-info 1 year ago account.php 1 year ago add-ons.php 1 year ago add-trial-to-pricing.php 1 year ago admin-notice.php 1 year ago ajax-loader.php 1 year ago api-connectivity-message-js.php 1 year ago auto-installation.php 1 year ago checkout.php 1 year ago clone-resolution-js.php 1 year ago connect.php 1 year ago contact.php 1 year ago debug.php 1 year ago email.php 1 year ago gdpr-optin-js.php 1 year ago index.php 1 year ago plugin-icon.php 1 year ago pricing.php 1 year ago secure-https-header.php 1 year ago sticky-admin-notice-js.php 1 year ago tabs-capture-js.php 1 year ago tabs.php 1 year ago
add-ons.php
494 lines
1 <?php
2 /**
3 * @package Freemius
4 * @copyright Copyright (c) 2015, Freemius, Inc.
5 * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
6 * @since 1.0.3
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 /**
14 * @var array $VARS
15 * @var Freemius
16 */
17 $fs = freemius( $VARS['id'] );
18
19 $slug = $fs->get_slug();
20
21 $open_addon_slug = fs_request_get( 'slug' );
22
23 $open_addon = false;
24
25 $is_data_debug_mode = $fs->is_data_debug_mode();
26 $is_whitelabeled = $fs->is_whitelabeled();
27
28 /**
29 * @var FS_Plugin[]
30 */
31 $addons = $fs->get_addons();
32
33 $has_addons = ( is_array( $addons ) && 0 < count( $addons ) );
34
35 $account_addon_ids = $fs->get_updated_account_addons();
36
37 $download_latest_text = fs_text_x_inline( 'Download Latest', 'as download latest version', 'download-latest', $slug );
38 $view_details_text = fs_text_inline( 'View details', 'view-details', $slug );
39
40 $has_tabs = $fs->_add_tabs_before_content();
41
42 $fs_blog_id = ( is_multisite() && ! is_network_admin() ) ?
43 get_current_blog_id() :
44 0;
45 ?>
46 <div id="fs_addons" class="wrap fs-section">
47 <?php if ( ! $has_tabs ) : ?>
48 <h2><?php echo esc_html( sprintf( fs_text_inline( 'Add Ons for %s', 'add-ons-for-x', $slug ), $fs->get_plugin_name() ) ) ?></h2>
49 <?php endif ?>
50
51 <?php $fs->do_action( 'addons/after_title' ) ?>
52
53 <div id="poststuff">
54 <?php if ( ! $has_addons ) : ?>
55 <h3><?php echo esc_html( sprintf(
56 '%s... %s',
57 fs_text_x_inline( 'Oops', 'exclamation', 'oops', $slug ),
58 fs_text_inline( 'We couldn\'t load the add-ons list. It\'s probably an issue on our side, please try to come back in few minutes.', 'add-ons-missing', $slug )
59 ) ) ?></h3>
60 <?php endif ?>
61 <ul class="fs-cards-list">
62 <?php if ( $has_addons ) : ?>
63 <?php
64 $plans_and_pricing_by_addon_id = $fs->_get_addons_plans_and_pricing_map_by_id();
65
66 $active_plugins_directories_map = Freemius::get_active_plugins_directories_map( $fs_blog_id );
67 ?>
68 <?php
69 $hide_all_addons_data = false;
70
71 if ( $fs->is_whitelabeled_by_flag() ) {
72 $hide_all_addons_data = true;
73
74 $addon_ids = $fs->get_updated_account_addons();
75 $installed_addons = $fs->get_installed_addons();
76 foreach ( $installed_addons as $fs_addon ) {
77 $addon_ids[] = $fs_addon->get_id();
78 }
79
80 if ( ! empty( $addon_ids ) ) {
81 $addon_ids = array_unique( $addon_ids );
82 }
83
84 foreach ( $addon_ids as $addon_id ) {
85 $addon = $fs->get_addon( $addon_id );
86
87 if ( ! is_object( $addon ) ) {
88 continue;
89 }
90
91 $addon_storage = FS_Storage::instance( WP_FS__MODULE_TYPE_PLUGIN, $addon->slug );
92
93 if ( ! $addon_storage->is_whitelabeled ) {
94 $hide_all_addons_data = false;
95 break;
96 }
97
98 if ( $is_data_debug_mode ) {
99 $is_whitelabeled = false;
100 }
101 }
102 }
103 ?>
104 <?php foreach ( $addons as $addon ) : ?>
105 <?php
106 $basename = $fs->get_addon_basename( $addon->id );
107
108 $is_addon_installed = file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $basename ) );
109
110 if ( ! $is_addon_installed && $hide_all_addons_data ) {
111 continue;
112 }
113
114 $is_addon_activated = $is_addon_installed ?
115 $fs->is_addon_activated( $addon->id ) :
116 false;
117
118 $is_plugin_active = (
119 $is_addon_activated ||
120 isset( $active_plugins_directories_map[ dirname( $basename ) ] )
121 );
122
123 $open_addon = ( $open_addon || ( $open_addon_slug === $addon->slug ) );
124
125 $price = 0;
126 $has_trial = false;
127 $has_free_plan = false;
128 $has_paid_plan = false;
129
130 if ( isset( $plans_and_pricing_by_addon_id[$addon->id] ) ) {
131 $plans = $plans_and_pricing_by_addon_id[$addon->id];
132
133 if ( is_array( $plans ) && 0 < count( $plans ) ) {
134 foreach ( $plans as $plan ) {
135 if ( ! isset( $plan->pricing ) ||
136 ! is_array( $plan->pricing ) ||
137 0 == count( $plan->pricing )
138 ) {
139 // No pricing means a free plan.
140 $has_free_plan = true;
141 continue;
142 }
143
144
145 $has_paid_plan = true;
146 $has_trial = $has_trial || ( is_numeric( $plan->trial_period ) && ( $plan->trial_period > 0 ) );
147
148 $min_price = 999999;
149 foreach ( $plan->pricing as $pricing ) {
150 $pricing = new FS_Pricing( $pricing );
151
152 if ( ! $pricing->is_usd() ) {
153 /**
154 * Skip non-USD pricing.
155 *
156 * @author Leo Fajardo (@leorw)
157 * @since 2.3.1
158 */
159 continue;
160 }
161
162 if ( $pricing->has_annual() ) {
163 $min_price = min( $min_price, $pricing->annual_price );
164 } else if ( $pricing->has_monthly() ) {
165 $min_price = min( $min_price, 12 * $pricing->monthly_price );
166 }
167 }
168
169 if ( $min_price < 999999 ) {
170 $price = $min_price;
171 }
172
173 }
174 }
175
176 if ( ! $has_paid_plan && ! $has_free_plan ) {
177 continue;
178 }
179 }
180 ?>
181 <li class="fs-card fs-addon" data-slug="<?php echo $addon->slug ?>">
182 <?php
183 $view_details_link = sprintf( '<a href="%s" aria-label="%s" data-title="%s"',
184 esc_url( network_admin_url( 'plugin-install.php?fs_allow_updater_and_dialog=true' . ( ! empty( $fs_blog_id ) ? '&fs_blog_id=' . $fs_blog_id : '' ) . '&tab=plugin-information&parent_plugin_id=' . $fs->get_id() . '&plugin=' . $addon->slug .
185 '&TB_iframe=true&width=600&height=550' ) ),
186 esc_attr( sprintf( fs_text_inline( 'More information about %s', 'more-information-about-x', $slug ), $addon->title ) ),
187 esc_attr( $addon->title )
188 ) . ' class="thickbox%s">%s</a>';
189
190 echo sprintf(
191 $view_details_link,
192 /**
193 * Additional class.
194 *
195 * @author Leo Fajardo (@leorw)
196 * @since 2.2.4
197 */
198 ' fs-overlay',
199 /**
200 * Set the view details link text to an empty string since it is an overlay that
201 * doesn't really need a text and whose purpose is to open the details dialog when
202 * the card is clicked.
203 *
204 * @author Leo Fajardo (@leorw)
205 * @since 2.2.4
206 */
207 ''
208 );
209 ?>
210 <?php
211 if ( is_null( $addon->info ) ) {
212 $addon->info = new stdClass();
213 }
214 if ( ! isset( $addon->info->card_banner_url ) ) {
215 $addon->info->card_banner_url = '//dashboard.freemius.com/assets/img/marketing/blueprint-300x100.jpg';
216 }
217 if ( ! isset( $addon->info->short_description ) ) {
218 $addon->info->short_description = 'What\'s the one thing your add-on does really, really well?';
219 }
220 ?>
221 <div class="fs-inner">
222 <ul>
223 <li class="fs-card-banner"
224 style="background-image: url('<?php echo $addon->info->card_banner_url ?>');"><?php
225 if ( $is_plugin_active || $is_addon_installed ) {
226 echo sprintf(
227 '<span class="fs-badge fs-installed-addon-badge">%s</span>',
228 esc_html( $is_plugin_active ?
229 fs_text_x_inline( 'Active', 'active add-on', 'active-addon', $slug ) :
230 fs_text_x_inline( 'Installed', 'installed add-on', 'installed-addon', $slug )
231 )
232 );
233 }
234 ?></li>
235 <!-- <li class="fs-tag"></li> -->
236 <li class="fs-title"><?php echo $addon->title ?></li>
237 <li class="fs-offer">
238 <span
239 class="fs-price"><?php
240 if ( $is_whitelabeled ) {
241 echo '&nbsp;';
242 } else {
243 $descriptors = array();
244
245 if ($has_free_plan)
246 $descriptors[] = fs_text_inline( 'Free', 'free', $slug );
247 if ($has_paid_plan && $price > 0)
248 $descriptors[] = '$' . number_format( $price, 2 );
249 if ($has_trial)
250 $descriptors[] = fs_text_x_inline( 'Trial', 'trial period', 'trial', $slug );
251
252 echo implode(' - ', $descriptors);
253
254 } ?></span>
255 </li>
256 <li class="fs-description"><?php echo ! empty( $addon->info->short_description ) ? $addon->info->short_description : 'SHORT DESCRIPTION' ?></li>
257 <?php
258 $is_free_only_wp_org_compliant = ( ! $has_paid_plan && $addon->is_wp_org_compliant );
259
260 $is_allowed_to_install = (
261 $fs->is_allowed_to_install() ||
262 $is_free_only_wp_org_compliant
263 );
264
265 $show_premium_activation_or_installation_action = true;
266
267 if ( ! in_array( $addon->id, $account_addon_ids ) ) {
268 $show_premium_activation_or_installation_action = false;
269 } else if ( $is_addon_installed ) {
270 /**
271 * If any add-on's version (free or premium) is installed, check if the
272 * premium version can be activated and show the relevant action. Otherwise,
273 * show the relevant action for the free version.
274 *
275 * @author Leo Fajardo (@leorw)
276 * @since 2.4.5
277 */
278 $fs_addon = $is_addon_activated ?
279 $fs->get_addon_instance( $addon->id ) :
280 null;
281
282 $premium_plugin_basename = is_object( $fs_addon ) ?
283 $fs_addon->premium_plugin_basename() :
284 "{$addon->premium_slug}/{$addon->slug}.php";
285
286 if (
287 ( $is_addon_activated && $fs_addon->is_premium() ) ||
288 file_exists( fs_normalize_path( WP_PLUGIN_DIR . '/' . $premium_plugin_basename ) )
289 ) {
290 $basename = $premium_plugin_basename;
291 }
292
293 $show_premium_activation_or_installation_action = (
294 ( ! $is_addon_activated || ! $fs_addon->is_premium() ) &&
295 /**
296 * This check is needed for cases when an active add-on doesn't have an
297 * associated Freemius instance.
298 *
299 * @author Leo Fajardo (@leorw)
300 * @since 2.4.5
301 */
302 ( ! $is_plugin_active )
303 );
304 }
305 ?>
306 <?php if ( ! $show_premium_activation_or_installation_action ) : ?>
307 <li class="fs-cta"><a class="button"><?php echo esc_html( $view_details_text ) ?></a></li>
308 <?php else : ?>
309 <?php
310 $latest_download_local_url = $is_free_only_wp_org_compliant ?
311 null :
312 $fs->_get_latest_download_local_url( $addon->id );
313 ?>
314
315 <li class="fs-cta fs-dropdown">
316 <div class="button-group">
317 <?php if ( $is_allowed_to_install ) : ?>
318 <?php
319 if ( ! $is_addon_installed ) {
320 echo sprintf(
321 '<a class="button button-primary" href="%s">%s</a>',
322 wp_nonce_url( self_admin_url( 'update.php?' . ( ( $has_paid_plan || ! $addon->is_wp_org_compliant ) ? 'fs_allow_updater_and_dialog=true&' : '' ) . 'action=install-plugin&plugin=' . $addon->slug ), 'install-plugin_' . $addon->slug ),
323 fs_esc_html_inline( 'Install Now', 'install-now', $slug )
324 );
325 } else {
326 echo sprintf(
327 '<a class="button button-primary edit" href="%s" title="%s" target="_parent">%s</a>',
328 wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $basename, 'activate-plugin_' . $basename ),
329 fs_esc_attr_inline( 'Activate this add-on', 'activate-this-addon', $addon->slug ),
330 fs_text_inline( 'Activate', 'activate', $addon->slug )
331 );
332 }
333 ?>
334 <?php else : ?>
335 <a target="_blank" rel="noopener" class="button button-primary" href="<?php echo $latest_download_local_url ?>"><?php echo esc_html( $download_latest_text ) ?></a>
336 <?php endif ?>
337 <div class="button button-primary fs-dropdown-arrow-button"><span class="fs-dropdown-arrow"></span><ul class="fs-dropdown-list" style="display: none">
338 <?php if ( $is_allowed_to_install && ! empty( $latest_download_local_url ) ) : ?>
339 <li><a target="_blank" rel="noopener" href="<?php echo $latest_download_local_url ?>"><?php echo esc_html( $download_latest_text ) ?></a></li>
340 <?php endif ?>
341 <li><?php
342 echo sprintf(
343 $view_details_link,
344 /**
345 * No additional class.
346 *
347 * @author Leo Fajardo (@leorw)
348 * @since 2.2.4
349 */
350 '',
351 /**
352 * Set the view details link text to a non-empty string since it is an
353 * item in the dropdown list and the text should be visible.
354 *
355 * @author Leo Fajardo (@leorw)
356 * @since 2.2.4
357 */
358 esc_html( $view_details_text )
359 );
360 ?></li>
361 </ul></div>
362 </div>
363 </li>
364 <?php endif ?>
365 </ul>
366 </div>
367 </li>
368 <?php endforeach ?>
369 <?php endif ?>
370 </ul>
371 </div>
372
373 <?php $fs->do_action( 'addons/after_addons' ) ?>
374 </div>
375 <script type="text/javascript">
376 (function( $, undef ) {
377 <?php if ( $open_addon ) : ?>
378
379 var interval = setInterval(function () {
380 // Open add-on information page.
381 <?php
382 /**
383 * @author Vova Feldman
384 *
385 * This code does NOT expose an XSS vulnerability because:
386 * 1. This page only renders for admins, so if an attacker manage to get
387 * admin access, they can do more harm.
388 * 2. This code won't be rendered unless $open_addon_slug matches any of
389 * the plugin's add-ons slugs.
390 */
391 ?>
392 $('.fs-card[data-slug=<?php echo $open_addon_slug ?>] a').click();
393 if ($('#TB_iframeContent').length > 0) {
394 clearInterval(interval);
395 interval = null;
396 }
397 }, 200);
398
399 <?php else : ?>
400
401 $( '.fs-card.fs-addon' )
402 .mouseover(function() {
403 var $this = $( this );
404
405 $this.find( '.fs-cta .button' ).addClass( 'button-primary' );
406
407 if ( 0 === $this.find( '.fs-dropdown-arrow-button.active' ).length ) {
408 /**
409 * When hovering over a card, close the dropdown on any other card.
410 *
411 * @author Leo Fajardo (@leorw)
412 * @since 2.2.4
413 */
414 toggleDropdown();
415 }
416 }).mouseout(function( evt ) {
417 var $relatedTarget = $( evt.relatedTarget );
418
419 if ( 0 !== $relatedTarget.parents( '.fs-addon' ).length ) {
420 return true;
421 }
422
423 var $this = $( this );
424
425 /**
426 * Set the color of the "View details" button to "secondary".
427 *
428 * @author Leo Fajardo (@leorw)
429 * @since 2.2.4
430 */
431 $this.find( '.fs-cta .button' ).filter(function() {
432 /**
433 * Keep the "primary" color of the dropdown arrow button, "Install Now" button, and
434 * "Download Latest" button.
435
436 * @author Leo Fajardo (@leorw)
437 * @since 2.2.4
438 */
439 return $( this ).parent().is( ':not(.button-group)' );
440 }).removeClass('button-primary');
441
442 toggleDropdown( $this.find( '.fs-dropdown' ), false );
443 }).find( 'a.thickbox, .button:not(.fs-dropdown-arrow-button)' ).click(function() {
444 toggleDropdown();
445 });
446
447 <?php endif ?>
448
449 var $dropdowns = $( '.fs-dropdown' );
450 if ( 0 !== $dropdowns.length ) {
451 $dropdowns.find( '.fs-dropdown-arrow-button' ).click(function() {
452 var $this = $( this ),
453 $dropdown = $this.parents( '.fs-dropdown' );
454
455 toggleDropdown( $dropdown, ! $dropdown.hasClass( 'active' ) );
456 });
457 }
458
459 /**
460 * Returns the default state of the dropdown arrow button and hides the dropdown list.
461 *
462 * @author Leo Fajardo (@leorw)
463 * @since 2.2.4
464 *
465 * @param {(Object|undefined)} [$dropdown]
466 * @param {(Boolean|undefined)} [state]
467 */
468 function toggleDropdown( $dropdown, state ) {
469 if ( undef === $dropdown ) {
470 var $activeDropdown = $dropdowns.find( '.active' );
471 if ( 0 !== $activeDropdown.length ) {
472 $dropdown = $activeDropdown;
473 }
474 }
475
476 if ( undef === $dropdown ) {
477 return;
478 }
479
480 if ( undef === state ) {
481 state = false;
482 }
483
484 $dropdown.toggleClass( 'active', state );
485 $dropdown.find( '.fs-dropdown-list' ).toggle( state );
486 $dropdown.find( '.fs-dropdown-arrow-button' ).toggleClass( 'active', state );
487 }
488 })( jQuery );
489 </script>
490 <?php
491 if ( $has_tabs ) {
492 $fs->_add_tabs_after_content();
493 }
494