PluginProbe
Buttonizer – Floating Menus, Sticky Buttons, & Popup Builder / 1.1
Buttonizer – Floating Menus, Sticky Buttons, & Popup Builder v1.1
3.6.0 3.5.0 trunk 1.0.10 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.6.1 1.0.7 1.0.8 1.0.9 1.1 1.1.1 1.2 1.3 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.5 1.5.1 All 110 releases
buttonizer-multifunctional-button / freemius / includes / fs-plugin-info-dialog.php

fs-plugin-info-dialog.php in Buttonizer – Floating Menus, Sticky Buttons, & Popup Builder 1.1, at freemius/includes/fs-plugin-info-dialog.php

942 lines 32.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package Freemius
4 * @copyright Copyright (c) 2015, Freemius, Inc.
5 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
6 * @since 1.0.6
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 /**
14 * Class FS_Plugin_Info_Dialog
15 *
16 * @author Vova Feldman (@svovaf)
17 * @since 1.1.7
18 */
19 class FS_Plugin_Info_Dialog {
20 /**
21 * @since 1.1.7
22 *
23 * @var FS_Logger
24 */
25 private $_logger;
26
27 /**
28 * @since 1.1.7
29 *
30 * @var Freemius
31 */
32 private $_fs;
33
34 function __construct( Freemius $fs ) {
35 $this->_fs = $fs;
36
37 $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_' . $fs->get_slug() . '_info', WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
38
39 // Remove default plugin information action.
40 remove_all_actions( 'install_plugins_pre_plugin-information' );
41
42 // Override action with custom plugins function for add-ons.
43 add_action( 'install_plugins_pre_plugin-information', array( &$this, 'install_plugin_information' ) );
44
45 // Override request for plugin information for Add-ons.
46 add_filter(
47 'fs_plugins_api',
48 array( &$this, '_get_addon_info_filter' ),
49 WP_FS__DEFAULT_PRIORITY, 3 );
50 }
51
52 /**
53 * Generate add-on plugin information.
54 *
55 * @author Vova Feldman (@svovaf)
56 * @since 1.0.6
57 *
58 * @param array $data
59 * @param string $action
60 * @param object|null $args
61 *
62 * @return array|null
63 */
64 function _get_addon_info_filter( $data, $action = '', $args = null ) {
65 $this->_logger->entrance();
66
67 $parent_plugin_id = fs_request_get( 'parent_plugin_id', false );
68
69 if ( $this->_fs->get_id() != $parent_plugin_id ||
70 ( 'plugin_information' !== $action ) ||
71 ! isset( $args->slug )
72 ) {
73 return $data;
74 }
75
76 // Find add-on by slug.
77 $selected_addon = $this->_fs->get_addon_by_slug($args->slug, WP_FS__DEV_MODE);
78
79 if ( false === $selected_addon ) {
80 return $data;
81 }
82
83 if ( ! isset( $selected_addon->info ) ) {
84 // Setup some default info.
85 $selected_addon->info = new stdClass();
86 $selected_addon->info->selling_point_0 = 'Selling Point 1';
87 $selected_addon->info->selling_point_1 = 'Selling Point 2';
88 $selected_addon->info->selling_point_2 = 'Selling Point 3';
89 $selected_addon->info->description = '<p>Tell your users all about your add-on</p>';
90 }
91
92 fs_enqueue_local_style( 'fs_addons', '/admin/add-ons.css' );
93
94 $data = $args;
95
96 $is_free = true;
97
98 // Load add-on pricing.
99 $has_pricing = false;
100 $has_features = false;
101 $plans = false;
102 $plans_result = $this->_fs->get_api_site_or_plugin_scope()->get( "/addons/{$selected_addon->id}/plans.json?type=visible" );
103 if ( ! isset( $plans_result->error ) ) {
104 $plans = $plans_result->plans;
105 if ( is_array( $plans ) ) {
106 for ( $i = 0, $len = count( $plans ); $i < $len; $i ++ ) {
107 $plans[ $i ] = new FS_Plugin_Plan( $plans[ $i ] );
108 $plan = $plans[ $i ];
109
110 $pricing_result = $this->_fs->get_api_site_or_plugin_scope()->get( "/addons/{$selected_addon->id}/plans/{$plan->id}/pricing.json" );
111 if ( ! isset( $pricing_result->error ) ) {
112 // Update plan's pricing.
113 $plan->pricing = $pricing_result->pricing;
114
115 if ( is_array( $plan->pricing ) && ! empty( $plan->pricing ) ) {
116 $is_free = false;
117
118 foreach ( $plan->pricing as &$pricing ) {
119 $pricing = new FS_Pricing( $pricing );
120 }
121 }
122
123 $has_pricing = true;
124 }
125
126 $features_result = $this->_fs->get_api_site_or_plugin_scope()->get( "/addons/{$selected_addon->id}/plans/{$plan->id}/features.json" );
127 if ( ! isset( $features_result->error ) &&
128 is_array( $features_result->features ) &&
129 0 < count( $features_result->features )
130 ) {
131 // Update plan's pricing.
132 $plan->features = $features_result->features;
133
134 $has_features = true;
135 }
136 }
137 }
138 }
139
140 // Fetch latest version from Freemius.
141 $latest = $this->_fs->_fetch_latest_version( $selected_addon->id );
142
143 if ( ! $is_free ) {
144 // If paid add-on, then it's not on wordpress.org
145 $is_wordpress_org = false;
146 } else {
147 // If no versions found, then assume it's a .org plugin.
148 $is_wordpress_org = ( false === $latest );
149 }
150
151 if ( $is_wordpress_org ) {
152 $repo_data = FS_Plugin_Updater::_fetch_plugin_info_from_repository(
153 'plugin_information', (object) array(
154 'slug' => $selected_addon->slug,
155 'is_ssl' => is_ssl(),
156 'fields' => array(
157 'banners' => true,
158 'reviews' => true,
159 'downloaded' => false,
160 'active_installs' => true
161 )
162 ) );
163
164 if ( ! empty( $repo_data ) ) {
165 $data = $repo_data;
166 $data->wp_org_missing = false;
167 } else {
168 // Couldn't find plugin on .org.
169 $is_wordpress_org = false;
170
171 // Plugin is missing, not on Freemius nor WP.org.
172 $data->wp_org_missing = true;
173 }
174 }
175
176 if ( ! $is_wordpress_org ) {
177 $data->checkout_link = $this->_fs->checkout_url();
178 $data->fs_missing = ( false === $latest );
179
180 if ( $is_free ) {
181 $data->download_link = $this->_fs->_get_latest_download_local_url( $selected_addon->id );
182 }
183 }
184
185 if ( ! $is_wordpress_org ) {
186 // Fetch as much as possible info from local files.
187 $plugin_local_data = $this->_fs->get_plugin_data();
188 $data->name = $selected_addon->title;
189 $data->author = $plugin_local_data['Author'];
190 $view_vars = array( 'plugin' => $selected_addon );
191 $data->sections = array(
192 'description' => fs_get_template( '/plugin-info/description.php', $view_vars ),
193 );
194
195 if ( ! empty( $selected_addon->info->banner_url ) ) {
196 $data->banners = array(
197 'low' => $selected_addon->info->banner_url,
198 );
199 }
200
201 if ( ! empty( $selected_addon->info->screenshots ) ) {
202 $view_vars = array(
203 'screenshots' => $selected_addon->info->screenshots,
204 'plugin' => $selected_addon,
205 );
206 $data->sections['screenshots'] = fs_get_template( '/plugin-info/screenshots.php', $view_vars );
207 }
208
209 if ( is_object( $latest ) ) {
210 $data->version = $latest->version;
211 $data->last_updated = ! is_null( $latest->updated ) ? $latest->updated : $latest->created;
212 $data->requires = $latest->requires_platform_version;
213 $data->tested = $latest->tested_up_to_version;
214 } else {
215 // Add dummy version.
216 $data->version = '1.0.0';
217
218 // Add message to developer to deploy the plugin through Freemius.
219 }
220 }
221
222 if ( $has_pricing ) {
223 // Add plans to data.
224 $data->plans = $plans;
225
226 if ( $has_features ) {
227 $view_vars = array(
228 'plans' => $plans,
229 'plugin' => $selected_addon,
230 );
231 $data->sections['features'] = fs_get_template( '/plugin-info/features.php', $view_vars );
232 }
233 }
234
235 $data->is_paid = ! $is_free;
236 $data->external = ! $is_wordpress_org;
237
238 return $data;
239 }
240
241 /**
242 * @author Vova Feldman (@svovaf)
243 * @since 1.1.7
244 *
245 * @param FS_Plugin_Plan $plan
246 *
247 * @return string
248 */
249 private function get_billing_cycle( FS_Plugin_Plan $plan ) {
250 $billing_cycle = null;
251
252 if ( 1 === count( $plan->pricing ) && 1 == $plan->pricing[0]->licenses ) {
253 $pricing = $plan->pricing[0];
254 if ( isset( $pricing->annual_price ) ) {
255 $billing_cycle = 'annual';
256 } else if ( isset( $pricing->monthly_price ) ) {
257 $billing_cycle = 'monthly';
258 } else if ( isset( $pricing->lifetime_price ) ) {
259 $billing_cycle = 'lifetime';
260 }
261 } else {
262 foreach ( $plan->pricing as $pricing ) {
263 if ( isset( $pricing->annual_price ) ) {
264 $billing_cycle = 'annual';
265 } else if ( isset( $pricing->monthly_price ) ) {
266 $billing_cycle = 'monthly';
267 } else if ( isset( $pricing->lifetime_price ) ) {
268 $billing_cycle = 'lifetime';
269 }
270
271 if ( ! is_null( $billing_cycle ) ) {
272 break;
273 }
274 }
275 }
276
277 return $billing_cycle;
278 }
279
280 /**
281 * @author Vova Feldman (@svovaf)
282 * @since 1.1.7
283 *
284 * @param FS_Plugin_Plan $plan
285 * @param FS_Pricing $pricing
286 *
287 * @return float|null|string
288 */
289 private function get_price_tag( FS_Plugin_Plan $plan, FS_Pricing $pricing ) {
290 $price_tag = '';
291 if ( isset( $pricing->annual_price ) ) {
292 $price_tag = $pricing->annual_price . ( $plan->is_block_features ? ' / year' : '' );
293 } else if ( isset( $pricing->monthly_price ) ) {
294 $price_tag = $pricing->monthly_price . ' / mo';
295 } else if ( isset( $pricing->lifetime_price ) ) {
296 $price_tag = $pricing->lifetime_price;
297 }
298
299 return '$' . $price_tag;
300 }
301
302 /**
303 * @author Vova Feldman (@svovaf)
304 * @since 1.1.7
305 *
306 * @param object $api
307 * @param FS_Plugin_Plan|null $plan
308 *
309 * @return string
310 */
311 private function get_plugin_cta( $api, $plan = null ) {
312 if ( ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) ) {
313
314 if ( ! empty( $api->checkout_link ) && isset( $api->plans ) && 0 < is_array( $api->plans ) ) {
315 if ( is_null( $plan ) ) {
316 $plan = $api->plans[0];
317 }
318
319 return ' <a class="button button-primary right" href="' . $this->_fs->addon_checkout_url(
320 $plan->plugin_id,
321 $plan->pricing[0]->id,
322 $this->get_billing_cycle( $plan ),
323 $plan->has_trial()
324 ) . '" target="_parent">' .
325 ( ! $plan->has_trial() ?
326 fs_text( 'purchase', $api->slug ) :
327 sprintf( fs_text( 'start-free-x', $api->slug ), $this->get_trial_period( $plan ) )
328 ) .
329 '</a>';
330
331 // @todo Add Cart concept.
332 // echo ' <a class="button right" href="' . $status['url'] . '" target="_parent">' . __( 'Add to Cart' ) . '</a>';
333
334 } else if ( ! empty( $api->download_link ) ) {
335 $status = install_plugin_install_status( $api );
336
337 // Hosted on WordPress.org.
338 switch ( $status['status'] ) {
339 case 'install':
340 if ( $api->external &&
341 $this->_fs->is_org_repo_compliant() ||
342 ! $this->_fs->is_premium()
343 ) {
344 /**
345 * Add-on hosted on Freemius, not yet installed, and core
346 * plugin is wordpress.org compliant. Therefore, require a download
347 * since installing external plugins is not allowed by the wp.org guidelines.
348 */
349 return ' <a class="button button-primary right" href="' . esc_url( $api->download_link ) . '" target="_blank">' . fs_text( 'download-latest', $api->slug ) . '</a>';
350 } else {
351 if ( $status['url'] ) {
352 return '<a class="button button-primary right" href="' . $status['url'] . '" target="_parent">' . fs_text( 'install-now', $api->slug ) . '</a>';
353 }
354 }
355 break;
356 case 'update_available':
357 if ( $status['url'] ) {
358 return '<a class="button button-primary right" href="' . $status['url'] . '" target="_parent">' . fs_text( 'install-update-now', $api->slug ) . '</a>';
359 }
360 break;
361 case 'newer_installed':
362 return '<a class="button button-primary right disabled">' . sprintf( fs_text( 'newer-installed', $api->slug ), $status['version'] ) . '</a>';
363 break;
364 case 'latest_installed':
365 return '<a class="button button-primary right disabled">' . fs_text( 'latest-installed', $api->slug ) . '</a>';
366 break;
367 }
368
369 }
370 }
371
372 return '';
373 }
374
375 /**
376 * @author Vova Feldman (@svovaf)
377 * @since 1.1.7
378 *
379 * @param FS_Plugin_Plan $plan
380 *
381 * @return string
382 */
383 private function get_trial_period( $plan ) {
384 $trial_period = (int) $plan->trial_period;
385
386 switch ( $trial_period ) {
387 case 30:
388 return 'month';
389 case 60:
390 return '2 months';
391 default:
392 return "{$plan->trial_period} days";
393 }
394 }
395
396 /**
397 * Display plugin information in dialog box form.
398 *
399 * Based on core install_plugin_information() function.
400 *
401 * @author Vova Feldman (@svovaf)
402 * @since 1.0.6
403 */
404 function install_plugin_information() {
405 global $tab;
406
407 if ( empty( $_REQUEST['plugin'] ) ) {
408 return;
409 }
410
411 $args = array(
412 'slug' => wp_unslash( $_REQUEST['plugin'] ),
413 'is_ssl' => is_ssl(),
414 'fields' => array(
415 'banners' => true,
416 'reviews' => true,
417 'downloaded' => false,
418 'active_installs' => true
419 )
420 );
421
422 if ( is_array( $args ) ) {
423 $args = (object) $args;
424 }
425
426 if ( ! isset( $args->per_page ) ) {
427 $args->per_page = 24;
428 }
429
430 if ( ! isset( $args->locale ) ) {
431 $args->locale = get_locale();
432 }
433
434 $api = apply_filters( 'fs_plugins_api', false, 'plugin_information', $args );
435
436 if ( is_wp_error( $api ) ) {
437 wp_die( $api );
438 }
439
440 $plugins_allowedtags = array(
441 'a' => array(
442 'href' => array(),
443 'title' => array(),
444 'target' => array(),
445 // Add image style for screenshots.
446 'class' => array()
447 ),
448 'style' => array(),
449 'abbr' => array( 'title' => array() ),
450 'acronym' => array( 'title' => array() ),
451 'code' => array(),
452 'pre' => array(),
453 'em' => array(),
454 'strong' => array(),
455 'div' => array( 'class' => array() ),
456 'span' => array( 'class' => array() ),
457 'p' => array(),
458 'ul' => array(),
459 'ol' => array(),
460 'li' => array( 'class' => array() ),
461 'i' => array( 'class' => array() ),
462 'h1' => array(),
463 'h2' => array(),
464 'h3' => array(),
465 'h4' => array(),
466 'h5' => array(),
467 'h6' => array(),
468 'img' => array( 'src' => array(), 'class' => array(), 'alt' => array() ),
469 // 'table' => array(),
470 // 'td' => array(),
471 // 'tr' => array(),
472 // 'th' => array(),
473 // 'thead' => array(),
474 // 'tbody' => array(),
475 );
476
477 $plugins_section_titles = array(
478 'description' => fs_text( 'description', $api->slug ),
479 'installation' => fs_text( 'installation', $api->slug ),
480 'faq' => fs_text( 'faq', $api->slug ),
481 'screenshots' => fs_text( 'screenshots', $api->slug ),
482 'changelog' => fs_text( 'changelog', $api->slug ),
483 'reviews' => fs_text( 'reviews', $api->slug ),
484 'other_notes' => fs_text( 'other_notes', $api->slug ),
485 );
486
487 // Sanitize HTML
488 // foreach ( (array) $api->sections as $section_name => $content ) {
489 // $api->sections[$section_name] = wp_kses( $content, $plugins_allowedtags );
490 // }
491
492 foreach ( array( 'version', 'author', 'requires', 'tested', 'homepage', 'downloaded', 'slug' ) as $key ) {
493 if ( isset( $api->$key ) ) {
494 $api->$key = wp_kses( $api->$key, $plugins_allowedtags );
495 }
496 }
497
498 // Add after $api->slug is ready.
499 $plugins_section_titles['features'] = fs_text( 'features-and-pricing', $api->slug );
500
501 $_tab = esc_attr( $tab );
502
503 $section = isset( $_REQUEST['section'] ) ? wp_unslash( $_REQUEST['section'] ) : 'description'; // Default to the Description tab, Do not translate, API returns English.
504 if ( empty( $section ) || ! isset( $api->sections[ $section ] ) ) {
505 $section_titles = array_keys( (array) $api->sections );
506 $section = array_shift( $section_titles );
507 }
508
509 iframe_header( fs_text( 'plugin-install', $api->slug ) );
510
511 $_with_banner = '';
512
513 // var_dump($api->banners);
514 if ( ! empty( $api->banners ) && ( ! empty( $api->banners['low'] ) || ! empty( $api->banners['high'] ) ) ) {
515 $_with_banner = 'with-banner';
516 $low = empty( $api->banners['low'] ) ? $api->banners['high'] : $api->banners['low'];
517 $high = empty( $api->banners['high'] ) ? $api->banners['low'] : $api->banners['high'];
518 ?>
519 <style type="text/css">
520 #plugin-information-title.with-banner
521 {
522 background-image: url( <?php echo esc_url( $low ); ?> );
523 }
524
525 @media only screen and ( -webkit-min-device-pixel-ratio: 1.5 )
526 {
527 #plugin-information-title.with-banner
528 {
529 background-image: url( <?php echo esc_url( $high ); ?> );
530 }
531 }
532 </style>
533 <?php
534 }
535
536 echo '<div id="plugin-information-scrollable">';
537 echo "<div id='{$_tab}-title' class='{$_with_banner}'><div class='vignette'></div><h2>{$api->name}</h2></div>";
538 echo "<div id='{$_tab}-tabs' class='{$_with_banner}'>\n";
539
540 foreach ( (array) $api->sections as $section_name => $content ) {
541 if ( 'reviews' === $section_name && ( empty( $api->ratings ) || 0 === array_sum( (array) $api->ratings ) ) ) {
542 continue;
543 }
544
545 if ( isset( $plugins_section_titles[ $section_name ] ) ) {
546 $title = $plugins_section_titles[ $section_name ];
547 } else {
548 $title = ucwords( str_replace( '_', ' ', $section_name ) );
549 }
550
551 $class = ( $section_name === $section ) ? ' class="current"' : '';
552 $href = add_query_arg( array( 'tab' => $tab, 'section' => $section_name ) );
553 $href = esc_url( $href );
554 $san_section = esc_attr( $section_name );
555 echo "\t<a name='$san_section' href='$href' $class>$title</a>\n";
556 }
557
558 echo "</div>\n";
559
560 ?>
561 <div id="<?php echo $_tab; ?>-content" class='<?php echo $_with_banner; ?>'>
562 <div class="fyi">
563 <?php if ( $api->is_paid ) : ?>
564 <?php if ( isset( $api->plans ) ) : ?>
565 <div class="plugin-information-pricing">
566 <?php foreach ( $api->plans as $plan ) : ?>
567 <?php
568 /**
569 * @var FS_Plugin_Plan $plan
570 */
571 ?>
572 <?php $first_pricing = $plan->pricing[0] ?>
573 <?php $is_multi_cycle = $first_pricing->is_multi_cycle() ?>
574 <div class="fs-plan<?php if ( ! $is_multi_cycle ) {
575 echo ' fs-single-cycle';
576 } ?>" data-plan-id="<?php echo $plan->id ?>">
577 <h3 data-plan="<?php echo $plan->id ?>"><?php printf( fs_text( 'x-plan', $api->slug ), $plan->title ) ?></h3>
578 <?php $has_annual = $first_pricing->has_annual() ?>
579 <?php $has_monthly = $first_pricing->has_monthly() ?>
580 <div class="nav-tab-wrapper">
581 <?php $billing_cycles = array( 'monthly', 'annual', 'lifetime' ) ?>
582 <?php $i = 0;
583 foreach ( $billing_cycles as $cycle ) : ?>
584 <?php $prop = "{$cycle}_price";
585 if ( isset( $first_pricing->{$prop} ) ) : ?>
586 <?php $is_featured = ( 'annual' === $cycle && $is_multi_cycle ) ?>
587 <?php
588 $prices = array();
589 foreach ( $plan->pricing as $pricing ) {
590 if ( isset( $pricing->{$prop} ) ) {
591 $prices[] = array(
592 'id' => $pricing->id,
593 'licenses' => $pricing->licenses,
594 'price' => $pricing->{$prop}
595 );
596 }
597 }
598 ?>
599 <a class="nav-tab" data-billing-cycle="<?php echo $cycle ?>"
600 data-pricing="<?php echo esc_attr( json_encode( $prices ) ) ?>">
601 <?php if ( $is_featured ) : ?>
602 <label>&#9733; <?php fs_echo( 'best', $api->slug ) ?> &#9733;</label>
603 <?php endif ?>
604 <?php fs_echo( $cycle, $api->slug ) ?>
605 </a>
606 <?php endif ?>
607 <?php $i ++; endforeach ?>
608 <?php wp_enqueue_script( 'jquery' ) ?>
609 <script type="text/javascript">
610 (function ($, undef) {
611 var
612 _formatBillingFrequency = function (cycle) {
613 switch (cycle) {
614 case 'monthly':
615 return '<?php printf(fs_text('billed-x', $api->slug), fs_text('monthly', $api->slug)) ?>';
616 case 'annual':
617 return '<?php printf(fs_text('billed-x', $api->slug), fs_text('annually', $api->slug)) ?>';
618 case 'lifetime':
619 return '<?php printf(fs_text('billed-x', $api->slug), fs_text('once', $api->slug)) ?>';
620 }
621 },
622 _formatLicensesTitle = function (pricing) {
623 switch (pricing.licenses) {
624 case 1:
625 return '<?php fs_echo( 'license-single-site', $api->slug ) ?>';
626 case null:
627 return '<?php fs_echo( 'license-unlimited', $api->slug ) ?>';
628 default:
629 return '<?php fs_echo( 'license-x-sites', $api->slug ) ?>'.replace('%s', pricing.licenses);
630 }
631 },
632 _formatPrice = function (pricing, cycle, multipleLicenses) {
633 if (undef === multipleLicenses)
634 multipleLicenses = true;
635
636 var priceCycle;
637 switch (cycle) {
638 case 'monthly':
639 priceCycle = ' / <?php fs_echo('mo', $api->slug) ?>';
640 break;
641 case 'lifetime':
642 priceCycle = '';
643 break;
644 case 'annual':
645 default:
646 priceCycle = ' / <?php fs_echo('year', $api->slug) ?>';
647 break;
648 }
649
650 if (!multipleLicenses && 1 == pricing.licenses) {
651 return '$' + pricing.price + priceCycle;
652 }
653
654 return _formatLicensesTitle(pricing) + ' - <var class="fs-price">$' + pricing.price + priceCycle + '</var>';
655 },
656 _checkoutUrl = function (plan, pricing, cycle) {
657 return '<?php echo esc_url_raw(remove_query_arg('billing_cycle', add_query_arg(array('plugin_id' => $plan->plugin_id), $api->checkout_link))) ?>' +
658 '&plan_id=' + plan +
659 '&pricing_id=' + pricing +
660 '&billing_cycle=' + cycle<?php if ($plan->has_trial()) { echo " + '&trial=true'"; }?>;
661 },
662 _updateCtaUrl = function (plan, pricing, cycle) {
663 $('.plugin-information-pricing .button, #plugin-information-footer .button').attr('href', _checkoutUrl(plan, pricing, cycle));
664 };
665
666 $(document).ready(function () {
667 var $plan = $('.plugin-information-pricing .fs-plan[data-plan-id=<?php echo $plan->id ?>]');
668 $plan.find('input[type=radio]').live('click', function () {
669 _updateCtaUrl(
670 $plan.attr('data-plan-id'),
671 $(this).val(),
672 $plan.find('.nav-tab-active').attr('data-billing-cycle')
673 );
674
675 $plan.find('.fs-trial-terms .fs-price').html(
676 $(this).parents('label').find('.fs-price').html()
677 );
678 });
679
680 $plan.find('.nav-tab').click(function () {
681 if ($(this).hasClass('nav-tab-active'))
682 return;
683
684 var $this = $(this),
685 billingCycle = $this.attr('data-billing-cycle'),
686 pricing = JSON.parse($this.attr('data-pricing')),
687 $pricesList = $this.parents('.fs-plan').find('.fs-pricing-body .fs-licenses'),
688 html = '';
689
690 // Un-select previously selected tab.
691 $plan.find('.nav-tab').removeClass('nav-tab-active');
692
693 // Select current tab.
694 $this.addClass('nav-tab-active');
695
696 // Render licenses prices.
697 if (1 == pricing.length) {
698 html = '<li><label><?php fs_echo( 'price', $api->slug ) ?>: ' + _formatPrice(pricing[0], billingCycle, false) + '</label></li>';
699 } else {
700 for (var i = 0; i < pricing.length; i++) {
701 html += '<li><label><input name="pricing-<?php echo $plan->id ?>" type="radio" value="' + pricing[i].id + '">' + _formatPrice(pricing[i], billingCycle) + '</label></li>';
702 }
703 }
704 $pricesList.html(html);
705
706 if (1 < pricing.length) {
707 // Select first license option.
708 $pricesList.find('li:first input').click();
709 }
710 else {
711 _updateCtaUrl(
712 $plan.attr('data-plan-id'),
713 pricing[0].id,
714 billingCycle
715 );
716 }
717
718 // Update billing frequency.
719 $plan.find('.fs-billing-frequency').html(_formatBillingFrequency(billingCycle));
720
721 if ('annual' === billingCycle) {
722 $plan.find('.fs-annual-discount').show();
723 } else {
724 $plan.find('.fs-annual-discount').hide();
725 }
726 });
727
728 <?php if ( $has_annual ) : ?>
729 // Select annual by default.
730 $plan.find('.nav-tab[data-billing-cycle=annual]').click();
731 <?php else : ?>
732 // Select first tab.
733 $plan.find('.nav-tab:first').click();
734 <?php endif ?>
735 });
736 }(jQuery));
737 </script>
738 </div>
739 <div class="fs-pricing-body">
740 <span class="fs-billing-frequency"></span>
741 <?php $annual_discount = ( $has_annual && $has_monthly ) ? $plan->pricing[0]->annual_discount_percentage() : 0 ?>
742 <?php if ( $annual_discount > 0 ) : ?>
743 <span
744 class="fs-annual-discount"><?php printf( fs_text( 'save-x', $api->slug ), $annual_discount . '%' ) ?></span>
745 <?php endif ?>
746 <ul class="fs-licenses">
747 </ul>
748 <?php echo $this->get_plugin_cta( $api, $plan ) ?>
749 <div style="clear:both"></div>
750 <?php if ( $plan->has_trial() ) : ?>
751 <?php $trial_period = $this->get_trial_period( $plan ) ?>
752 <ul class="fs-trial-terms">
753 <li>
754 <i class="dashicons dashicons-yes"></i><?php printf( fs_text( 'no-commitment-x', $api->slug ), $trial_period ) ?>
755 </li>
756 <li>
757 <i class="dashicons dashicons-yes"></i><?php printf( fs_text( 'after-x-pay-as-little-y', $api->slug ), $trial_period, '<var class="fs-price">' . $this->get_price_tag( $plan, $plan->pricing[0] ) . '</var>' ) ?>
758 </li>
759 </ul>
760 <?php endif ?>
761 </div>
762 </div>
763 </div>
764 <?php endforeach ?>
765 <?php endif ?>
766 <?php endif ?>
767 <div>
768 <h3><?php fs_echo( 'details', $api->slug ) ?></h3>
769 <ul>
770 <?php if ( ! empty( $api->version ) ) { ?>
771 <li><strong><?php fs_echo( 'version', $api->slug ); ?>:</strong> <?php echo $api->version; ?></li>
772 <?php
773 }
774 if ( ! empty( $api->author ) ) {
775 ?>
776 <li>
777 <strong><?php fs_echo( 'author:', $api->slug ); ?></strong> <?php echo links_add_target( $api->author, '_blank' ); ?>
778 </li>
779 <?php
780 }
781 if ( ! empty( $api->last_updated ) ) {
782 ?>
783 <li><strong><?php fs_echo( 'last-updated:', $api->slug ); ?></strong> <span
784 title="<?php echo $api->last_updated; ?>">
785 <?php printf( fs_text( 'x-ago', $api->slug ), human_time_diff( strtotime( $api->last_updated ) ) ); ?>
786 </span></li>
787 <?php
788 }
789 if ( ! empty( $api->requires ) ) {
790 ?>
791 <li>
792 <strong><?php fs_echo( 'requires-wordpress-version:', $api->slug ); ?></strong> <?php printf( fs_text( 'x-or-higher', $api->slug ), $api->requires ); ?>
793 </li>
794 <?php
795 }
796 if ( ! empty( $api->tested ) ) {
797 ?>
798 <li><strong><?php fs_echo( 'compatible-up-to:', $api->slug ); ?></strong> <?php echo $api->tested; ?>
799 </li>
800 <?php
801 }
802 if ( ! empty( $api->downloaded ) ) {
803 ?>
804 <li>
805 <strong><?php fs_echo( 'downloaded:', $api->slug ); ?></strong> <?php printf(
806 fs_text( ( 1 == $api->downloaded ) ? 'x-time' : 'x-times', $api->slug ),
807 number_format_i18n( $api->downloaded )
808 ); ?>
809 </li>
810 <?php
811 }
812 if ( ! empty( $api->slug ) && empty( $api->external ) ) {
813 ?>
814 <li><a target="_blank"
815 href="https://wordpress.org/plugins/<?php echo $api->slug; ?>/"><?php fs_echo( 'wp-org-plugin-page', $api->slug ); ?> &#187;</a>
816 </li>
817 <?php
818 }
819 if ( ! empty( $api->homepage ) ) {
820 ?>
821 <li><a target="_blank"
822 href="<?php echo esc_url( $api->homepage ); ?>"><?php fs_echo( 'plugin-homepage', $api->slug ); ?> &#187;</a>
823 </li>
824 <?php
825 }
826 if ( ! empty( $api->donate_link ) && empty( $api->contributors ) ) {
827 ?>
828 <li><a target="_blank"
829 href="<?php echo esc_url( $api->donate_link ); ?>"><?php fs_echo( 'donate-to-plugin', $api->slug ); ?> &#187;</a>
830 </li>
831 <?php } ?>
832 </ul>
833 </div>
834 <?php if ( ! empty( $api->rating ) ) { ?>
835 <h3><?php fs_echo( 'average-rating', $api->slug ); ?></h3>
836 <?php wp_star_rating( array(
837 'rating' => $api->rating,
838 'type' => 'percent',
839 'number' => $api->num_ratings
840 ) ); ?>
841 <small>(<?php printf(
842 fs_text( 'based-on-x', $api->slug ),
843 sprintf(
844 fs_text( ( 1 == $api->num_ratings ) ? 'x-rating' : 'x-ratings', $api->slug ),
845 number_format_i18n( $api->num_ratings )
846 ) ); ?>)</small>
847 <?php
848 }
849
850 if ( ! empty( $api->ratings ) && array_sum( (array) $api->ratings ) > 0 ) {
851 foreach ( $api->ratings as $key => $ratecount ) {
852 // Avoid div-by-zero.
853 $_rating = $api->num_ratings ? ( $ratecount / $api->num_ratings ) : 0;
854 $stars_label = sprintf(
855 fs_text( ( 1 == $key ) ? 'x-star' : 'x-stars', $api->slug ),
856 number_format_i18n( $key )
857 );
858 ?>
859 <div class="counter-container">
860 <span class="counter-label"><a
861 href="https://wordpress.org/support/view/plugin-reviews/<?php echo $api->slug; ?>?filter=<?php echo $key; ?>"
862 target="_blank"
863 title="<?php echo esc_attr( sprintf( fs_text('click-to-reviews', $api->slug), $stars_label) ) ?>"><?php echo $stars_label ?></a></span>
864 <span class="counter-back">
865 <span class="counter-bar" style="width: <?php echo 92 * $_rating; ?>px;"></span>
866 </span>
867 <span class="counter-count"><?php echo number_format_i18n( $ratecount ); ?></span>
868 </div>
869 <?php
870 }
871 }
872 if ( ! empty( $api->contributors ) ) {
873 ?>
874 <h3><?php fs_echo( 'contributors', $api->slug ); ?></h3>
875 <ul class="contributors">
876 <?php
877 foreach ( (array) $api->contributors as $contrib_username => $contrib_profile ) {
878 if ( empty( $contrib_username ) && empty( $contrib_profile ) ) {
879 continue;
880 }
881 if ( empty( $contrib_username ) ) {
882 $contrib_username = preg_replace( '/^.+\/(.+)\/?$/', '\1', $contrib_profile );
883 }
884 $contrib_username = sanitize_user( $contrib_username );
885 if ( empty( $contrib_profile ) ) {
886 echo "<li><img src='https://wordpress.org/grav-redirect.php?user={$contrib_username}&amp;s=36' width='18' height='18' />{$contrib_username}</li>";
887 } else {
888 echo "<li><a href='{$contrib_profile}' target='_blank'><img src='https://wordpress.org/grav-redirect.php?user={$contrib_username}&amp;s=36' width='18' height='18' />{$contrib_username}</a></li>";
889 }
890 }
891 ?>
892 </ul>
893 <?php if ( ! empty( $api->donate_link ) ) { ?>
894 <a target="_blank"
895 href="<?php echo esc_url( $api->donate_link ); ?>"><?php fs_echo( 'donate-to-plugin', $api->slug ) ?> &#187;</a>
896 <?php } ?>
897 <?php } ?>
898 </div>
899 <div id="section-holder" class="wrap">
900 <?php
901 if ( ! empty( $api->tested ) && version_compare( substr( $GLOBALS['wp_version'], 0, strlen( $api->tested ) ), $api->tested, '>' ) ) {
902 echo '<div class="notice notice-warning"><p>' . '<strong>' . fs_text( 'warning:', $api->slug ) . '</strong> ' . fs_text( 'not-tested-warning', $api->slug ) . '</p></div>';
903 } else if ( ! empty( $api->requires ) && version_compare( substr( $GLOBALS['wp_version'], 0, strlen( $api->requires ) ), $api->requires, '<' ) ) {
904 echo '<div class="notice notice-warning"><p>' . '<strong>' . fs_text( 'warning:', $api->slug ) . '</strong> ' . fs_text( 'not-compatible-warning', $api->slug ) . '</p></div>';
905 }
906
907 foreach ( (array) $api->sections as $section_name => $content ) {
908 $content = links_add_base_url( $content, 'https://wordpress.org/plugins/' . $api->slug . '/' );
909 $content = links_add_target( $content, '_blank' );
910
911 $san_section = esc_attr( $section_name );
912
913 $display = ( $section_name === $section ) ? 'block' : 'none';
914
915 if ( 'description' === $section_name &&
916 ( ( ! $api->external && $api->wp_org_missing ) ||
917 ( $api->external && $api->fs_missing ) )
918 ) {
919 $missing_notice = array(
920 'type' => 'error',
921 'id' => md5( microtime() ),
922 'message' => fs_text( ( $api->is_paid ? 'paid-addon-not-deployed' : 'free-addon-not-deployed' ), $api->slug ),
923 );
924 fs_require_template( 'admin-notice.php', $missing_notice );
925 }
926 echo "\t<div id='section-{$san_section}' class='section' style='display: {$display};'>\n";
927 echo $content;
928 echo "\t</div>\n";
929 }
930 echo "</div>\n";
931 echo "</div>\n";
932 echo "</div>\n"; // #plugin-information-scrollable
933 echo "<div id='$tab-footer'>\n";
934
935 echo $this->get_plugin_cta( $api );
936
937 echo "</div>\n";
938
939 iframe_footer();
940 exit;
941 }
942 }