Completed
Push — develop ( 6e6f66...59e2b4 )
by Zack
18:38 queued 04:04
created

License_Handler::strings()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 2
dl 0
loc 32
ccs 21
cts 21
cp 1
crap 1
rs 9.408
c 0
b 0
f 0
1
<?php
2
namespace GV;
3
4
/** If this file is called directly, abort. */
5
if ( ! defined( 'GRAVITYVIEW_DIR' ) ) {
6
	die();
7
}
8
9
/**
10
 * The \GV\License_Handler class.
11
 *
12
 * Handles everything licensing. Ka-ching!
13
 */
14
class License_Handler {
0 ignored issues
show
Coding Style introduced by
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
15
	/**
16
	 * @var \GV\Addon_Settings The global addon settings binding.
17
	 */
18
	private $settings;
19
20
	const name = 'GravityView';
21
	const author = 'Katz Web Services, Inc.';
22
	const url = 'https://gravityview.co';
23
24
	/**
25
	 * Post ID on gravityview.co
26
	 * @since 1.15
27
	 */
28
	const item_id = 17;
29
30
	/**
31
	 * Name of the transient used to store license status for GV
32
	 * @since 1.17
33
	 */
34
	const status_transient_key = 'gravityview_edd-activate_valid';
35
36
	/**
37
	 * @var string Key used to store active GravityView/Gravity Forms plugin data
38
	 * @since 1.15
39
	 */
40
	const related_plugins_key = 'gravityview_related_plugins';
41
42
	/** @var \GV\EDD_SL_Plugin_Updater */
43
	private $EDD_SL_Plugin_Updater;
44
45
	/**
46
	 * @var \GV\License_Handler
47
	 */
48
	private static $__instance;
49
50 1
	private function __construct( $settings ) {
51
52 1
		$this->settings = $settings;
53
54 1
		if ( ! $this->settings instanceof Addon_Settings ) {
55
			$this->settings = gravityview()->plugin->settings;
56
		}
57
58 1
		add_action( 'admin_init', array( $this, 'setup_edd' ), 0 );
59 1
		add_action( 'wp_ajax_gravityview_license', array( $this, 'license_call' ) );
60 1
		add_action( 'admin_init', array( $this, 'refresh_license_status' ) );
61 1
		add_action( 'admin_init', array( $this, 'check_license' ) );
62 1
		add_action( 'update_option_active_plugins', array( $this, 'flush_related_plugins_transient' ) );
63 1
		add_action( 'update_option_active_sitewide_plugins', array( $this, 'flush_related_plugins_transient' ) );
64 1
	}
65
66
	/**
67
	 * @return \GV\License_Handler The global instance.
68
	 */
69 2
	public static function get( $settings = null ) {
70 2
		if ( ! self::$__instance ) {
71 1
			self::$__instance = new self( $settings );
72
		}
73 2
		return self::$__instance;
74
	}
75
76
	/**
77
	 * Generate the array of settings passed to the EDD license call
78
	 *
79
	 * @since 1.7.4
80
	 *
81
	 * @param string $action The action to send to edd, such as `check_license`
82
	 * @param string $license The license key to have passed to EDD
83
	 *
84
	 * @return array
85
	 */
86 1
	private function _get_edd_settings( $action = '', $license = '' ) {
87
88
		// retrieve our license key from the DB
89 1
		$license_key = empty( $license ) ? trim( $this->settings->get( 'license_key' ) ) : $license;
90
91
		$settings = array(
92 1
			'version'   => Plugin::$version,
93 1
			'license'   => $license_key,
94 1
			'item_name' => self::name,
95 1
			'item_id'   => self::item_id,
96 1
			'author'    => self::author,
97 1
			'language'  => get_locale(),
98 1
			'url'       => home_url(),
99 1
		    'beta'      => $this->settings->get( 'beta' ),
100
		);
101
102 1
		if ( ! empty( $action ) ) {
103 1
			$settings['edd_action'] = esc_attr( $action );
104
		}
105
106 1
		return array_map( 'urlencode', $settings );
107
	}
108
109
	/**
110
	 * Include the EDD plugin updater class, if not exists
111
	 *
112
	 * @since 1.7.4
113
	 * @since 1.21.5.3 Changed visibility of method to public
114
	 *
115
	 * @return void
116
	 */
117 1
	public function setup_edd() {
118 1
		if ( ! class_exists( '\GV\EDD_SL_Plugin_Updater' ) ) {
119 1
			require_once gravityview()->plugin->dir( 'future/lib/EDD_SL_Plugin_Updater.php' );
120
		}
121
122
		// setup the updater
123 1
		$this->EDD_SL_Plugin_Updater = new EDD_SL_Plugin_Updater(
124 1
			self::url,
125 1
			GRAVITYVIEW_FILE,
126 1
			$this->_get_edd_settings()
127
		);
128 1
	}
129
130
	/**
131
	 * Perform the call to EDD based on the AJAX call or passed data
132
	 *
133
	 * @since 1.7.4
134
	 *
135
	 * @param array $array {
136
	 * @type string $license The license key
137
	 * @type string $edd_action The EDD action to perform, like `check_license`
138
	 * @type string $field_id The ID of the field to check
139
	 * @type boolean $update Whether to update plugin settings. Prevent updating the data by setting an `update` key to false
140
	 * @type string $format If `object`, return the object of the license data. Else, return the JSON-encoded object
141
	 * }
142
	 * @param boolean $cap_check Require `gravityview_edit_settings` capability from current user.
143
	 *
144
	 * @return mixed|string|void
145
	 */
146 1
	public function license_call( $array = array(), $cap_check = true ) {
147
148 1
		$is_ajax = ( defined( 'DOING_AJAX' ) && DOING_AJAX );
149 1
		$data = empty( $array ) ? Utils::_POST( 'data', array() ) : $array;
150
151 1
		$data = wp_parse_args( $data, array(
152 1
			'license' => '',
153
			'edd_action' => '',
154
			'field_id' => '',
155
			'update' => '',
156
			'format' => 'json',
157
		) );
158
159 1
		if ( $is_ajax && empty( $data['license'] ) ) {
160
			die( -1 );
161
		}
162
163
		// If the user isn't allowed to edit settings, show an error message
164 1
		if ( $cap_check && ! \GVCommon::has_cap( 'gravityview_edit_settings' ) ) {
165 1
			$license_data = new \stdClass();
166 1
			$license_data->error = 'capability';
167 1
			$license_data->message = $this->get_license_message( $license_data );
168 1
			$json = json_encode( $license_data );
169
		} else {
170 1
			$license      = esc_attr( Utils::get( $data, 'license' ) );
171 1
			$license_data = $this->_license_get_remote_response( $data, $license );
172
173
			// Empty is returned when there's an error.
174 1
			if ( empty( $license_data ) ) {
175 1
				if ( $is_ajax ) {
176
					exit( json_encode( array() ) );
177
				} else { // Non-ajax call
178 1
					return json_encode( array() );
179
				}
180
			}
181
182 1
			$license_data->details = $this->license_details( $license_data );
183 1
			$license_data->message = $this->get_license_message( $license_data );
184
185 1
			$json = json_encode( $license_data );
186
187 1
			$update_license = Utils::get( $data, 'update' ) || 'gravityview_license' === Utils::_POST('action');
188
189 1
			$is_check_action_button = ( 'check_license' === Utils::get( $data, 'edd_action' ) && defined( 'DOING_AJAX' ) && DOING_AJAX );
190
191 1
			do_action('gravityview/admin_installer/delete_downloads_data', true );
192
193 1
			if ( $is_check_action_button ) {
194
				delete_transient( self::status_transient_key );
195
196
			// Failed is the response from trying to de-activate a license and it didn't work.
197
			// This likely happened because people entered in a different key and clicked "Deactivate",
198
			// meaning to deactivate the original key. We don't want to save this response, since it is
199
			// most likely a mistake.
200 1
			} else if ( $license_data->license !== 'failed' && $update_license ) {
201
202 1
				if ( ! empty( $data['field_id'] ) ) {
203 1
					set_transient( self::status_transient_key, $license_data, DAY_IN_SECONDS );
204
				}
205
206 1
				$this->license_call_update_settings( $license_data, $data );
207
			}
208
		}
209
210 1
		if ( $is_ajax ) {
211
			exit( $json );
212
		} else { // Non-ajax call
213 1
			return ( Utils::_GET( 'format', Utils::get( $data, 'format' ) ) === 'object' ) ? $license_data : $json;
214
		}
215
	}
216
217
	/**
218
	 * Generate the status message displayed in the license field
219
	 *
220
	 * @since 1.7.4
221
	 * @param $license_data
222
	 *
223
	 * @return string
224
	 */
225 2
	private function get_license_message( $license_data ) {
226 2
		if ( empty( $license_data ) ) {
227 2
			$message = '';
228
		} else {
229 1
			if( ! empty( $license_data->error ) ) {
230 1
				$class = 'error';
231 1
				$string_key = $license_data->error;
232 1
			} else { $class = $license_data->license;
233 1
				$string_key = $license_data->license;
234
			}
235
236 1
			$message = sprintf( '<p><strong>%s: %s</strong></p>', $this->strings( 'status' ), $this->strings( $string_key, $license_data ) );
237
238 1
			$message = $this->generate_license_box( $message, $class );
239
		}
240
241 2
		return $message;
242
	}
243
244
	/**
245
	 * Allow pure HTML in settings fields
246
	 *
247
	 * @since 1.17
248
	 *
249
	 * @param array $response License response
250
	 *
251
	 * @return string `html` key of the $field
252
	 */
253 2
	public function license_details( $response = array() ) {
254
255 2
		$response = (array) $response;
256
257 2
		$return = '';
258 2
		$wrapper = '<span class="gv-license-details" aria-live="polite" aria-busy="false">%s</span>';
259
260 2
		if ( ! empty( $response['license_key'] ) ) {
261 1
			$return .= '<h3>' . esc_html__( 'License Details:', 'gravityview' ) . '</h3>';
262
263 1
			if ( in_array( Utils::get( $response, 'license' ), array( 'invalid', 'deactivated' ) ) ) {
264 1
				$return .= $this->strings( $response['license'], $response );
265 1
			} elseif ( ! empty( $response['license_name'] ) ) {
266
				$response_keys = array(
267 1
					'license_name'   => '',
268
					'license_limit'  => '',
269
					'customer_name'  => '',
270
					'customer_email' => '',
271
					'site_count'     => '',
272
					'expires'        => '',
273
					'upgrades'       => ''
274
				);
275
276
				// Make sure all the keys are set
277 1
				$response = wp_parse_args( $response, $response_keys );
278
279 1
				$login_link    = sprintf( '<a href="%s" class="howto" rel="external">%s</a>', esc_url( sprintf( 'https://gravityview.co/wp-login.php?username=%s', $response['customer_email'] ) ), esc_html__( 'Access your GravityView account', 'gravityview' ) );
280 1
				$local_text    = ( ! empty( $response['is_local'] ) ? '<span class="howto">' . __( 'This development site does not count toward license activation limits', 'gravityview' ) . '</span>' : '' );
281 1
				$license_limit = empty( $response['license_limit'] ) ? __( 'Unlimited', 'gravityview' ) : (int) $response['license_limit'];
282
283
				$details    = array(
284 1
					'license'     => sprintf( esc_html__( 'License level: %s', 'gravityview' ), esc_html( $response['license_name'] ), esc_html( $response['license_limit'] ) ),
285 1
					'licensed_to' => sprintf( esc_html_x( 'Licensed to: %1$s (%2$s)', '1: Customer name; 2: Customer email', 'gravityview' ), esc_html__( $response['customer_name'], 'gravityview' ), esc_html__( $response['customer_email'], 'gravityview' ) ) . $login_link,
286 1
					'activations' => sprintf( esc_html__( 'Activations: %d of %s sites', 'gravityview' ), intval( $response['site_count'] ), esc_html( $license_limit ) ) . $local_text,
287 1
					'expires'     => 'lifetime' === $response['expires'] ? '' : sprintf( esc_html__( 'Renew on: %s', 'gravityview' ), date_i18n( get_option( 'date_format' ), strtotime( $response['expires'] ) - DAY_IN_SECONDS ) ),
288 1
					'upgrade'     => $this->get_upgrade_html( $response['upgrades'] ),
289
				);
290
291 1
				if ( ! empty( $response['error'] ) && 'expired' === $response['error'] ) {
292
					unset( $details['upgrade'] );
293
					$details['expires'] = '<div class="error inline"><p>' . $this->strings( 'expired', $response ) . '</p></div>';
294
				}
295
296 1
				$return .= '<ul><li>' . implode( '</li><li>', array_filter( $details ) ) . '</li></ul>';
297
			}
298
		}
299
300 2
		return sprintf( $wrapper, $return );
301
	}
302
303
	/**
304
	 * Display possible upgrades for a license
305
	 *
306
	 * @since 1.17
307
	 *
308
	 * @param array $upgrades Array of upgrade paths, returned from the GV website
309
	 *
310
	 * @return string HTML list of upgrades available for the current license
311
	 */
312 1
	private function get_upgrade_html( $upgrades ) {
313
314 1
		$output = '';
315
316 1
		if ( ! empty( $upgrades ) ) {
317
318 1
			$locale_parts = explode( '_', get_locale() );
319 1
			$is_english = ( 'en' === $locale_parts[0] );
320
321 1
			$output .= '<h4>' . esc_html__( 'Upgrades available:', 'gravityview' ) . '</h4>';
322 1
			$output .= '<ul class="ul-disc">';
323
324 1
			foreach ( $upgrades as $upgrade_id => $upgrade ) {
325 1
				$upgrade = (object) $upgrade;
326
327 1
				$anchor_text = sprintf( esc_html_x( 'Upgrade to %1$s for %2$s', '1: GravityView upgrade name, 2: Cost of upgrade', 'gravityview' ), esc_attr( $upgrade->name ), esc_attr( $upgrade->price ) );
328
329 1
				if ( $is_english && isset( $upgrade->description ) ) {
330 1
					$message = esc_html( $upgrade->description );
331
				} else {
332
					switch( $upgrade->price_id ) {
333
						// Interstellar
334
						case 1:
335
						default:
336
							$message = esc_html__( 'Get access to Extensions', 'gravityview' );
337
							break;
338
						// Galactic
339
						case 2:
0 ignored issues
show
Unused Code introduced by
case 2: $message = e...avityview'); break; does not seem to be reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
340
							$message = esc_html__( 'Get access to Entry Importer and other Premium plugins', 'gravityview' );
341
							break;
342
					}
343
				}
344
345 1
				$output .= sprintf( '<li><a href="%s">%s</a><span class="howto">%s</span></li>', esc_url( add_query_arg( array( 'utm_source' => 'settings', 'utm_medium' => 'admin', 'utm_content' => 'license-details', 'utm_campaign' => 'Upgrades' ), $upgrade->url ) ), $anchor_text, $message );
346
			}
347 1
			$output .= '</ul>';
348
		}
349
350 1
		return $output;
351
	}
352
353
	/**
354
	 * Generate the status message box HTML based on the current status
355
	 *
356
	 * @since 1.7.4
357
	 * @param $message
358
	 * @param string $class
359
	 *
360
	 * @return string
361
	 */
362 1
	private function generate_license_box( $message, $class = '' ) {
363 1
		$template = '<div id="gv-edd-status" aria-live="polite" aria-busy="false" class="gv-edd-message inline %s">%s</div>';
364
365 1
		$output = sprintf( $template, esc_attr( $class ), $message );
366
367 1
		return $output;
368
	}
369
370
	/**
371
	 * Override the text used in the GravityView EDD license Javascript
372
	 *
373
	 * @param  string $status Status to get. If empty, get all strings.
374
	 * @param  object|array|null $license_data Object with license data, used to generate link to license renewal URL
375
	 * @return string Modified array of content
376
	 */
377 1
	public function strings( $status = NULL, $license_data = null ) {
378
379
		$strings = array(
380 1
			'status' => esc_html__( 'Status', 'gravityview' ),
381 1
			'error' => esc_html__( 'There was an error processing the request.', 'gravityview' ),
382 1
			'failed'  => esc_html__( 'Could not deactivate the license. The license key you attempted to deactivate may not be active or valid.', 'gravityview' ),
383 1
			'site_inactive' => esc_html__( 'The license key is valid, but it has not been activated for this site.', 'gravityview' ),
384 1
			'inactive' => esc_html__( 'The license key is valid, but it has not been activated for this site.', 'gravityview' ),
385 1
			'no_activations_left' => esc_html__( 'Invalid: this license has reached its activation limit.', 'gravityview' ) . ' ' . sprintf( esc_html__( 'You can manage license activations %son your GravityView account page%s.', 'gravityview' ), '<a href="https://gravityview.co/account/#licenses">', '</a>' ),
386 1
			'deactivated' => esc_html__( 'The license has been deactivated.', 'gravityview' ),
387 1
			'valid' => esc_html__( 'The license key is valid and active.', 'gravityview' ),
388 1
			'disabled' => sprintf( esc_html__( 'This license key is disabled. For updates and support, %spurchase a new license%s.', 'gravityview' ), '<a href="https://gravityview.co/account/">', '</a>' ),
389 1
			'invalid' => esc_html__( 'The license key entered is invalid.', 'gravityview' ),
390 1
			'missing' => esc_html__( 'Invalid license key.', 'gravityview' ),
391 1
			'revoked' => esc_html__( 'This license key has been revoked.', 'gravityview' ),
392 1
			'expired' => sprintf( esc_html__( 'This license key has expired. %sRenew your license on the GravityView website%s to receive updates and support.', 'gravityview' ), '<a href="'. esc_url( $this->get_license_renewal_url( $license_data ) ) .'">', '</a>' ),
393 1
			'capability' => esc_html__( 'You don\'t have the ability to edit plugin settings.', 'gravityview' ),
394
395 1
			'verifying_license' => esc_html__( 'Verifying license&hellip;', 'gravityview' ),
396 1
			'activate_license' => esc_html__( 'Activate License', 'gravityview' ),
397 1
			'deactivate_license' => esc_html__( 'Deactivate License', 'gravityview' ),
398 1
			'check_license' => esc_html__( 'Verify License', 'gravityview' ),
399
		);
400
401
		/**
402
		 * @internal Do not rely on this filter.
403
		 * @since 2.1
404
		 */
405 1
		$strings = apply_filters( 'gravityview/admin/license/strings', $strings );
406
407 1
		return Utils::get( $strings, $status, null );
408
	}
409
410
	/**
411
	 * URL to direct license renewal, or if license key is not set, then just the account page
412
	 * @since 1.13.1
413
	 * @param  object|null $license_data Object with license data
414
	 * @return string Renewal or account URL
415
	 */
416 1
	private function get_license_renewal_url( $license_data ) {
417 1
		$license_data = is_array( $license_data ) ? (object)$license_data : $license_data;
418
419 1
		if ( ! empty( $license_data->renewal_url ) ) {
420
			$renew_license_url = $license_data->renewal_url;
421 1
		} elseif( ! empty( $license_data->license_key ) ) {
422 1
			$renew_license_url = sprintf( 'https://gravityview.co/checkout/?download_id=17&edd_license_key=%s', $license_data->license_key );
423
		} else {
424 1
			$renew_license_url = 'https://gravityview.co/account/';
425
		}
426
427 1
		$renew_license_url = add_query_arg( wp_parse_args( 'utm_source=admin_notice&utm_medium=admin&utm_content=expired&utm_campaign=Activation&force_login=1' ), $renew_license_url );
428
429 1
		return $renew_license_url;
430
	}
431
432
	/**
433
	 * Perform the call
434
	 *
435
	 * @return array|\WP_Error
436
	 */
437 1
	private function _license_get_remote_response( $data, $license = '' ) {
438 1
		$api_params = $this->_get_edd_settings( $data['edd_action'], $license );
439
440 1
		$url = add_query_arg( $api_params, self::url );
441
442 1
		$response = wp_remote_get( $url, array(
443 1
			'timeout'   => 15,
444
			'sslverify' => false,
445
		) );
446
447 1
		if ( is_wp_error( $response ) ) {
448
			gravityview()->log->error( 'WP_Error response from license check. API params:', array( 'data' => $api_params ) );
449
			return array();
450
		}
451
452 1
		$license_data = json_decode( wp_remote_retrieve_body( $response ) );
453
454
		// Not JSON
455 1
		if ( empty( $license_data ) ) {
456 1
			gravityview()->log->error( 'Empty license data response from license check', array( 'data' => compact( 'response', 'url', 'api_params', 'data' ) ) );
457
458 1
			delete_transient( self::status_transient_key );
459
460
			// Change status
461 1
			return array();
462
		}
463
464
		// Store the license key inside the data array
465 1
		$license_data->license_key = $license;
466
467 1
		return $license_data;
468
	}
469
470
	/**
471
	 * Update the license after fetching it
472
	 * @param object $license_data
473
	 * @return void
474
	 */
475 1
	private function license_call_update_settings( $license_data, $data ) {
476 1
		$settings = array();
477
478 1
        $settings['license_key'] = $license_data->license_key = trim( $data['license'] );
479 1
		$settings['license_key_status'] = $license_data->license;
480 1
		$settings['license_key_response'] = (array)$license_data;
481
482 1
		$this->settings->set( $settings );
483 1
	}
484
485 2
	public function settings_edd_license_activation( $field, $echo ) {
0 ignored issues
show
Unused Code introduced by
The parameter $field is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
486 2
		$script_debug = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
487
488 2
		wp_enqueue_script( 'gv-admin-edd-license', GRAVITYVIEW_URL . 'assets/js/admin-edd-license' . $script_debug . '.js', array( 'jquery' ) );
489
490 2
		$status = trim( $this->settings->get( 'license_key_status' ) );
491 2
		$key = trim( $this->settings->get( 'license_key' ) );
492
493 2
		if ( ! empty( $key ) ) {
494
			$response = $this->settings->get( 'license_key_response' );
495
			$response = is_array( $response ) ? (object) $response : json_decode( $response );
496
		} else {
497 2
			$response = array();
498
		}
499
500 2
		wp_localize_script( 'gv-admin-edd-license', 'GVGlobals', array(
501 2
			'license_box' => $this->get_license_message( $response )
502
		) );
503
504
		$fields = array(
505
			array(
506 2
				'name'  => 'edd-activate',
507 2
				'value' => __( 'Activate License', 'gravityview' ),
508 2
				'data-pending_text' => __( 'Verifying license&hellip;', 'gravityview' ),
509 2
				'data-edd_action' => 'activate_license',
510 2
				'class' => 'button-primary',
511
			),
512
			array(
513 2
				'name'  => 'edd-deactivate',
514 2
				'value' => __( 'Deactivate License', 'gravityview' ),
515 2
				'data-pending_text' => __( 'Deactivating license&hellip;', 'gravityview' ),
516 2
				'data-edd_action' => 'deactivate_license',
517 2
				'class' => ( empty( $status ) ? 'button-primary hide' : 'button-primary' ),
518
			),
519
			array(
520 2
				'name'  => 'edd-check',
521 2
				'value' => __( 'Check License', 'gravityview' ),
522 2
				'data-pending_text' => __( 'Verifying license&hellip;', 'gravityview' ),
523 2
				'title' => 'Check the license before saving it',
524 2
				'data-edd_action' => 'check_license',
525 2
				'class' => 'button-secondary',
526
			),
527
		);
528
529 2
		$class = 'button gv-edd-action';
530
531 2
		$class .= ( ! empty( $key ) && $status !== 'valid' ) ? '' : ' hide';
532
533 2
		$disabled_attribute = \GVCommon::has_cap( 'gravityview_edit_settings' ) ? false : 'disabled';
534
535 2
		$submit = '<div class="gv-edd-button-wrapper">';
536 2
		foreach ( $fields as $field ) {
537 2
			$field['type'] = 'button';
538 2
			$field['class'] = isset( $field['class'] ) ? $field['class'] . ' '. $class : $class;
539 2
			$field['style'] = 'margin-left: 10px;';
540 2
			if( $disabled_attribute ) {
541 1
				$field['disabled'] = $disabled_attribute;
542
			}
543 2
			$submit .= $this->settings->as_html( $field, $echo );
544
		}
545 2
		$submit .= '</div>';
546
547 2
		return $submit;
548
	}
549
550
	/**
551
	 * When the status transient expires (or is deleted on activation), re-check the status
552
	 *
553
	 * @since 1.17
554
	 *
555
	 * @return void
556
	 */
557 1
	public function refresh_license_status() {
558 1
		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
559
			return;
560
		}
561
562
		// The transient is fresh; don't fetch.
563 1
		if ( $status = get_transient( self::status_transient_key ) ) {
564
			return;
565
		}
566
567
		$data = array(
568 1
			'edd_action' => 'check_license',
569 1
			'license' => trim( $this->settings->get( 'license_key' ) ),
570
			'update' => true,
571 1
			'format' => 'object',
572 1
			'field_id' => 'refresh_license_status', // Required to set the `status_transient_key` transient
573
		);
574
575 1
		$license_call = $this->license_call( $data, false );
576
577 1
		gravityview()->log->debug( 'Refreshed the license.', array( 'data' => $license_call ) );
578 1
	}
579
580
	/**
581
	 * Check the GravityView license information
582
	 *
583
	 * @since 1.19.3
584
	 * @param bool $force Whether to force checking license, even if AJAX
0 ignored issues
show
Bug introduced by
There is no parameter named $force. 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...
585
	 *
586
	 * @return void
587
	 */
588 1
	public function check_license() {
589 1
		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
590
			return; // Don't fire when saving settings or AJAX
591
		}
592
593 1
		if ( ! apply_filters( 'gv_send_site_data', true ) ) {
594
			return;
595
		}
596
597
		// Send checkins once per week
598 1
		$last_checked = get_option( 'gv_last_checkin', false );
599
600 1
		if ( is_numeric( $last_checked ) && $last_checked > strtotime( '-1 week', current_time( 'timestamp' ) ) ) {
601
			return; // checked within a week
602
		}
603
604 1
		$status = get_transient( 'gv_license_check' );
605
606
		// Run the license check a maximum of once per day, and not on GV website
607 1
		if ( false === $status && site_url() !== self::url ) {
608
609
			// Call the custom API.
610 1
			$response = wp_remote_post( self::url, array(
611 1
				'timeout'   => 15,
612
			    'sslverify' => false,
613
			    'body'      =>  array(
614 1
				    'edd_action' => 'check_license',
615 1
				    'license'    => trim( $this->settings->get( 'license_key' ) ),
616 1
				    'item_name'  => self::name,
617 1
				    'url'        => home_url(),
618 1
				    'site_data'  => $this->get_site_data(),
619
			    ),
620
			));
621
622
			// make sure the response came back okay
623 1
			if ( is_wp_error( $response ) ) {
624
625
				// Connection failed, try again in three hours
626
				set_transient( 'gv_license_check', 1, 3 * HOUR_IN_SECONDS );
627
628
				return;
629
			}
630
631 1
			set_transient( 'gv_license_check', 1, DAY_IN_SECONDS );
632
633 1
			update_option( 'gv_last_checkin', current_time( 'timestamp' ) );
634
		}
635 1
	}
636
637
	/**
638
	 * Retrieves site data (plugin versions, integrations, etc) to be sent along with the license check.
639
	 *
640
	 * @since 1.9
641
	 *
642
	 * @return array
643
	 */
644 1
	public function get_site_data() {
645 1
		$data = array();
646
647 1
		$theme_data = wp_get_theme();
648 1
		$theme      = $theme_data->Name . ' ' . $theme_data->Version;
649
650 1
		$data['gv_version']  = Plugin::$version;
651 1
		$data['php_version']  = phpversion();
652 1
		$data['wp_version']   = get_bloginfo( 'version' );
653 1
		$data['gf_version']  = \GFForms::$version;
654 1
		$data['server']       = Utils::get( $_SERVER, 'SERVER_SOFTWARE' );
655 1
		$data['multisite']    = is_multisite();
656 1
		$data['theme']        = $theme;
657 1
		$data['url']          = home_url();
658 1
		$data['license_key']  = $this->settings->get( 'license_key' );
659 1
		$data['beta']         = $this->settings->get( 'beta' );
660
661
		// View Data
662 1
		$gravityview_posts = wp_count_posts( 'gravityview', 'readable' );
663
664 1
		$data['view_count'] = null;
665 1
		$data['view_first'] = null;
666 1
		$data['view_latest'] = null;
667
668 1
		if ( $gravityview_posts->publish ) {
669 1
			$data['view_count'] = $gravityview_posts->publish;
670
671 1
			$first = get_posts( 'numberposts=1&post_type=gravityview&post_status=publish&order=ASC' );
672 1
			$latest = get_posts( 'numberposts=1&post_type=gravityview&post_status=publish&order=DESC' );
673
674 1
			if ( $first = array_shift( $first ) ) {
675 1
				$data['view_first'] = $first->post_date;
676
			}
677 1
			if ( $latest = array_pop( $latest ) ) {
678 1
				$data['view_latest'] = $latest->post_date;
679
			}
680
		}
681
682
		// Form counts
683 1
		if ( class_exists( 'GFFormsModel' ) ) {
684 1
			$form_data = \GFFormsModel::get_form_count();
685 1
			$data['forms_total'] = Utils::get( $form_data, 'total', 0 );
686 1
			$data['forms_active'] = Utils::get( $form_data, 'active', 0 );
687 1
			$data['forms_inactive'] = Utils::get( $form_data, 'inactive', 0 );
688 1
			$data['forms_trash'] = Utils::get( $form_data, 'inactive', 0 );
689
		}
690
691
		// Retrieve current plugin information
692 1
		if ( ! function_exists( 'get_plugins' ) ) {
693
			include ABSPATH . '/wp-admin/includes/plugin.php';
694
		}
695
696 1
		$data['integrations']     = self::get_related_plugins_and_extensions();
697 1
		$data['active_plugins']   = get_option( 'active_plugins', array() );
698 1
		$data['inactive_plugins'] = array();
699 1
		$data['locale']           = get_locale();
700
701
		// Validate request on the GV server
702 1
		$data['hash']             = 'gv_version.url.locale:' . sha1( $data['gv_version'] . $data['url'] . $data['locale'] );
703
704 1
		return $data;
705
	}
706
707
	/**
708
	 * Get active GravityView Extensions and Gravity Forms Add-ons to help debug issues.
709
	 *
710
	 * @since 1.15
711
	 * @return string List of active extensions related to GravityView or Gravity Forms, separated by HTML line breaks
712
	 */
713 1
	static public function get_related_plugins_and_extensions( $implode = '<br />' ) {
714 1
		if ( ! function_exists( 'wp_get_active_and_valid_plugins' ) ) {
715
			return 'Running < WP 3.0';
716
		}
717
718 1
		$extensions = get_site_transient( self::related_plugins_key );
719
720 1
		if ( empty( $extensions ) ) {
721
722 1
			$active_plugins = wp_get_active_and_valid_plugins();
723 1
			$extensions = array();
724 1
			foreach ( $active_plugins as $active_plugin ) {
725
				// Match gravityview, gravity-forms, gravityforms, gravitate
726
				if ( ! preg_match( '/(gravityview|gravity-?forms|gravitate|perk|gravity|gf)/ism', $active_plugin ) ) {
727
					continue;
728
				}
729
730
				$plugin_data = get_plugin_data( $active_plugin );
731
732
				$extensions[] = sprintf( '%s %s', $plugin_data['Name'], $plugin_data['Version'] );
733
			}
734
735 1
			if ( ! empty( $extensions ) ) {
736
				set_site_transient( self::related_plugins_key, $extensions, HOUR_IN_SECONDS );
737
			} else {
738 1
				return 'There was an error fetching related plugins.';
739
			}
740
		}
741
742
		return $implode ? implode( $implode, $extensions ) : $extensions;
743
	}
744
745
	/**
746
	 * When a plugin is activated or deactivated, delete the cached extensions/plugins used by get_related_plugins_and_extensions()
747
	 *
748
	 * @see get_related_plugins_and_extensions()
749
	 * @since 1.15
750
	 */
751 1
	public function flush_related_plugins_transient() {
752 1
		if ( function_exists( 'delete_site_transient' ) ) {
753 1
			delete_site_transient( self::related_plugins_key );
754
		}
755 1
	}
756
}
757