PluginProbe ʕ •ᴥ•ʔ
Code Manager / 1.0.13
Code Manager v1.0.13
1.0.48 1.0.47 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.19 1.0.2 1.0.20 1.0.21 1.0.22 1.0.23 1.0.24 1.0.25 1.0.26 1.0.27 1.0.28 1.0.3 1.0.30 1.0.31 1.0.32 1.0.33 1.0.34 1.0.35 1.0.36 1.0.37 1.0.38 1.0.39 1.0.4 1.0.40 1.0.41 1.0.42 1.0.43 1.0.44 1.0.45 1.0.46 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9
code-manager / freemius / templates / add-ons.php
code-manager / freemius / templates Last commit date
account 4 years ago debug 4 years ago forms 4 years ago js 4 years ago partials 4 years ago plugin-info 4 years ago account.php 4 years ago add-ons.php 4 years ago add-trial-to-pricing.php 4 years ago admin-notice.php 4 years ago ajax-loader.php 4 years ago auto-installation.php 4 years ago checkout.php 4 years ago connect.php 4 years ago contact.php 4 years ago debug.php 4 years ago email.php 4 years ago firewall-issues-js.php 4 years ago gdpr-optin-js.php 4 years ago index.php 4 years ago plugin-icon.php 4 years ago powered-by.php 4 years ago pricing.php 4 years ago secure-https-header.php 4 years ago sticky-admin-notice-js.php 4 years ago tabs-capture-js.php 4 years ago tabs.php 4 years ago
add-ons.php
502 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
495 $params = array(
496 'page' => 'addons',
497 'module_id' => $fs->get_id(),
498 'module_type' => $fs->get_module_type(),
499 'module_slug' => $slug,
500 'module_version' => $fs->get_plugin_version(),
501 );
502 fs_require_template( 'powered-by.php', $params );