Completed
Push — master ( e7ef90...760553 )
by J.D.
03:28
created

functions.php ➔ wordpoints_component_is_active()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
/**
4
 * WordPoints Common Functions.
5
 *
6
 * These are general functions that are here to be available to all components,
7
 * modules, and plugins.
8
 *
9
 * @package WordPoints
10
 * @since 1.0.0
11
 */
12
13
/**
14
 * Register the installer for WordPoints.
15
 *
16
 * @since 2.0.0
17
 *
18
 * @WordPress\action plugins_loaded
19
 */
20
function wordpoints_register_installer() {
21
22
	WordPoints_Installables::register(
23
		'plugin'
24
		, 'wordpoints'
25
		, array(
26
			'version'      => WORDPOINTS_VERSION,
27
			'un_installer' => WORDPOINTS_DIR . '/includes/class-un-installer.php',
28
			'network_wide' => is_wordpoints_network_active(),
29
		)
30
	);
31
}
32
33
/**
34
 * Install the plugin on activation.
35
 *
36
 * @since 1.0.0
37
 *
38
 * @WordPress\action activate_wordpoints/wordpoints.php
39
 *
40
 * @param bool $network_active Whether the plugin is being network activated.
41
 */
42
function wordpoints_activate( $network_active ) {
43
44
	// The installer won't be registered yet.
45
	wordpoints_register_installer();
46
47
	WordPoints_Installables::install( 'plugin', 'wordpoints', $network_active );
48
}
49
50
/**
51
 * Check module compatibility before breaking updates.
52
 *
53
 * @since 2.0.0
54
 *
55
 * @WordPress\action plugins_loaded
56
 */
57
function wordpoints_breaking_update() {
58
59
	if ( is_wordpoints_network_active() ) {
60
		$wordpoints_data = get_site_option( 'wordpoints_data' );
61
	} else {
62
		$wordpoints_data = get_option( 'wordpoints_data' );
63
	}
64
65
	// Normally this should never happen, because the plugins_loaded action won't
66
	// run until the next request after WordPoints is activated and installs itself.
67
	if ( empty( $wordpoints_data['version'] ) ) {
68
		return;
69
	}
70
71
	// The major version is determined by the first number, so we can just cast to
72
	// an integer. IF the major versions are equal, we don't need to do anything.
73
	if ( (int) WORDPOINTS_VERSION === (int) $wordpoints_data['version'] ) {
74
		return;
75
	}
76
77
	$updater = new WordPoints_Breaking_Updater( 'wordpoints_breaking', WORDPOINTS_VERSION );
78
	$updater->update();
79
}
80
81
/**
82
 * Prints the random string stored in the database.
83
 *
84
 * @since 2.0.0
85
 *
86
 * @WordPress\action shutdown Only when checking module compatibility during a
87
 *                            breaking update.
88
 */
89
function wordpoints_maintenance_shutdown_print_rand_str() {
90
91
	if ( ! isset( $_GET['wordpoints_module_check'] ) ) {
92
		return;
93
	}
94
95
	if ( is_network_admin() ) {
96
		$nonce = get_site_option( 'wordpoints_module_check_nonce' );
97
	} else {
98
		$nonce = get_option( 'wordpoints_module_check_nonce' );
99
	}
100
101
	if ( ! $nonce || ! hash_equals( $nonce, sanitize_key( $_GET['wordpoints_module_check'] ) ) ) {
102
		return;
103
	}
104
105
	if ( is_network_admin() ) {
106
		$rand_str = get_site_option( 'wordpoints_module_check_rand_str' );
107
	} else {
108
		$rand_str = get_option( 'wordpoints_module_check_rand_str' );
109
	}
110
111
	echo esc_html( $rand_str );
112
}
113
114
/**
115
 * Filters the modules when checking compatibility during a breaking update.
116
 *
117
 * @since 2.0.0
118
 *
119
 * @WordPress\filter pre_option_wordpoints_active_modules Only when checking module
120
 *                   compatibility during a breaking update.
121
 * @WordPress\filter pre_site_option_wordpoints_sitewide_active_modules Only when
122
 *                   checking module compatibility during a breaking update. Only in
123
 *                   the network admin.
124
 *
125
 * @param array $modules The active modules.
126
 *
127
 * @return array The modules whose compatibility is being checked.
128
 */
129
function wordpoints_maintenance_filter_modules( $modules ) {
130
131
	if ( ! isset( $_GET['check_module'], $_GET['wordpoints_module_check'] ) ) {
132
		return $modules;
133
	}
134
135
	if ( is_network_admin() ) {
136
		$nonce = get_site_option( 'wordpoints_module_check_nonce' );
137
	} else {
138
		$nonce = get_option( 'wordpoints_module_check_nonce' );
139
	}
140
141
	if ( ! $nonce || ! hash_equals( $nonce, sanitize_key( $_GET['wordpoints_module_check'] ) ) ) {
142
		return $modules;
143
	}
144
145
	$modules = explode(
146
		','
147
		, sanitize_text_field( wp_unslash( $_GET['check_module'] ) )
148
	);
149
150
	if ( 'pre_site_option_wordpoints_sitewide_active_modules' === current_filter() ) {
151
		$modules = array_flip( $modules );
152
	}
153
154
	return $modules;
155
}
156
157
//
158
// Sanitizing Functions.
159
//
160
161
/**
162
 * Convert a value to an integer.
163
 *
164
 * False is returned if $maybe_int is not an integer, or a float or string whose
165
 * integer value is equal to its non-integer value (for example, 1.00 or '10', as
166
 * opposed to 1.3 [evaluates to int 1] or '10 piggies' [10]). This is to ensure that
167
 * there was intention behind the value.
168
 *
169
 * @since 1.0.0
170
 *
171
 * @see wordpoints_posint() Convert a value to a positive integer.
172
 * @see wordpoints_negint() Convert a value to a negative integer.
173
 *
174
 * @param mixed $maybe_int The value to convert to an integer.
175
 *
176
 * @return int|false False if $maybe_int couldn't reliably be converted to an integer.
177
 */
178
function wordpoints_int( &$maybe_int ) {
179
180
	$type = gettype( $maybe_int );
181
182
	switch ( $type ) {
183
184
		case 'integer': break;
185
186
		case 'string':
187
			if ( (string) (int) $maybe_int === $maybe_int ) {
188
				$maybe_int = (int) $maybe_int;
189
			} else {
190
				$maybe_int = false;
191
			}
192
		break;
193
194
		case 'double':
195
			if ( (float) (int) $maybe_int === $maybe_int ) {
196
				$maybe_int = (int) $maybe_int;
197
			} else {
198
				$maybe_int = false;
199
			}
200
		break;
201
202
		default:
203
			$maybe_int = false;
204
	}
205
206
	return $maybe_int;
207
}
208
209
/**
210
 * Convert a value to a positive integer.
211
 *
212
 * If the value is negative, false is returned. I prefer this approach over that used
213
 * in absint() {@link https://codex.wordpress.org/Function_Reference/absint} because
214
 * sometimes if you are expecting a positive value and you get a negative value
215
 * instead, it is unlikely that the absolute value was intended. In many cases we
216
 * don't want to assume that the absolute value was intended, because if it wasn't
217
 * there could be big consequences. In many of these cases returning false is much
218
 * safer.
219
 *
220
 * Note that 0 is unsigned, so it is not considered positive by this function.
221
 *
222
 * The value is passed by reference, so you can keep things short and sweet.
223
 *
224
 * @since 1.0.0
225
 *
226
 * @uses wordpoints_int()
227
 *
228
 * @param mixed $maybe_int The value to convert to a positive integer.
229
 *
230
 * @return int
231
 */
232
function wordpoints_posint( &$maybe_int ) {
233
234
	$maybe_int = ( wordpoints_int( $maybe_int ) > 0 ) ? $maybe_int : false;
235
	return $maybe_int;
236
}
237
238
/**
239
 * Convert a value to a negative integer (0 exclusive).
240
 *
241
 * @since 1.0.0
242
 *
243
 * @uses wordpoints_int()
244
 * @see wordpoints_posint()
245
 *
246
 * @param mixed $maybe_int The value to convert to an integer.
247
 *
248
 * @return int
249
 */
250
function wordpoints_negint( &$maybe_int ) {
251
252
	$maybe_int = ( wordpoints_int( $maybe_int ) < 0 ) ? $maybe_int : false;
253
	return $maybe_int;
254
}
255
256
/**
257
 * Verify an nonce.
258
 *
259
 * This is a wrapper for the wp_verify_nonce() function. It was introduced to provide
260
 * a better bootstrap for verifying an nonce request. In addition, it supplies better
261
 * input validation and sanitization. Sanitizing the inputs before passing them in to
262
 * wp_verify_nonce() is especially important, because that function is pluggable, and
263
 * it is impossible to know how it might be implemented.
264
 *
265
 * The possible return values are also certain, which isn't so for wp_verify_nonce(),
266
 * due to it being pluggable.
267
 *
268
 * @since 1.9.0
269
 * @since 2.0.0 $format_values now accepts a string when there is only one value.
270
 *
271
 * @see wp_verify_nonce()
272
 *
273
 * @param string          $nonce_key     The key for the nonce in the request parameters array.
274
 * @param string          $action_format A sprintf()-style format string for the nonce action.
275
 * @param string|string[] $format_values The keys of the request values to use to format the action.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $format_values not be string|string[]|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
276
 * @param string          $request_type  The request array to use, 'get' ($_GET) or 'post' ($_POST).
277
 *
278
 * @return int|false Returns 1 or 2 on success, false on failure.
279
 */
280
function wordpoints_verify_nonce(
281
	$nonce_key,
282
	$action_format,
283
	$format_values = null,
284
	$request_type = 'get'
285
) {
286
287
	if ( 'post' === $request_type ) {
288
		$request = $_POST; // WPCS: CSRF OK.
289
	} else {
290
		$request = $_GET;
291
	}
292
293
	if ( ! isset( $request[ $nonce_key ] ) ) {
294
		return false;
295
	}
296
297
	if ( ! empty( $format_values ) ) {
298
299
		$values = array();
300
301
		foreach ( (array) $format_values as $value ) {
302
303
			if ( ! isset( $request[ $value ] ) ) {
304
				return false;
305
			}
306
307
			$values[] = $request[ $value ];
308
		}
309
310
		$action_format = vsprintf( $action_format, $values );
311
	}
312
313
	$is_valid = wp_verify_nonce(
314
		sanitize_key( $request[ $nonce_key ] )
315
		, strip_tags( $action_format )
316
	);
317
318
	if ( 1 === $is_valid || 2 === $is_valid ) {
319
		return $is_valid;
320
	}
321
322
	return false;
323
}
324
325
/**
326
 * Sanitize a WP_Error object for passing directly to wp_die().
327
 *
328
 * The wp_die() function accepts an WP_Error object as the first parameter, but it
329
 * does not sanitize it's contents before printing it out to the user. By passing
330
 * the object through this function before giving it to wp_die(), the potential for
331
 * XSS should be avoided.
332
 *
333
 * Example:
334
 *
335
 * wp_die( wordpoints_sanitize_wp_error( $error ) );
336
 *
337
 * @since 1.10.0
338
 *
339
 * @param WP_Error $error The error to sanitize.
340
 *
341
 * @return WP_Error The sanitized error.
342
 */
343
function wordpoints_sanitize_wp_error( $error ) {
344
345
	$code = $error->get_error_code();
346
347
	$error_data = $error->error_data;
348
349
	if ( isset( $error_data[ $code ]['title'] ) ) {
350
351
		$error_data[ $code ]['title'] = wp_kses(
352
			$error->error_data[ $code ]['title']
353
			, 'wordpoints_sanitize_wp_error_title'
354
		);
355
356
		$error->error_data = $error_data;
357
	}
358
359
	$all_errors = $error->errors;
360
361
	foreach ( $all_errors as $code => $errors ) {
362
363
		foreach ( $errors as $key => $message ) {
364
			$all_errors[ $code ][ $key ] = wp_kses(
365
				$message
366
				, 'wordpoints_sanitize_wp_error_message'
367
			);
368
		}
369
	}
370
371
	$error->errors = $all_errors;
372
373
	return $error;
374
}
375
376
/**
377
 * Escape a MySQL identifier.
378
 *
379
 * Quotes the identifier with backticks and escapes any backticks within it by
380
 * doubling them.
381
 *
382
 * @since 2.1.0
383
 *
384
 * @link https://dev.mysql.com/doc/refman/5.7/en/identifiers.html#idm139700789409120
385
 *
386
 * @param string $identifier The identifier (column, table, alias, etc.).
387
 *
388
 * @return string The escaped identifier. Already quoted, do not place within
389
 *                backticks.
390
 */
391
function wordpoints_escape_mysql_identifier( $identifier ) {
392
	return '`' . str_replace( '`', '``', $identifier ) . '`';
393
}
394
395
//
396
// Database Helpers.
397
//
398
399
/**
400
 * Get an option that must be an array.
401
 *
402
 * This is a wrapper for get_option() that will force the return value to be an
403
 * array.
404
 *
405
 * @since 1.0.0
406
 * @since 1.1.0 The $context parameter was added for site options.
407
 * @since 1.2.0 The 'network' context was added.
408
 * @since 2.1.0 The 'network' context was deprecated.
409
 *
410
 * @param string $option The name of the option to get.
411
 * @param string $context The context for the option. Use 'site' to get site options.
412
 *
413
 * @return array The option value if it is an array, or an empty array if not.
414
 */
415
function wordpoints_get_array_option( $option, $context = 'default' ) {
416
417
	switch ( $context ) {
418
419
		case 'default':
420
			$value = get_option( $option, array() );
421
		break;
422
423
		case 'site':
424
			$value = get_site_option( $option, array() );
425
		break;
426
427
		case 'network':
428
			_deprecated_argument(
429
				__FUNCTION__
430
				, '2.1.0'
431
				, 'Using "network" as the value of $context is deprecated, use wordpoints_get_maybe_network_array_option() instead.'
432
			);
433
434
			$value = wordpoints_get_maybe_network_option( $option, array() );
0 ignored issues
show
Documentation introduced by
array() is of type array, but the function expects a boolean|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
435
		break;
436
437
		default:
438
			_doing_it_wrong( __FUNCTION__, sprintf( 'Unknown option context "%s"', esc_html( $context ) ), '1.2.0' );
439
			$value = array();
440
	}
441
442
	if ( ! is_array( $value ) ) {
443
		$value = array();
444
	}
445
446
	return $value;
447
}
448
449
/**
450
 * Get an option or site option from the database, based on the plugin's status.
451
 *
452
 * If the plugin is network activated on a multisite install, this will return a
453
 * network ('site') option. Otherwise it will return a regular option.
454
 *
455
 * @since 1.2.0
456
 * @deprecated 2.1.0 Use wordpoints_get_maybe_network_option() instead.
457
 *
458
 * @param string $option  The name of the option to get.
459
 * @param mixed  $default A default value to return if the option isn't found.
460
 *
461
 * @return mixed The option value if it exists, or $default (false by default).
462
 */
463
function wordpoints_get_network_option( $option, $default = false ) {
464
465
	_deprecated_function(
466
		__FUNCTION__
467
		, '2.1.0'
468
		, 'wordpoints_get_maybe_network_option()'
469
	);
470
471
	return wordpoints_get_maybe_network_option( $option, null, $default );
472
}
473
474
/**
475
 * Add an option or site option, based on the plugin's activation status.
476
 *
477
 * If the plugin is network activated on a multisite install, this will add a
478
 * network ('site') option. Otherwise it will create a regular option.
479
 *
480
 * @since 1.2.0
481
 * @deprecated 2.1.0 Use wordpoints_add_maybe_network_option() instead.
482
 *
483
 * @param string $option   The name of the option to add.
484
 * @param mixed  $value    The value for the option.
485
 * @param string $autoload Whether to automatically load the option. 'yes' (default)
486
 *                         or 'no'. Does not apply if WordPoints is network active.
487
 *
488
 * @return bool Whether the option was added successfully.
489
 */
490
function wordpoints_add_network_option( $option, $value, $autoload = 'yes' ) {
491
492
	_deprecated_function(
493
		__FUNCTION__
494
		, '2.1.0'
495
		, 'wordpoints_add_maybe_network_option()'
496
	);
497
498
	return wordpoints_add_maybe_network_option( $option, $value, null, $autoload );
499
}
500
501
/**
502
 * Update an option or site option, based on the plugin's activation status.
503
 *
504
 * If the plugin is network activated on a multisite install, this will update a
505
 * network ('site') option. Otherwise it will update a regular option.
506
 *
507
 * @since 1.2.0
508
 * @deprecated 2.1.0 Use wordpoints_update_maybe_network_option() instead.
509
 *
510
 * @param string $option The name of the option to update.
511
 * @param mixed  $value  The new value for the option.
512
 *
513
 * @return bool Whether the option was updated successfully.
514
 */
515
function wordpoints_update_network_option( $option, $value ) {
516
517
	_deprecated_function(
518
		__FUNCTION__
519
		, '2.1.0'
520
		, 'wordpoints_update_maybe_network_option()'
521
	);
522
523
	return wordpoints_update_maybe_network_option( $option, $value );
524
}
525
526
/**
527
 * Delete an option or site option, based on the plugin's activation status.
528
 *
529
 * If the plugin is network activated on a multisite install, this will delete a
530
 * network ('site') option. Otherwise it will delete a regular option.
531
 *
532
 * @since 1.2.0
533
 * @deprecated 2.1.0 Use wordpoints_delete_maybe_network_option() instead.
534
 *
535
 * @param string $option The name of the option to delete.
536
 *
537
 * @return bool Whether the option was successfully deleted.
538
 */
539
function wordpoints_delete_network_option( $option ) {
540
541
	_deprecated_function(
542
		__FUNCTION__
543
		, '2.1.0'
544
		, 'wordpoints_delete_maybe_network_option()'
545
	);
546
547
	return wordpoints_delete_maybe_network_option( $option );
548
}
549
550
/**
551
 * Get an option or network option that must be an array.
552
 *
553
 * This is a wrapper for {@see wordpoints_get_maybe_network_option()} that will force
554
 * the return value to be an array.
555
 *
556
 * @since 2.1.0
557
 *
558
 * @param string $option The name of the option to get.
559
 * @param bool   $network Whether to retrieve a network option, or a regular option.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $network not be boolean|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
560
 *                        By default a regular option will be retrieved, unless
561
 *                        WordPoints is network active, in which case a network
562
 *                        option will be retrieved.
563
 *
564
 * @return array The option value if it is an array, or an empty array if not.
565
 */
566
function wordpoints_get_maybe_network_array_option( $option, $network = null ) {
567
568
	$value = wordpoints_get_maybe_network_option( $option, $network );
569
570
	if ( ! is_array( $value ) ) {
571
		$value = array();
572
	}
573
574
	return $value;
575
}
576
577
/**
578
 * Get an option or network option from the database.
579
 *
580
 * @since 2.1.0
581
 *
582
 * @param string $option  The name of the option to get.
583
 * @param bool   $network Whether to retrieve a network option, or a regular option.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $network not be boolean|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
584
 *                        By default a regular option will be retrieved, unless
585
 *                        WordPoints is network active, in which case a network
586
 *                        option will be retrieved.
587
 * @param mixed  $default A default value to return if the option isn't found.
588
 *
589
 * @return mixed The option value if it exists, or $default (false by default).
590
 */
591
function wordpoints_get_maybe_network_option( $option, $network = null, $default = false ) {
592
593
	if ( $network || ( null === $network && is_wordpoints_network_active() ) ) {
594
		return get_site_option( $option, $default );
595
	} else {
596
		return get_option( $option, $default );
597
	}
598
}
599
600
/**
601
 * Add an option or network option.
602
 *
603
 * @since 2.1.0
604
 *
605
 * @param string $option   The name of the option to add.
606
 * @param mixed  $value    The value for the option.
607
 * @param bool   $network  Whether to add a network option, or a regular option. By
0 ignored issues
show
Documentation introduced by
Should the type for parameter $network not be boolean|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
608
 *                         default a regular option will be added, unless WordPoints
609
 *                         is network active, in which case a network option will be
610
 *                         added.
611
 * @param string $autoload Whether to automatically load the option. 'yes' (default)
612
 *                         or 'no'. Does not apply if WordPoints is network active.
613
 *
614
 * @return bool Whether the option was added successfully.
615
 */
616
function wordpoints_add_maybe_network_option( $option, $value, $network = null, $autoload = 'yes' ) {
617
618 View Code Duplication
	if ( $network || ( null === $network && is_wordpoints_network_active() ) ) {
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...
619
		return add_site_option( $option, $value );
620
	} else {
621
		return add_option( $option, $value, '', $autoload );
622
	}
623
}
624
625
/**
626
 * Update an option or network option.
627
 *
628
 * @since 2.1.0
629
 *
630
 * @param string $option  The name of the option to update.
631
 * @param mixed  $value   The new value for the option.
632
 * @param bool   $network Whether to update a network option, or a regular option.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $network not be boolean|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
633
 *                        By default a regular option will be updated, unless
634
 *                        WordPoints is network active, in which case a network
635
 *                        option will be updated.
636
 *
637
 * @return bool Whether the option was updated successfully.
638
 */
639
function wordpoints_update_maybe_network_option( $option, $value, $network = null ) {
640
641 View Code Duplication
	if ( $network || ( null === $network && is_wordpoints_network_active() ) ) {
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...
642
		return update_site_option( $option, $value );
643
	} else {
644
		return update_option( $option, $value );
645
	}
646
}
647
648
/**
649
 * Delete an option or network option.
650
 *
651
 * @since 2.1.0
652
 *
653
 * @param string $option  The name of the option to delete.
654
 * @param bool   $network Whether to delete a network option, or a regular option.
0 ignored issues
show
Documentation introduced by
Should the type for parameter $network not be boolean|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
655
 *                        By default a regular option will be deleted, unless
656
 *                        WordPoints is network active, in which case a network
657
 *                        option will be deleted.
658
 *
659
 * @return bool Whether the option was successfully deleted.
660
 */
661
function wordpoints_delete_maybe_network_option( $option, $network = null ) {
662
663
	if ( $network || ( null === $network && is_wordpoints_network_active() ) ) {
664
		return delete_site_option( $option );
665
	} else {
666
		return delete_option( $option );
667
	}
668
}
669
670
/**
671
 * Prepare an IN or NOT IN condition for a database query.
672
 *
673
 * Example return: "'foo','bar','blah'".
674
 *
675
 * @since 1.0.0
676
 *
677
 * @uses wpdb::prepare() To prepare the query.
678
 *
679
 * @param array  $_in    The values that the column must be IN (or NOT IN).
680
 * @param string $format The format for the values in $_in: '%s', '%d', or '%f'.
681
 *
682
 * @return string|false The comma-delimited string of values. False on failure.
683
 */
684
function wordpoints_prepare__in( $_in, $format = '%s' ) {
685
686
	global $wpdb;
687
688
	// Validate $format.
689
	$formats = array( '%d', '%s', '%f' );
690
691
	if ( ! in_array( $format, $formats ) ) {
692
693
		$format = esc_html( $format );
694
		_doing_it_wrong( __FUNCTION__, esc_html( "WordPoints Debug Error: invalid format '{$format}', allowed values are %s, %d, and %f" ), '1.0.0' );
695
696
		$format = '%s';
697
	}
698
699
	$_in = array_unique( $_in );
700
701
	$count = count( $_in );
702
703
	if ( 0 === $count ) {
704
705
		_doing_it_wrong( __FUNCTION__, 'WordPoints Debug Error: empty array passed as first parameter', '1.0.0' );
706
707
		return false;
708
	}
709
710
	// String a bunch of format signs together, one for each value in $_in.
711
	$in = $format . str_repeat( ",{$format}", $count - 1 );
712
713
	return $wpdb->prepare( $in, $_in ); // WPCS: unprepared SQL OK
714
}
715
716
//
717
// Form Helpers.
718
//
719
720
/**
721
 * Display a <select> form element filled with a list of post types.
722
 *
723
 * The value of the 'selected' option is 'ALL' by default, which corresponds to the
724
 * 'Any' option ('ALL' is an invalid post type name).
725
 *
726
 * @since 1.0.0
727
 * @since 1.5.1 The 'filter' option was added.
728
 *
729
 * @param array $options {
730
 *        An array of display options.
731
 *
732
 *        @type string $name     The value for the name attribute of the element.
733
 *        @type string $id       The value for the id attribute of the element.
734
 *        @type string $selected The name of the selected points type.
735
 *        @type string $class    The value for the class attribute of the element.
736
 *        @type callable $filter A boolean callback function to filter the post types
737
 *                               with. It will be passed the post type object.
738
 * }
739
 * @param array $args Arguments to pass to get_post_types(). Default is array().
740
 */
741
function wordpoints_list_post_types( $options, $args = array() ) {
742
743
	$defaults = array(
744
		'name'     => '',
745
		'id'       => '',
746
		'selected' => 'ALL',
747
		'class'    => '',
748
		'filter'   => null,
749
	);
750
751
	$options = array_merge( $defaults, $options );
752
753
	echo '<select class="' . esc_attr( $options['class'] ) . '" name="' . esc_attr( $options['name'] ) . '" id="' . esc_attr( $options['id'] ) . '">';
754
	echo '<option value="ALL"' . selected( $options['selected'], 'ALL', false ) . '>' . esc_html_x( 'Any', 'post type', 'wordpoints' ) . '</option>';
755
756
	foreach ( get_post_types( $args, 'objects' ) as $post_type ) {
757
758
		if ( isset( $options['filter'] ) && ! call_user_func( $options['filter'], $post_type ) ) {
759
			continue;
760
		}
761
762
		echo '<option value="' . esc_attr( $post_type->name ) . '"' . selected( $options['selected'], $post_type->name, false ) . '>' . esc_html( $post_type->label ) . '</option>';
763
	}
764
765
	echo '</select>';
766
}
767
768
//
769
// Miscellaneous.
770
//
771
772
/**
773
 * Check if the plugin is network activated.
774
 *
775
 * @since 1.2.0
776
 *
777
 * @return bool True if WordPoints is network activated, false otherwise.
778
 */
779
function is_wordpoints_network_active() {
780
781
	require_once ABSPATH . '/wp-admin/includes/plugin.php';
782
783
	$network_active = is_plugin_active_for_network(
784
		plugin_basename( WORDPOINTS_DIR . 'wordpoints.php' )
785
	);
786
787
	/**
788
	 * Filter whether the plugin is network active.
789
	 *
790
	 * This is primarily used during install, when the above checks won't work. It's
791
	 * not really intended for general use.
792
	 *
793
	 * @since 1.3.0
794
	 *
795
	 * @param bool $network_active Whether WordPoints is network activated.
796
	 */
797
	return apply_filters( 'is_wordpoints_network_active', $network_active );
798
}
799
800
/**
801
 * Retrieve an array of the IDs of excluded users.
802
 *
803
 * @since 1.0.0
804
 *
805
 * @uses apply_filters() Calls 'wordpoints_excluded_users' with the array of user IDs
806
 *       and the $context.
807
 *
808
 * @param string $context The context in which the list will be used. Useful in
809
 *        filtering.
810
 *
811
 * @return array An array of user IDs to exclude in the current $context.
812
 */
813
function wordpoints_get_excluded_users( $context ) {
814
815
	$user_ids = wordpoints_get_maybe_network_array_option(
816
		'wordpoints_excluded_users'
817
	);
818
819
	/**
820
	 * Excluded users option.
821
	 *
822
	 * This option is set on the Configure > Settings administration panel.
823
	 *
824
	 * @since 1.0.0
825
	 *
826
	 * @param int[]  $user_ids The ids of the user's to be excluded.
827
	 * @param string $context  The context in which the function is being called.
828
	 */
829
	return apply_filters( 'wordpoints_excluded_users', $user_ids, $context );
830
}
831
832
/**
833
 * Give a shortcode error.
834
 *
835
 * The error is only displayed to those with the 'manage_options' capability, or if
836
 * the shortcode is being displayed in a post that the current user can edit.
837
 *
838
 * @since 1.0.1
839
 * @since 1.8.0 The $message now supports WP_Error objects.
840
 *
841
 * @param string|WP_Error $message The error message.
842
 *
843
 * @return string The error message.
844
 */
845
function wordpoints_shortcode_error( $message ) {
846
847
	if (
848
		( get_post() && current_user_can( 'edit_post', get_the_ID() ) )
849
		|| current_user_can( 'manage_options' )
850
	) {
851
852
		if ( is_wp_error( $message ) ) {
853
			$message = $message->get_error_message();
854
		}
855
856
		return '<p class="wordpoints-shortcode-error">' . esc_html__( 'Shortcode error:', 'wordpoints' ) . ' ' . wp_kses( $message, 'wordpoints_shortcode_error' ) . '</p>';
857
	}
858
859
	return '';
860
}
861
862
/**
863
 * Get the custom capabilities.
864
 *
865
 * @since 1.3.0
866
 *
867
 * @return array The custom capabilities as keys, WP core counterparts as values.
868
 */
869
function wordpoints_get_custom_caps() {
870
871
	return array(
872
		'install_wordpoints_modules'        => 'install_plugins',
873
		'manage_network_wordpoints_modules' => 'manage_network_plugins',
874
		'activate_wordpoints_modules'       => 'activate_plugins',
875
		'delete_wordpoints_modules'         => 'delete_plugins',
876
	);
877
}
878
879
/**
880
 * Add custom capabilities to the desired roles.
881
 *
882
 * Used during installation.
883
 *
884
 * @since 1.3.0
885
 *
886
 * @param array $capabilities The capabilities to add as keys, WP core counterparts
887
 *                            as values.
888
 */
889
function wordpoints_add_custom_caps( $capabilities ) {
890
891
	/** @var WP_Role $role */
892
	foreach ( wp_roles()->role_objects as $role ) {
893
894
		foreach ( $capabilities as $custom_cap => $core_cap ) {
895
			if ( $role->has_cap( $core_cap ) ) {
896
				$role->add_cap( $custom_cap );
897
			}
898
		}
899
	}
900
}
901
902
/**
903
 * Remove custom capabilities.
904
 *
905
 * Used during uninstallation.
906
 *
907
 * @since 1.3.0
908
 *
909
 * @param string[] $capabilities The list of capabilities to remove.
910
 */
911
function wordpoints_remove_custom_caps( $capabilities ) {
912
913
	/** @var WP_Role $role */
914
	foreach ( wp_roles()->role_objects as $role ) {
915
		foreach ( $capabilities as $custom_cap ) {
916
			$role->remove_cap( $custom_cap );
917
		}
918
	}
919
}
920
921
/**
922
 * Map custom meta capabilities.
923
 *
924
 * @since 1.4.0
925
 *
926
 * @WordPress\filter map_meta_cap
927
 *
928
 * @param array  $caps    The user's capabilities.
929
 * @param string $cap     The current capability in question.
930
 * @param int    $user_id The ID of the user whose caps are being checked.
931
 *
932
 * @return array The user's capabilities.
933
 */
934
function wordpoints_map_custom_meta_caps( $caps, $cap, $user_id ) {
935
936
	switch ( $cap ) {
937
		case 'install_wordpoints_modules':
938
			if ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS ) {
939
				$caps[] = 'do_not_allow';
940
			} elseif ( is_multisite() && ! is_super_admin( $user_id ) ) {
941
				$caps[] = 'do_not_allow';
942
			} else {
943
				$caps[] = $cap;
944
			}
945
		break;
946
	}
947
948
	return $caps;
949
}
950
951
/**
952
 * Component registration wrapper.
953
 *
954
 * @since 1.0.0
955
 *
956
 * @uses WordPoints_Components::register()
957
 *
958
 * @param array $args The component args.
959
 *
960
 * @return bool Whether the component was registered.
961
 */
962
function wordpoints_component_register( $args ) {
963
964
	return WordPoints_Components::instance()->register( $args );
965
}
966
967
/**
968
 * Component activation check wrapper.
969
 *
970
 * @since 1.0.0
971
 *
972
 * @uses WordPoints_Components::is_active()
973
 *
974
 * @param string $slug The component slug.
975
 *
976
 * @return bool Whether the component is active.
977
 */
978
function wordpoints_component_is_active( $slug ) {
979
980
	return WordPoints_Components::instance()->is_active( $slug );
981
}
982
983
/**
984
 * Register the points component.
985
 *
986
 * @since 1.0.0
987
 *
988
 * @WordPress\action wordpoints_components_register
989
 *
990
 * @uses wordpoints_component_register()
991
 */
992 View Code Duplication
function wordpoints_points_component_register() {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in 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...
993
994
	wordpoints_component_register(
995
		array(
996
			'slug'          => 'points',
997
			'name'          => _x( 'Points', 'component name', 'wordpoints' ),
998
			'version'       => WORDPOINTS_VERSION,
999
			'author'        => _x( 'WordPoints', 'component author', 'wordpoints' ),
1000
			'author_uri'    => 'https://wordpoints.org/',
1001
			'component_uri' => 'https://wordpoints.org/',
1002
			'description'   => __( 'Enables a points system for your site.', 'wordpoints' ),
1003
			'file'          => WORDPOINTS_DIR . 'components/points/points.php',
1004
			'un_installer'  => WORDPOINTS_DIR . 'components/points/includes/class-un-installer.php',
1005
		)
1006
	);
1007
}
1008
1009
/**
1010
 * Register the ranks component.
1011
 *
1012
 * @since 1.7.0
1013
 *
1014
 * @WordPress\action wordpoints_components_register
1015
 */
1016 View Code Duplication
function wordpoints_ranks_component_register() {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in 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...
1017
1018
	wordpoints_component_register(
1019
		array(
1020
			'slug'           => 'ranks',
1021
			'name'           => _x( 'Ranks', 'component name', 'wordpoints' ),
1022
			'version'        => WORDPOINTS_VERSION,
1023
			'author'         => _x( 'WordPoints', 'component author', 'wordpoints' ),
1024
			'author_uri'     => 'https://wordpoints.org/',
1025
			'component_uri'  => 'https://wordpoints.org/',
1026
			'description'    => __( 'Assign users ranks based on their points levels.', 'wordpoints' ),
1027
			'file'           => WORDPOINTS_DIR . 'components/ranks/ranks.php',
1028
			'un_installer'   => WORDPOINTS_DIR . 'components/ranks/includes/class-un-installer.php',
1029
		)
1030
	);
1031
}
1032
1033
/**
1034
 * Initialize the plugin's cache groups.
1035
 *
1036
 * @since 1.10.0
1037
 *
1038
 * @WordPress\action init 5 Earlier than the default so that the groups will be
1039
 *                          registered before any other code runs.
1040
 */
1041
function wordpoints_init_cache_groups() {
1042
1043
	if ( function_exists( 'wp_cache_add_non_persistent_groups' ) ) {
1044
		wp_cache_add_non_persistent_groups( array( 'wordpoints_modules' ) );
1045
	}
1046
1047
	if ( function_exists( 'wp_cache_add_global_groups' ) ) {
1048
1049
		wp_cache_add_global_groups(
1050
			array(
1051
				'wordpoints_hook_periods',
1052
				'wordpoints_hook_period_ids_by_reaction',
1053
			)
1054
		);
1055
	}
1056
}
1057
1058
/**
1059
 * Register scripts and styles.
1060
 *
1061
 * It is run on both the front and back end with a priority of 5, so the scripts will
1062
 * all be registered when we want to enqueue them, usually on the default priority of
1063
 * 10.
1064
 *
1065
 * @since 1.0.0
1066
 *
1067
 * @WordPress\action wp_enqueue_scripts    5 Front-end scripts enqueued.
1068
 * @WordPress\action admin_enqueue_scripts 5 Admin scripts enqueued.
1069
 */
1070
function wordpoints_register_scripts() {}
1071
1072
/**
1073
 * Load the plugin's textdomain.
1074
 *
1075
 * @since 1.1.0
1076
 *
1077
 * @WordPress\action plugins_loaded
1078
 */
1079
function wordpoints_load_textdomain() {
1080
1081
	load_plugin_textdomain( 'wordpoints', false, plugin_basename( WORDPOINTS_DIR ) . '/languages/' );
1082
}
1083
1084
/**
1085
 * Generate a cryptographically secure hash.
1086
 *
1087
 * You can use wp_hash() instead if you need to use a salt. However, at present that
1088
 * function uses the outdated MD5 hashing algorithm, so you will want to take that
1089
 * into consideration as well. The benefit of using this function instead is that it
1090
 * will use a strong hashing algorithm, and the hashes won't be invalidated when the
1091
 * salts change.
1092
 *
1093
 * @since 2.0.1
1094
 *
1095
 * @param string $data The data to generate a hash for.
1096
 *
1097
 * @return string The hash.
1098
 */
1099
function wordpoints_hash( $data ) {
1100
	return hash( 'sha256', $data );
1101
}
1102
1103
/**
1104
 * Construct a class with a variable number of args.
1105
 *
1106
 * @since 2.1.0
1107
 *
1108
 * @param string $class_name The name of the class to construct.
1109
 * @param array  $args       Up to 4 args to pass to the constructor.
1110
 *
1111
 * @return object|false The constructed object, or false if to many args were passed.
1112
 */
1113
function wordpoints_construct_class_with_args( $class_name, array $args ) {
1114
1115
	switch ( count( $args ) ) {
1116
		case 0:
1117
			return new $class_name();
1118
		case 1:
1119
			return new $class_name( $args[0] );
1120
		case 2:
1121
			return new $class_name( $args[0], $args[1] );
1122
		case 3:
1123
			return new $class_name( $args[0], $args[1], $args[2] );
1124
		case 4:
1125
			return new $class_name( $args[0], $args[1], $args[2], $args[3] );
1126
		default:
1127
			return false;
1128
	}
1129
}
1130
1131
/**
1132
 * Check if a function is disabled by PHP's `disabled_functions` INI directive.
1133
 *
1134
 * @since 2.2.0
1135
 *
1136
 * @param string $function The name of the function to check.
1137
 *
1138
 * @return bool Whether the function is disabled.
1139
 */
1140
function wordpoints_is_function_disabled( $function ) {
1141
1142
	if ( 'set_time_limit' === $function && ini_get( 'safe_mode' ) ) {
1143
		return true;
1144
	}
1145
1146
	return in_array( $function, explode( ',', ini_get( 'disable_functions' ) ) );
1147
}
1148
1149
// EOF
1150