Completed
Push — master ( 06f781...8ac3a5 )
by Stephanie
03:24
created

FrmAddonsController::shorten_edd_filename()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
3
class FrmAddonsController {
4
5
	public static function menu() {
6
		if ( ! current_user_can( 'activate_plugins' ) ) {
7
			return;
8
		}
9
10
		add_submenu_page( 'formidable', 'Formidable | ' . __( 'Add-Ons', 'formidable' ), __( 'Add-Ons', 'formidable' ), 'frm_view_forms', 'formidable-addons', 'FrmAddonsController::list_addons' );
11
12
		if ( ! FrmAppHelper::pro_is_installed() ) {
13
			add_submenu_page(
14
				'formidable',
15
				'Formidable | ' . __( 'Upgrade to Pro', 'formidable' ),
16
				'<span style="color:#f15a24">' . __( 'Upgrade to Pro', 'formidable' ) . '</span>',
0 ignored issues
show
introduced by
Expected a sanitizing function (see Codex for 'Data Validation'), but instead saw '__'
Loading history...
17
				'frm_view_forms',
18
				'formidable-pro-upgrade',
19
				'FrmAddonsController::upgrade_to_pro'
20
			);
21
		}
22
	}
23
24
	public static function list_addons() {
25
		FrmAppHelper::include_svg();
26
		$installed_addons = apply_filters( 'frm_installed_addons', array() );
27
		$license_type     = '';
28
29
		$addons = self::get_api_addons();
30
		$errors = array();
31
32
		if ( isset( $addons['error'] ) ) {
33
			$api    = new FrmFormApi();
34
			$errors = $api->get_error_from_response( $addons );
35
			$license_type = isset( $addons['error']['type'] ) ? $addons['error']['type'] : '';
36
			unset( $addons['error'] );
37
		}
38
		self::prepare_addons( $addons );
39
40
		$pricing = FrmAppHelper::admin_upgrade_link( 'addons' );
41
42
		include( FrmAppHelper::plugin_path() . '/classes/views/addons/list.php' );
43
	}
44
45
	public static function license_settings() {
46
		$plugins = apply_filters( 'frm_installed_addons', array() );
47
		if ( empty( $plugins ) ) {
48
			esc_html_e( 'There are no plugins on your site that require a license', 'formidable' );
49
50
			return;
51
		}
52
53
		ksort( $plugins );
54
55
		include( FrmAppHelper::plugin_path() . '/classes/views/addons/settings.php' );
56
	}
57
58
	private static function get_api_addons() {
59
		$api    = new FrmFormApi();
60
		$addons = $api->get_api_info();
61
62
		if ( empty( $addons ) ) {
63
			$addons = self::fallback_plugin_list();
64
		} else {
65
			foreach ( $addons as $k => $addon ) {
66
				if ( empty( $addon['excerpt'] ) && $k !== 'error' ) {
67
					unset( $addons[ $k ] );
68
				}
69
			}
70
		}
71
72
		return $addons;
73
	}
74
75
	/**
76
	 * If the API is unable to connect, show something on the addons page
77
	 *
78
	 * @since 3.04.03
79
	 * @return array
80
	 */
81
	private static function fallback_plugin_list() {
82
		return array(
83
			'formidable-pro' => array(
84
				'title'   => 'Formidable Pro',
85
				'link'    => 'pricing/',
86
				'docs'    => '',
87
				'excerpt' => 'Enhance your basic Formidable forms with a plethora of Pro field types and features. Create advanced forms and data-driven applications in minutes.',
88
			),
89
			'mailchimp'      => array(
90
				'title'   => 'MailChimp Forms',
91
				'excerpt' => 'Get on the path to more sales and leads in a matter of minutes. Add leads to a MailChimp mailing list when they submit forms and update their information along with the entry.',
92
			),
93
			'registration'   => array(
94
				'title'   => 'User Registration Forms',
95
				'link'    => 'downloads/user-registration/',
96
				'excerpt' => 'Give new users access to your site as quickly and painlessly as possible. Allow users to register, edit and be able to login to their profiles on your site from the front end in a clean, customized registration form.',
97
			),
98
			'paypal'         => array(
99
				'title'   => 'PayPal Standard Forms',
100
				'link'    => 'downloads/paypal-standard/',
101
				'excerpt' => 'Automate your business by collecting instant payments from your clients. Collect information, calculate a total, and send them on to PayPal. Require a payment before publishing content on your site.',
102
			),
103
			'stripe'         => array(
104
				'title'   => 'Stripe Forms',
105
				'docs'    => 'knowledgebase/stripe/',
106
				'excerpt' => 'Any Formidable forms on your site can accept credit card payments without users ever leaving your site.',
107
			),
108
			'authorize-net'  => array(
109
				'title'   => 'Authorize.net AIM Forms',
110
				'link'    => 'downloads/authorize-net-aim/',
111
				'docs'    => 'knowledgebase/authorize-net-aim/',
112
				'excerpt' => 'Accept one-time payments directly on your site, using Authorize.net AIM.',
113
			),
114
			'woocommerce'    => array(
115
				'title'   => 'WooCommerce Forms',
116
				'excerpt' => 'Use a Formidable form on your WooCommerce product pages.',
117
			),
118
			'autoresponder'  => array(
119
				'title'   => 'Form Action Automation',
120
				'docs'    => 'knowledgebase/schedule-autoresponder/',
121
				'excerpt' => 'Schedule email notifications, SMS messages, and API actions.',
122
			),
123
			'modal'          => array(
124
				'title'   => 'Bootstrap Modal Forms',
125
				'link'    => 'downloads/bootstrap-modal/',
126
				'docs'    => 'knowledgebase/bootstrap-modal/',
127
				'excerpt' => 'Open a view or form in a Bootstrap popup.',
128
			),
129
			'bootstrap'      => array(
130
				'title'   => 'Bootstrap Style Forms',
131
				'excerpt' => 'Instantly add Bootstrap styling to all your Formidable forms.',
132
			),
133
			'zapier'         => array(
134
				'title'   => 'Zapier Forms',
135
				'excerpt' => 'Connect with hundreds of different applications through Zapier. Insert a new row in a Google docs spreadsheet, post on Twitter, or add a new Dropbox file with your form.',
136
			),
137
			'signature'      => array(
138
				'title'   => 'Digital Signature Forms',
139
				'excerpt' => 'Add a signature field to your form. The user may write their signature with a trackpad/mouse or just type it.',
140
			),
141
			'api'            => array(
142
				'title'   => 'Formidable Forms API',
143
				'link'    => 'downloads/formidable-api/',
144
				'excerpt' => 'Send entry results to any other site that has a Rest API. This includes the option of sending entries from one Formidable site to another.',
145
			),
146
			'twilio'         => array(
147
				'title'   => 'Twilio SMS Forms',
148
				'docs'    => 'knowledgebase/twilio-add-on/',
149
				'excerpt' => 'Allow users to text their votes for polls created by Formidable Forms, or send SMS notifications when entries are submitted or updated.',
150
			),
151
		);
152
	}
153
154
	/**
155
	 * If Pro is missing but has been authenticated, include a download URL
156
	 *
157
	 * @since 3.04.03
158
	 * @return string
159
	 */
160
	public static function get_pro_download_url() {
161
		$pro_cred_store = 'frmpro-credentials';
162
		$pro_wpmu_store = 'frmpro-wpmu-sitewide';
163
		if ( is_multisite() && get_site_option( $pro_wpmu_store ) ) {
164
			$creds = get_site_option( $pro_cred_store );
165
		} else {
166
			$creds = get_option( $pro_cred_store );
167
		}
168
169
		if ( empty( $creds ) || ! is_array( $creds ) || ! isset( $creds['license'] ) ) {
170
			return '';
171
		}
172
173
		$license = $creds['license'];
174
		if ( empty( $license ) ) {
175
			return '';
176
		}
177
178
		if ( strpos( $license, '-' ) ) {
179
			// this is a fix for licenses saved in the past
180
			$license = strtoupper( $license );
181
		}
182
183
		$api       = new FrmFormApi( $license );
184
		$downloads = $api->get_api_info();
185
		$pro       = isset( $downloads['93790'] ) ? $downloads['93790'] : array();
186
187
		return isset( $pro['url'] ) ? $pro['url'] : '';
188
	}
189
190
	/**
191
	 * @since 4.0.01
192
	 */
193
	public static function is_license_expired() {
194
		$installed_addons = apply_filters( 'frm_installed_addons', array() );
195
		if ( empty( $installed_addons ) || ! isset( $installed_addons['formidable_pro'] ) ) {
196
			return false;
197
		}
198
		$installed_addons = array(
199
			'formidable_pro' => $installed_addons['formidable_pro'],
200
		);
201
202
		$version_info = self::fill_update_addon_info( $installed_addons );
203
		if ( ! isset( $version_info['error'] ) ) {
204
			return false;
205
		}
206
207
		return $version_info['error'];
208
	}
209
210
	/**
211
	 * @since 3.04.03
212
	 */
213
	public static function check_update( $transient ) {
214
		if ( ! is_object( $transient ) ) {
215
			$transient = new stdClass();
216
		}
217
218
		$installed_addons = apply_filters( 'frm_installed_addons', array() );
219
		if ( empty( $installed_addons ) ) {
220
			return $transient;
221
		}
222
223
		$version_info = self::fill_update_addon_info( $installed_addons );
224
225
		$transient->last_checked = time();
226
227
		$wp_plugins = get_plugins();
228
229
		foreach ( $version_info as $id => $plugin ) {
230
			$plugin = (object) $plugin;
231
232
			if ( ! isset( $plugin->new_version ) || ! isset( $plugin->package ) ) {
233
				continue;
234
			}
235
236
			$folder = $plugin->plugin;
237
			if ( empty( $folder ) ) {
238
				continue;
239
			}
240
241
			if ( ! self::is_installed( $folder ) ) {
242
				// don't show an update if the plugin isn't installed
243
				continue;
244
			}
245
246
			$wp_plugin  = isset( $wp_plugins[ $folder ] ) ? $wp_plugins[ $folder ] : array();
247
			$wp_version = isset( $wp_plugin['Version'] ) ? $wp_plugin['Version'] : '1.0';
248
249
			if ( version_compare( $wp_version, $plugin->new_version, '<' ) ) {
250
				$slug                           = explode( '/', $folder );
251
				$plugin->slug                   = $slug[0];
252
				$transient->response[ $folder ] = $plugin;
253
			}
254
255
			$transient->checked[ $folder ] = $wp_version;
256
257
		}
258
259
		return $transient;
260
	}
261
262
	/**
263
	 * Check if a plugin is installed before showing an update for it
264
	 *
265
	 * @since 3.05
266
	 *
267
	 * @param string $plugin - the folder/filename.php for a plugin
268
	 *
269
	 * @return bool - True if installed
270
	 */
271
	private static function is_installed( $plugin ) {
272
		if ( ! function_exists( 'get_plugins' ) ) {
273
			require_once ABSPATH . 'wp-admin/includes/plugin.php';
274
		}
275
276
		$all_plugins = get_plugins();
277
278
		return isset( $all_plugins[ $plugin ] );
279
	}
280
281
	/**
282
	 * @since 3.04.03
283
	 *
284
	 * @param array $installed_addons
285
	 *
286
	 * @return array
287
	 */
288
	private static function fill_update_addon_info( $installed_addons ) {
289
		$checked_licenses = array();
290
		$version_info     = array();
291
292
		foreach ( $installed_addons as $addon ) {
293
			if ( $addon->store_url !== 'https://formidableforms.com' ) {
294
				// check if this is a third-party addon
295
				continue;
296
			}
297
298
			$new_license = $addon->license;
299
			if ( empty( $new_license ) || in_array( $new_license, $checked_licenses ) ) {
300
				continue;
301
			}
302
303
			$checked_licenses[] = $new_license;
304
305
			$api = new FrmFormApi( $new_license );
306
			if ( empty( $version_info ) ) {
307
				$version_info = $api->get_api_info();
308
				continue;
309
			}
310
311
			$plugin = $api->get_addon_for_license( $addon, $version_info );
312
			if ( empty( $plugin ) ) {
313
				continue;
314
			}
315
316
			$download_id = isset( $plugin['id'] ) ? $plugin['id'] : 0;
317
			if ( ! empty( $download_id ) && ! isset( $version_info[ $download_id ]['package'] ) ) {
318
				// if this addon is using its own license, get the update url
319
				$addon_info = $api->get_api_info();
320
321
				$version_info[ $download_id ] = $addon_info[ $download_id ];
322
				if ( isset( $addon_info['error'] ) ) {
323
					$version_info[ $download_id ]['error'] = array(
324
						'message' => $addon_info['error']['message'],
325
						'code'    => $addon_info['error']['code'],
326
					);
327
				}
328
			}
329
		}
330
331
		return $version_info;
332
	}
333
334
	/**
335
	 * Get the action link for an addon that isn't active.
336
	 *
337
	 * @since 3.06.03
338
	 * @param string $addon The plugin slug
0 ignored issues
show
Bug introduced by
There is no parameter named $addon. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
339
	 * @return array
340
	 */
341
	public static function install_link( $plugin ) {
342
		$link    = array();
343
		$addons = self::get_api_addons();
344
		self::prepare_addons( $addons );
345
346
		foreach ( $addons as $addon ) {
347
			$slug = explode( '/', $addon['plugin'] );
348
			if ( $slug[0] !== 'formidable-' . $plugin ) {
349
				continue;
350
			}
351
352
			if ( $addon['status']['type'] === 'installed' && ! empty( $addon['activate_url'] ) ) {
353
				$link = array(
354
					'url'   => $addon['plugin'],
355
					'class' => 'frm-activate-addon',
356
				);
357
			} elseif ( isset( $addon['url'] ) && ! empty( $addon['url'] ) ) {
358
				$link = array(
359
					'url'   => $addon['url'],
360
					'class' => 'frm-install-addon',
361
				);
362
			} elseif ( isset( $addon['categories'] ) && ! empty( $addon['categories'] ) ) {
363
				$link = array(
364
					'categories' => $addon['categories'],
365
				);
366
			}
367
368
			return $link;
369
		}
370
	}
371
372
	/**
373
	 * @since 3.04.03
374
	 *
375
	 * @param array $addons
376
	 * @param object $license The FrmAddon object
377
	 *
378
	 * @return array
379
	 */
380
	public static function get_addon_for_license( $addons, $license ) {
381
		$download_id = $license->download_id;
382
		$plugin      = array();
383 View Code Duplication
		if ( empty( $download_id ) && ! empty( $addons ) ) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
384
			foreach ( $addons as $addon ) {
385
				if ( strtolower( $license->plugin_name ) == strtolower( $addon['title'] ) ) {
386
					return $addon;
387
				}
388
			}
389
		} elseif ( isset( $addons[ $download_id ] ) ) {
390
			$plugin = $addons[ $download_id ];
391
		}
392
393
		return $plugin;
394
	}
395
396
	private static function prepare_addons( &$addons ) {
397
		$activate_url = '';
398
		if ( current_user_can( 'activate_plugins' ) ) {
399
			$activate_url = add_query_arg( array( 'action' => 'activate' ), admin_url( 'plugins.php' ) );
400
		}
401
402
		$loop_addons = $addons;
403
		foreach ( $loop_addons as $id => $addon ) {
404
			if ( is_numeric( $id ) ) {
405
				$slug      = str_replace( array( '-wordpress-plugin', '-wordpress' ), '', $addon['slug'] );
406
				$file_name = $addon['plugin'];
407
			} else {
408
				$slug = $id;
409
				if ( isset( $addon['file'] ) ) {
410
					$base_file = $addon['file'];
411
				} else {
412
					$base_file = 'formidable-' . $slug;
413
				}
414
				$file_name = $base_file . '/' . $base_file . '.php';
415
			}
416
417
			$addon['installed']    = self::is_installed( $file_name );
418
			$addon['activate_url'] = '';
419
420
			if ( $addon['installed'] && ! empty( $activate_url ) && ! is_plugin_active( $file_name ) ) {
421
				$addon['activate_url'] = add_query_arg(
422
					array(
423
						'_wpnonce' => wp_create_nonce( 'activate-plugin_' . $file_name ),
424
						'plugin'   => $file_name,
425
					),
426
					$activate_url
427
				);
428
			}
429
430
			if ( ! isset( $addon['docs'] ) ) {
431
				$addon['docs'] = 'knowledgebase/formidable-' . $slug . '/';
432
			}
433
			self::prepare_addon_link( $addon['docs'] );
434
435
			if ( ! isset( $addon['link'] ) ) {
436
				$addon['link'] = 'downloads/' . $slug . '/';
437
			}
438
			self::prepare_addon_link( $addon['link'] );
439
440
			self::set_addon_status( $addon );
441
			$addons[ $id ] = $addon;
442
		}
443
	}
444
445
	/**
446
	 * @since 3.04.02
447
	 */
448
	private static function prepare_addon_link( &$link ) {
449
		$site_url = 'https://formidableforms.com/';
450
		if ( strpos( $link, 'http' ) !== 0 ) {
451
			$link = $site_url . $link;
452
		}
453
		$link       = FrmAppHelper::make_affiliate_url( $link );
454
		$query_args = array(
455
			'utm_source'   => 'WordPress',
456
			'utm_medium'   => 'addons',
457
			'utm_campaign' => 'liteplugin',
458
		);
459
		$link       = add_query_arg( $query_args, $link );
460
	}
461
462
	/**
463
	 * Add the status to the addon array. Status options are:
464
	 * installed, active, not installed
465
	 *
466
	 * @since 3.04.02
467
	 */
468
	private static function set_addon_status( &$addon ) {
469
		if ( ! empty( $addon['activate_url'] ) ) {
470
			$addon['status'] = array(
471
				'type'  => 'installed',
472
				'label' => __( 'Installed', 'formidable' ),
473
			);
474
		} elseif ( $addon['installed'] ) {
475
			$addon['status'] = array(
476
				'type'  => 'active',
477
				'label' => __( 'Active', 'formidable' ),
478
			);
479
		} else {
480
			$addon['status'] = array(
481
				'type'  => 'not-installed',
482
				'label' => __( 'Not Installed', 'formidable' ),
483
			);
484
		}
485
	}
486
487
	public static function upgrade_to_pro() {
488
		FrmAppHelper::include_svg();
489
490
		$link_parts = array(
491
			'medium'  => 'upgrade',
492
			'content' => 'button',
493
		);
494
495
		$features = array(
496
			'Display Entries' => array(
497
				array(
498
					'label' => 'Display form data with virtually limitless views',
499
					'link'  => array(
500
						'content' => 'views',
501
						'anchor'  => 'feature-display-form-data-views',
502
					),
503
					'lite'  => false,
504
				),
505
				array(
506
					'label' => 'Generate graphs and stats based on your submitted data',
507
					'link'  => array(
508
						'content' => 'graphs',
509
						'anchor'  => 'feature-create-a-graph-wordpress-forms',
510
					),
511
					'lite'  => false,
512
				),
513
			),
514
			'Entry Management' => array(
515
				array(
516
					'label' => 'Import entries from a CSV',
517
					'link'  => array(
518
						'content' => 'import-entries',
519
						'anchor'  => 'feature-importing-exporting-wordpress-forms',
520
					),
521
					'lite'  => false,
522
				),
523
				array(
524
					'label' => 'Logged-in users can save drafts and return later',
525
					'link'  => array(
526
						'content' => 'save-drafts',
527
						'anchor'  => 'feature-save-and-continue-partial-submissions',
528
					),
529
					'lite'  => false,
530
				),
531
				array(
532
					'label' => 'Flexibly and powerfully view, edit, and delete entries from anywhere on your site',
533
					'link'  => array(
534
						'content' => 'front-edit',
535
						'anchor'  => 'feature-front-end-editing-wordpress',
536
					),
537
					'lite'  => false,
538
				),
539
				array(
540
					'label' => 'View form submissions from the back-end',
541
					'lite'  => true,
542
				),
543
				array(
544
					'label' => 'Export your entries to a CSV',
545
					'lite'  => true,
546
				),
547
			),
548
			'Form Building' => array(
549
				array(
550
					'label' => 'Save a calculated value into a field',
551
					'link'  => array(
552
						'content' => 'calculations',
553
						'anchor'  => 'feature-wordpress-calculated-fields-form',
554
					),
555
					'lite'  => false,
556
				),
557
				array(
558
					'label' => 'Allow multiple file uploads',
559
					'link'  => array(
560
						'content' => 'file-uploads',
561
						'anchor'  => 'feature-wordpress-multiple-file-upload-form',
562
					),
563
					'lite'  => false,
564
				),
565
				array(
566
					'label' => 'Repeat sections of fields',
567
					'link'  => array(
568
						'content' => 'repeaters',
569
						'anchor'  => 'feature-dynamically-add-form-fields',
570
					),
571
					'lite'  => false,
572
				),
573
				array(
574
					'label' => 'Hide and show fields conditionally based on other fields or the user\'s role',
575
					'link'  => array(
576
						'content' => 'conditional-logic',
577
						'anchor'  => 'feature-conditional-logic-wordpress-forms',
578
					),
579
					'lite'  => false,
580
				),
581
				array(
582
					'label' => 'Confirmation fields',
583
					'link'  => array(
584
						'content' => 'confirmation-fields',
585
						'anchor'  => 'feature-confirm-email-address-password-wordpress-form',
586
					),
587
					'lite'  => false,
588
				),
589
				array(
590
					'label' => 'Multi-paged forms',
591
					'link'  => array(
592
						'content' => 'page-breaks',
593
						'anchor'  => 'feature-wordpress-multi-step-form',
594
					),
595
					'lite'  => false,
596
				),
597
				array(
598
					'label' => 'Include section headings, page breaks, rich text, dates, times, scales, star ratings, sliders, toggles, dynamic fields populated from other forms, passwords, and tags in advanced forms.',
599
					'lite'  => false,
600
				),
601
				array(
602
					'label' => 'Include text, email, url, paragraph text, radio, checkbox, dropdown fields, hidden fields, user ID fields, and HTML blocks in your form.',
603
					'lite'  => true,
604
				),
605
				array(
606
					'label' => 'Drag & Drop Form building',
607
					'link'  => array(
608
						'content' => 'drag-drop',
609
						'anchor'  => 'feature-drag-drop-form-builder',
610
					),
611
					'lite'  => true,
612
				),
613
				array(
614
					'label' => 'Create forms from Templates',
615
					'link'  => array(
616
						'content' => 'form-templates',
617
						'anchor'  => 'feature-wordpress-form-templates',
618
					),
619
					'lite'  => true,
620
				),
621
				array(
622
					'label' => 'Import and export forms with XML',
623
					'link'  => array(
624
						'content' => 'import',
625
						'anchor'  => 'feature-importing-exporting-wordpress-forms',
626
					),
627
					'lite'  => true,
628
				),
629
				array(
630
					'label' => 'Use input placeholder text in your fields that clear when typing starts.',
631
					'lite'  => true,
632
				),
633
			),
634
			'Form Actions' => array(
635
				array(
636
					'label' => 'Conditionally send your email notifications based on values in your form',
637
					'link'  => array(
638
						'content' => 'conditional-emails',
639
						'anchor'  => 'feature-conditional-logic-wordpress-forms',
640
					),
641
					'lite'  => false,
642
				),
643
				array(
644
					'label' => 'Create and edit WordPress posts or custom posts from the front-end',
645
					'link'  => array(
646
						'content' => 'create-posts',
647
						'anchor'  => 'feature-user-submitted-posts-wordpress-forms',
648
					),
649
					'lite'  => false,
650
				),
651
				array(
652
					'label' => 'Send multiple emails and autoresponders',
653
					'link'  => array(
654
						'content' => 'multiple-emails',
655
						'anchor'  => 'feature-email-autoresponders-wordpress',
656
					),
657
					'lite'  => true,
658
				),
659
			),
660
			'Form Appearance' => array(
661
				array(
662
					'label' => 'Create Multiple styles for different forms',
663
					'link'  => array(
664
						'content' => 'multiple-styles',
665
						'anchor'  => 'feature-wordpress-visual-form-styler',
666
					),
667
					'lite'  => false,
668
				),
669
				array(
670
					'label' => 'Customizable layout with CSS classes',
671
					'link'  => array(
672
						'content' => 'form-layout',
673
						'anchor'  => 'feature-wordpress-mobile-friendly-responsive-forms',
674
					),
675
					'lite'  => true,
676
				),
677
				array(
678
					'label' => 'Customize the HTML for your forms',
679
					'link'  => array(
680
						'content' => 'custom-html',
681
						'anchor'  => 'feature-customize-form-html-wordpress',
682
					),
683
					'lite'  => true,
684
				),
685
				array(
686
					'label' => 'Style your form with the Visual Form Styler',
687
					'lite'  => true,
688
				),
689
			),
690
		);
691
692
		include( FrmAppHelper::plugin_path() . '/classes/views/addons/upgrade_to_pro.php' );
693
	}
694
695
	/**
696
	 * @since 3.04.02
697
	 */
698
	public static function ajax_install_addon() {
699
700
		self::install_addon_permissions();
701
702
		// Set the current screen to avoid undefined notices.
703
		global $hook_suffix;
704
		set_current_screen();
705
706
		self::maybe_show_cred_form();
707
708
		$installed = self::install_addon();
709
		self::maybe_activate_addon( $installed );
710
711
		// Send back a response.
712
		echo json_encode( __( 'Your plugin has been installed. Please reload the page to see more options.', 'formidable' ) );
713
		wp_die();
714
	}
715
716
	/**
717
	 * @since 3.04.02
718
	 */
719
	private static function maybe_show_cred_form() {
720
		// Start output bufferring to catch the filesystem form if credentials are needed.
721
		ob_start();
722
723
		$show_form = false;
724
		$method    = '';
725
		$url       = add_query_arg( array( 'page' => 'formidable-settings' ), admin_url( 'admin.php' ) );
726
		$url       = esc_url_raw( $url );
727
		$creds     = request_filesystem_credentials( $url, $method, false, false, null );
728
729
		if ( false === $creds ) {
730
			$show_form = true;
731
		} elseif ( ! WP_Filesystem( $creds ) ) {
732
			request_filesystem_credentials( $url, $method, true, false, null );
733
			$show_form = true;
734
		}
735
736
		if ( $show_form ) {
737
			//$form = ob_get_clean();
738
			//TODO: test this: echo json_encode( array( 'form' => $form ) );
739
			echo json_encode( array( 'form' => __( 'Sorry, you\'re site requires FTP authentication. Please install plugins manaully.', 'formidable' ) ) );
740
			wp_die();
741
		}
742
743
		ob_end_clean();
744
	}
745
746
	/**
747
	 * We do not need any extra credentials if we have gotten this far,
748
	 * so let's install the plugin.
749
	 *
750
	 * @since 3.04.02
751
	 */
752
	private static function install_addon() {
753
		require_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
754
755
		$download_url = FrmAppHelper::get_param( 'plugin', '', 'post', 'esc_url_raw' );
756
757
		// Create the plugin upgrader with our custom skin.
758
		$installer = new Plugin_Upgrader( new FrmInstallerSkin() );
759
		$installer->install( $download_url );
760
761
		// Flush the cache and return the newly installed plugin basename.
762
		wp_cache_flush();
763
764
		return $installer->plugin_info();
765
	}
766
767
	/**
768
	 * @since 3.06.03
769
	 */
770
	public static function ajax_activate_addon() {
771
772
		self::install_addon_permissions();
773
774
		// Set the current screen to avoid undefined notices.
775
		global $hook_suffix;
776
		set_current_screen();
777
778
		$plugin = FrmAppHelper::get_param( 'plugin', '', 'post', 'sanitize_text_field' );
779
		self::maybe_activate_addon( $plugin );
780
781
		// Send back a response.
782
		echo json_encode( __( 'Your plugin has been activated. Please reload the page to see more options.', 'formidable' ) );
783
		wp_die();
784
	}
785
786
	/**
787
	 * @since 3.04.02
788
	 * @param string $installed The plugin folder name with file name
789
	 */
790
	private static function maybe_activate_addon( $installed ) {
791
		if ( ! $installed ) {
792
			return;
793
		}
794
795
		$activate = activate_plugin( $installed );
796
		if ( is_wp_error( $activate ) ) {
797
			// Ignore the invalid header message that shows with nested plugins.
798
			if ( $activate->get_error_code() !== 'no_plugin_header' ) {
799
				echo json_encode( array( 'error' => $activate->get_error_message() ) );
800
				wp_die();
801
			}
802
		}
803
	}
804
805
	/**
806
	 * Run security checks before installing
807
	 *
808
	 * @since 3.04.02
809
	 */
810
	private static function install_addon_permissions() {
811
		check_ajax_referer( 'frm_ajax', 'nonce' );
812
813
		if ( ! current_user_can( 'activate_plugins' ) || ! isset( $_POST['plugin'] ) ) {
814
			echo json_encode( true );
815
			wp_die();
816
		}
817
	}
818
819
	/**
820
	 * @since 3.04.03
821
	 * @deprecated 3.06
822
	 * @codeCoverageIgnore
823
	 * @return array
824
	 */
825
	public static function error_for_license( $license ) {
826
		return FrmDeprecated::error_for_license( $license );
827
	}
828
829
	/**
830
	 * @since 3.04.03
831
	 * @deprecated 3.06
832
	 * @codeCoverageIgnore
833
	 */
834
	public static function get_pro_updater() {
835
		return FrmDeprecated::get_pro_updater();
836
	}
837
838
	/**
839
	 * @since 3.04.03
840
	 * @deprecated 3.06
841
	 * @codeCoverageIgnore
842
	 *
843
	 * @return array
844
	 */
845
	public static function get_addon_info( $license = '' ) {
846
		return FrmDeprecated::get_addon_info( $license );
847
	}
848
849
	/**
850
	 * @since 3.04.03
851
	 * @deprecated 3.06
852
	 * @codeCoverageIgnore
853
	 *
854
	 * @return string
855
	 */
856
	public static function get_cache_key( $license ) {
857
		return FrmDeprecated::get_cache_key( $license );
858
	}
859
860
	/**
861
	 * @since 3.04.03
862
	 * @deprecated 3.06
863
	 * @codeCoverageIgnore
864
	 */
865
	public static function reset_cached_addons( $license = '' ) {
866
		FrmDeprecated::reset_cached_addons( $license );
867
	}
868
869
	/**
870
	 * @since 2.03.08
871
	 * @deprecated 3.04.03
872
	 * @codeCoverageIgnore
873
	 *
874
	 * @param boolean $return
875
	 * @param string $package
876
	 *
877
	 * @return boolean
878
	 */
879
	public static function add_shorten_edd_filename_filter( $return, $package ) {
880
		return FrmDeprecated::add_shorten_edd_filename_filter( $return, $package );
881
	}
882
883
	/**
884
	 * @since 2.03.08
885
	 * @deprecated 3.04.03
886
	 * @codeCoverageIgnore
887
	 *
888
	 * @param string $filename
889
	 * @param string $ext
890
	 *
891
	 * @return string
892
	 */
893
	public static function shorten_edd_filename( $filename, $ext ) {
894
		return FrmDeprecated::shorten_edd_filename( $filename, $ext );
895
	}
896
897
	/**
898
	 * @deprecated 3.04.03
899
	 * @codeCoverageIgnore
900
	 */
901
	public static function get_licenses() {
902
		FrmDeprecated::get_licenses();
903
	}
904
}
905