1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace voku\helper; |
6
|
|
|
|
7
|
|
|
/** |
8
|
|
|
* PHP Hooks Class (Modified) |
9
|
|
|
* |
10
|
|
|
* <p> |
11
|
|
|
* <br /> |
12
|
|
|
* The PHP Hooks Class is a fork of the WordPress filters hook system rolled in |
13
|
|
|
* to a class to be ported into any php based system |
14
|
|
|
* |
15
|
|
|
* <br /><br /> |
16
|
|
|
* This class is heavily based on the WordPress plugin API and most (if not all) |
17
|
|
|
* of the code comes from there. |
18
|
|
|
* </p> |
19
|
|
|
* |
20
|
|
|
* @copyright 2011 - 2018 |
21
|
|
|
* |
22
|
|
|
* @author Ohad Raz <[email protected]> |
23
|
|
|
* @link http://en.bainternet.info |
24
|
|
|
* @author David Miles <[email protected]> |
25
|
|
|
* @link http://github.com/amereservant/PHP-Hooks |
26
|
|
|
* @author Lars Moelleken <[email protected]> |
27
|
|
|
* @link https://github.com/voku/PHP-Hooks/ |
28
|
|
|
* @author Damien "Mistic" Sorel <[email protected]> |
29
|
|
|
* @link http://www.strangeplanet.fr |
30
|
|
|
* |
31
|
|
|
* @license GNU General Public License v3.0 - license.txt |
32
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
33
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
34
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE |
35
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
36
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
37
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
38
|
|
|
* THE SOFTWARE. |
39
|
|
|
* |
40
|
|
|
* @package voku\helper |
41
|
|
|
*/ |
42
|
|
|
class Hooks |
43
|
|
|
{ |
44
|
|
|
/** |
45
|
|
|
* Filters - holds list of hooks |
46
|
|
|
* |
47
|
|
|
* @var array |
48
|
|
|
*/ |
49
|
|
|
protected $filters = []; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* Merged Filters |
53
|
|
|
* |
54
|
|
|
* @var array |
55
|
|
|
*/ |
56
|
|
|
protected $merged_filters = []; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Actions |
60
|
|
|
* |
61
|
|
|
* @var array |
62
|
|
|
*/ |
63
|
|
|
protected $actions = []; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Current Filter - holds the name of the current filter |
67
|
|
|
* |
68
|
|
|
* @var array |
69
|
|
|
*/ |
70
|
|
|
protected $current_filter = []; |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Container for storing shortcode tags and their hook to call for the shortcode |
74
|
|
|
* |
75
|
|
|
* @var array |
76
|
|
|
*/ |
77
|
|
|
public static $shortcode_tags = []; |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* Default priority |
81
|
|
|
* |
82
|
|
|
* @const int |
83
|
|
|
*/ |
84
|
|
|
const PRIORITY_NEUTRAL = 50; |
85
|
|
|
|
86
|
|
|
/** |
87
|
1 |
|
* This class is not allowed to call from outside: private! |
88
|
|
|
*/ |
89
|
1 |
|
protected function __construct() |
90
|
|
|
{ |
91
|
|
|
} |
92
|
|
|
|
93
|
|
|
/** |
94
|
|
|
* Prevent the object from being cloned. |
95
|
|
|
*/ |
96
|
|
|
protected function __clone() |
97
|
|
|
{ |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* Avoid serialization. |
102
|
|
|
*/ |
103
|
|
|
public function __wakeup() |
104
|
|
|
{ |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* Returns a Singleton instance of this class. |
109
|
|
|
* |
110
|
10 |
|
* @return Hooks |
111
|
|
|
*/ |
112
|
10 |
|
public static function getInstance(): self |
113
|
|
|
{ |
114
|
10 |
|
static $instance; |
115
|
1 |
|
|
116
|
1 |
|
if (null === $instance) { |
117
|
|
|
$instance = new self(); |
118
|
10 |
|
} |
119
|
|
|
|
120
|
|
|
return $instance; |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* FILTERS |
125
|
|
|
*/ |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* Adds Hooks to a function or method to a specific filter action. |
129
|
|
|
* |
130
|
|
|
* @param string $tag <p> |
131
|
|
|
* The name of the filter to hook the |
132
|
|
|
* {@link $function_to_add} to. |
133
|
|
|
* </p> |
134
|
|
|
* @param string|array|object $function_to_add <p> |
135
|
|
|
* The name of the function to be called |
136
|
|
|
* when the filter is applied. |
137
|
|
|
* </p> |
138
|
|
|
* @param int $priority <p> |
139
|
|
|
* [optional] Used to specify the order in |
140
|
|
|
* which the functions associated with a |
141
|
|
|
* particular action are executed (default: 50). |
142
|
|
|
* Lower numbers correspond with earlier execution, |
143
|
|
|
* and functions with the same priority are executed |
144
|
|
|
* in the order in which they were added to the action. |
145
|
|
|
* </p> |
146
|
|
|
* @param string $include_path <p> |
147
|
|
|
* [optional] File to include before executing the callback. |
148
|
|
|
* </p> |
149
|
|
|
* |
150
|
7 |
|
* @return bool |
151
|
|
|
*/ |
152
|
7 |
|
public function add_filter(string $tag, $function_to_add, int $priority = self::PRIORITY_NEUTRAL, string $include_path = null): bool |
153
|
|
|
{ |
154
|
7 |
|
$idx = $this->_filter_build_unique_id($function_to_add); |
155
|
7 |
|
|
156
|
7 |
|
$this->filters[$tag][$priority][$idx] = [ |
157
|
|
|
'function' => $function_to_add, |
158
|
|
|
'include_path' => \is_string($include_path) ? $include_path : null, |
159
|
7 |
|
]; |
160
|
|
|
|
161
|
7 |
|
unset($this->merged_filters[$tag]); |
162
|
|
|
|
163
|
|
|
return true; |
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* Removes a function from a specified filter hook. |
168
|
|
|
* |
169
|
|
|
* @param string $tag <p>The filter hook to which the function to be removed is |
170
|
|
|
* hooked.</p> |
171
|
|
|
* @param string|array|object $function_to_remove <p>The name of the function which should be removed.</p> |
172
|
|
|
* @param int $priority <p>[optional] The priority of the function (default: 50).</p> |
173
|
1 |
|
* |
174
|
|
|
* @return bool |
175
|
1 |
|
*/ |
176
|
|
|
public function remove_filter(string $tag, $function_to_remove, int $priority = self::PRIORITY_NEUTRAL): bool |
177
|
1 |
|
{ |
178
|
1 |
|
$function_to_remove = $this->_filter_build_unique_id($function_to_remove); |
179
|
|
|
|
180
|
|
|
if (!isset($this->filters[$tag][$priority][$function_to_remove])) { |
181
|
1 |
|
return false; |
182
|
1 |
|
} |
183
|
1 |
|
|
184
|
1 |
|
unset($this->filters[$tag][$priority][$function_to_remove]); |
185
|
|
|
if (empty($this->filters[$tag][$priority])) { |
186
|
1 |
|
unset($this->filters[$tag][$priority]); |
187
|
|
|
} |
188
|
1 |
|
|
189
|
|
|
unset($this->merged_filters[$tag]); |
190
|
|
|
|
191
|
|
|
return true; |
192
|
|
|
} |
193
|
|
|
|
194
|
|
|
/** |
195
|
|
|
* Remove all of the hooks from a filter. |
196
|
|
|
* |
197
|
|
|
* @param string $tag <p>The filter to remove hooks from.</p> |
198
|
|
|
* @param false|int $priority <p>The priority number to remove.</p> |
199
|
4 |
|
* |
200
|
|
|
* @return bool |
201
|
4 |
|
*/ |
202
|
|
|
public function remove_all_filters(string $tag, $priority = false): bool |
203
|
|
|
{ |
204
|
|
|
if (isset($this->merged_filters[$tag])) { |
205
|
4 |
|
unset($this->merged_filters[$tag]); |
206
|
2 |
|
} |
207
|
|
|
|
208
|
|
|
if (!isset($this->filters[$tag])) { |
209
|
2 |
|
return true; |
210
|
1 |
|
} |
211
|
1 |
|
|
212
|
2 |
|
if (false !== $priority && isset($this->filters[$tag][$priority])) { |
213
|
|
|
unset($this->filters[$tag][$priority]); |
214
|
|
|
} else { |
215
|
2 |
|
unset($this->filters[$tag]); |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
return true; |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* Check if any filter has been registered for the given hook. |
223
|
|
|
* |
224
|
|
|
* <p> |
225
|
|
|
* <br /> |
226
|
|
|
* <strong>INFO:</strong> Use !== false to check if it's true! |
227
|
|
|
* </p> |
228
|
|
|
* |
229
|
|
|
* @param string $tag <p>The name of the filter hook.</p> |
230
|
|
|
* @param false|string $function_to_check <p>[optional] Callback function name to check for </p> |
231
|
|
|
* |
232
|
|
|
* @return mixed <p> |
233
|
|
|
* If {@link $function_to_check} is omitted, |
234
|
|
|
* returns boolean for whether the hook has |
235
|
|
|
* anything registered. |
236
|
|
|
* When checking a specific function, the priority |
237
|
|
|
* of that hook is returned, or false if the |
238
|
|
|
* function is not attached. |
239
|
|
|
* When using the {@link $function_to_check} argument, |
240
|
|
|
* this function may return a non-boolean value that |
241
|
|
|
* evaluates to false |
242
|
3 |
|
* (e.g.) 0, so use the === operator for testing the return value. |
243
|
|
|
* </p> |
244
|
3 |
|
*/ |
245
|
3 |
|
public function has_filter(string $tag, $function_to_check = false) |
246
|
3 |
|
{ |
247
|
|
|
$has = isset($this->filters[$tag]); |
248
|
|
|
if (false === $function_to_check || !$has) { |
249
|
3 |
|
return $has; |
250
|
|
|
} |
251
|
|
|
|
252
|
|
|
if (!($idx = $this->_filter_build_unique_id($function_to_check))) { |
253
|
3 |
|
return false; |
254
|
3 |
|
} |
255
|
3 |
|
|
256
|
|
|
foreach (\array_keys($this->filters[$tag]) as $priority) { |
257
|
2 |
|
if (isset($this->filters[$tag][$priority][$idx])) { |
258
|
|
|
return $priority; |
259
|
2 |
|
} |
260
|
|
|
} |
261
|
|
|
|
262
|
|
|
return false; |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* Call the functions added to a filter hook. |
267
|
|
|
* |
268
|
|
|
* <p> |
269
|
|
|
* <br /> |
270
|
|
|
* <strong>INFO:</strong> Additional variables passed to the functions hooked to <tt>$tag</tt>. |
271
|
|
|
* </p> |
272
|
|
|
* |
273
|
|
|
* @param string $tag <p>The name of the filter hook.</p> |
274
|
|
|
* @param mixed $value <p>The value on which the filters hooked to <tt>$tag</tt> are applied on.</p> |
275
|
4 |
|
* |
276
|
|
|
* @return mixed <p>The filtered value after all hooked functions are applied to it.</p> |
277
|
4 |
|
*/ |
278
|
|
|
public function apply_filters(string $tag, $value) |
279
|
|
|
{ |
280
|
4 |
|
$args = []; |
281
|
1 |
|
|
282
|
1 |
|
// Do 'all' actions first |
283
|
1 |
View Code Duplication |
if (isset($this->filters['all'])) { |
|
|
|
|
284
|
1 |
|
$this->current_filter[] = $tag; |
285
|
|
|
$args = \func_get_args(); |
286
|
4 |
|
$this->_call_all_hook($args); |
287
|
1 |
|
} |
288
|
1 |
|
|
289
|
1 |
View Code Duplication |
if (!isset($this->filters[$tag])) { |
|
|
|
|
290
|
|
|
if (isset($this->filters['all'])) { |
291
|
1 |
|
\array_pop($this->current_filter); |
292
|
|
|
} |
293
|
|
|
|
294
|
4 |
|
return $value; |
295
|
4 |
|
} |
296
|
4 |
|
|
297
|
|
|
if (!isset($this->filters['all'])) { |
298
|
|
|
$this->current_filter[] = $tag; |
299
|
4 |
|
} |
300
|
3 |
|
|
301
|
3 |
|
// Sort |
302
|
3 |
View Code Duplication |
if (!isset($this->merged_filters[$tag])) { |
|
|
|
|
303
|
|
|
\ksort($this->filters[$tag]); |
304
|
4 |
|
$this->merged_filters[$tag] = true; |
305
|
|
|
} |
306
|
4 |
|
|
307
|
4 |
|
\reset($this->filters[$tag]); |
308
|
4 |
|
|
309
|
|
|
if (empty($args)) { |
310
|
4 |
|
$args = \func_get_args(); |
311
|
|
|
} |
312
|
|
|
|
313
|
4 |
|
\array_shift($args); |
314
|
4 |
|
|
315
|
|
|
do { |
316
|
4 |
|
foreach ((array)\current($this->filters[$tag]) as $the_) { |
317
|
|
|
if (null !== $the_['function']) { |
318
|
|
|
|
319
|
|
|
if (null !== $the_['include_path']) { |
320
|
|
|
/** @noinspection PhpIncludeInspection */ |
321
|
4 |
|
include_once $the_['include_path']; |
322
|
4 |
|
} |
323
|
4 |
|
|
324
|
4 |
|
$args[0] = $value; |
325
|
4 |
|
$value = \call_user_func_array($the_['function'], $args); |
326
|
|
|
} |
327
|
4 |
|
} |
328
|
|
|
} while (\next($this->filters[$tag]) !== false); |
329
|
4 |
|
|
330
|
|
|
\array_pop($this->current_filter); |
331
|
|
|
|
332
|
|
|
return $value; |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
/** |
336
|
|
|
* Execute functions hooked on a specific filter hook, specifying arguments in an array. |
337
|
|
|
* |
338
|
|
|
* @param string $tag <p>The name of the filter hook.</p> |
339
|
|
|
* @param array $args <p>The arguments supplied to the functions hooked to <tt>$tag</tt></p> |
340
|
1 |
|
* |
341
|
|
|
* @return mixed <p>The filtered value after all hooked functions are applied to it.</p> |
342
|
|
|
*/ |
343
|
1 |
|
public function apply_filters_ref_array(string $tag, array $args) |
344
|
1 |
|
{ |
345
|
1 |
|
// Do 'all' actions first |
346
|
1 |
View Code Duplication |
if (isset($this->filters['all'])) { |
|
|
|
|
347
|
1 |
|
$this->current_filter[] = $tag; |
348
|
|
|
$all_args = \func_get_args(); |
349
|
1 |
|
$this->_call_all_hook($all_args); |
350
|
1 |
|
} |
351
|
|
|
|
352
|
|
View Code Duplication |
if (!isset($this->filters[$tag])) { |
|
|
|
|
353
|
|
|
if (isset($this->filters['all'])) { |
354
|
1 |
|
\array_pop($this->current_filter); |
355
|
|
|
} |
356
|
|
|
|
357
|
1 |
|
return $args[0]; |
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
if (!isset($this->filters['all'])) { |
361
|
|
|
$this->current_filter[] = $tag; |
362
|
1 |
|
} |
363
|
|
|
|
364
|
|
|
// Sort |
365
|
|
View Code Duplication |
if (!isset($this->merged_filters[$tag])) { |
|
|
|
|
366
|
|
|
\ksort($this->filters[$tag]); |
367
|
1 |
|
$this->merged_filters[$tag] = true; |
368
|
|
|
} |
369
|
|
|
|
370
|
1 |
|
\reset($this->filters[$tag]); |
371
|
1 |
|
|
372
|
|
View Code Duplication |
do { |
|
|
|
|
373
|
1 |
|
foreach ((array)\current($this->filters[$tag]) as $the_) { |
374
|
|
|
if (null !== $the_['function']) { |
375
|
|
|
|
376
|
|
|
if (null !== $the_['include_path']) { |
377
|
|
|
/** @noinspection PhpIncludeInspection */ |
378
|
1 |
|
include_once $the_['include_path']; |
379
|
1 |
|
} |
380
|
1 |
|
|
381
|
1 |
|
$args[0] = \call_user_func_array($the_['function'], $args); |
382
|
|
|
} |
383
|
1 |
|
} |
384
|
|
|
} while (\next($this->filters[$tag]) !== false); |
385
|
1 |
|
|
386
|
|
|
\array_pop($this->current_filter); |
387
|
|
|
|
388
|
|
|
return $args[0]; |
389
|
|
|
} |
390
|
|
|
|
391
|
|
|
/** |
392
|
|
|
* Hooks a function on to a specific action. |
393
|
|
|
* |
394
|
|
|
* @param string $tag <p> |
395
|
|
|
* The name of the action to which the |
396
|
|
|
* <tt>$function_to_add</tt> is hooked. |
397
|
|
|
* </p> |
398
|
|
|
* @param string|array $function_to_add <p>The name of the function you wish to be called.</p> |
399
|
|
|
* @param int $priority <p> |
400
|
|
|
* [optional] Used to specify the order in which |
401
|
|
|
* the functions associated with a particular |
402
|
|
|
* action are executed (default: 50). |
403
|
|
|
* Lower numbers correspond with earlier execution, |
404
|
|
|
* and functions with the same priority are executed |
405
|
|
|
* in the order in which they were added to the action. |
406
|
|
|
* </p> |
407
|
|
|
* @param string $include_path <p>[optional] File to include before executing the callback.</p> |
408
|
5 |
|
* |
409
|
|
|
* @return bool |
410
|
5 |
|
*/ |
411
|
|
|
public function add_action( |
412
|
|
|
string $tag, |
413
|
|
|
$function_to_add, |
414
|
|
|
int $priority = self::PRIORITY_NEUTRAL, |
415
|
|
|
string $include_path = null |
416
|
|
|
): bool |
417
|
|
|
{ |
418
|
|
|
return $this->add_filter($tag, $function_to_add, $priority, $include_path); |
419
|
|
|
} |
420
|
|
|
|
421
|
|
|
/** |
422
|
|
|
* Check if any action has been registered for a hook. |
423
|
|
|
* |
424
|
|
|
* <p> |
425
|
|
|
* <br /> |
426
|
|
|
* <strong>INFO:</strong> Use !== false to check if it's true! |
427
|
|
|
* </p> |
428
|
|
|
* |
429
|
|
|
* @param string $tag <p>The name of the action hook.</p> |
430
|
|
|
* @param false|string $function_to_check <p>[optional]</p> |
431
|
|
|
* |
432
|
|
|
* @return mixed <p> |
433
|
|
|
* If <tt>$function_to_check</tt> is omitted, |
434
|
|
|
* returns boolean for whether the hook has |
435
|
|
|
* anything registered. |
436
|
|
|
* When checking a specific function, |
437
|
3 |
|
* the priority of that hook is returned, |
438
|
|
|
* or false if the function is not attached. |
439
|
3 |
|
* When using the <tt>$function_to_check</tt> |
440
|
|
|
* argument, this function may return a non-boolean |
441
|
|
|
* value that evaluates to false (e.g.) 0, |
442
|
|
|
* so use the === operator for testing the return value. |
443
|
|
|
* </p> |
444
|
|
|
*/ |
445
|
|
|
public function has_action(string $tag, $function_to_check = false) |
446
|
|
|
{ |
447
|
|
|
return $this->has_filter($tag, $function_to_check); |
448
|
|
|
} |
449
|
|
|
|
450
|
|
|
/** |
451
|
1 |
|
* Removes a function from a specified action hook. |
452
|
|
|
* |
453
|
1 |
|
* @param string $tag <p>The action hook to which the function to be removed is hooked.</p> |
454
|
|
|
* @param mixed $function_to_remove <p>The name of the function which should be removed.</p> |
455
|
|
|
* @param int $priority <p>[optional] The priority of the function (default: 50).</p> |
456
|
|
|
* |
457
|
|
|
* @return bool <p>Whether the function is removed.</p> |
458
|
|
|
*/ |
459
|
|
|
public function remove_action(string $tag, $function_to_remove, int $priority = self::PRIORITY_NEUTRAL): bool |
460
|
|
|
{ |
461
|
|
|
return $this->remove_filter($tag, $function_to_remove, $priority); |
462
|
|
|
} |
463
|
|
|
|
464
|
4 |
|
/** |
465
|
|
|
* Remove all of the hooks from an action. |
466
|
4 |
|
* |
467
|
|
|
* @param string $tag <p>The action to remove hooks from.</p> |
468
|
|
|
* @param false|int $priority <p>The priority number to remove them from.</p> |
469
|
|
|
* |
470
|
|
|
* @return bool |
471
|
|
|
*/ |
472
|
|
|
public function remove_all_actions(string $tag, $priority = false): bool |
473
|
|
|
{ |
474
|
|
|
return $this->remove_all_filters($tag, $priority); |
475
|
|
|
} |
476
|
|
|
|
477
|
|
|
/** |
478
|
|
|
* Execute functions hooked on a specific action hook. |
479
|
|
|
* |
480
|
2 |
|
* @param string $tag <p>The name of the action to be executed.</p> |
481
|
|
|
* @param mixed $arg <p> |
482
|
2 |
|
* [optional] Additional arguments which are passed on |
483
|
|
|
* to the functions hooked to the action. |
484
|
|
|
* </p> |
485
|
|
|
* |
486
|
2 |
|
* @return bool <p>Will return false if $tag does not exist in $filter array.</p> |
487
|
2 |
|
*/ |
488
|
2 |
|
public function do_action(string $tag, $arg = ''): bool |
489
|
1 |
|
{ |
490
|
|
|
if (!\is_array($this->actions)) { |
491
|
|
|
$this->actions = []; |
492
|
|
|
} |
493
|
2 |
|
|
494
|
1 |
View Code Duplication |
if (isset($this->actions[$tag])) { |
|
|
|
|
495
|
1 |
|
++$this->actions[$tag]; |
496
|
1 |
|
} else { |
497
|
1 |
|
$this->actions[$tag] = 1; |
498
|
|
|
} |
499
|
2 |
|
|
500
|
1 |
|
// Do 'all' actions first |
501
|
1 |
View Code Duplication |
if (isset($this->filters['all'])) { |
|
|
|
|
502
|
1 |
|
$this->current_filter[] = $tag; |
503
|
|
|
$all_args = \func_get_args(); |
504
|
1 |
|
$this->_call_all_hook($all_args); |
505
|
|
|
} |
506
|
|
|
|
507
|
2 |
View Code Duplication |
if (!isset($this->filters[$tag])) { |
|
|
|
|
508
|
2 |
|
if (isset($this->filters['all'])) { |
509
|
2 |
|
\array_pop($this->current_filter); |
510
|
|
|
} |
511
|
2 |
|
|
512
|
|
|
return false; |
513
|
|
|
} |
514
|
2 |
|
|
515
|
2 |
|
if (!isset($this->filters['all'])) { |
516
|
|
|
$this->current_filter[] = $tag; |
517
|
2 |
|
} |
518
|
|
|
|
519
|
2 |
|
$args = []; |
520
|
|
|
|
521
|
2 |
|
if ( |
522
|
|
|
\is_array($arg) |
523
|
|
|
&& |
524
|
2 |
|
isset($arg[0]) |
525
|
|
|
&& |
526
|
|
|
\is_object($arg[0]) |
527
|
2 |
|
&& |
528
|
|
|
1 == \count($arg) |
529
|
2 |
|
) { |
530
|
1 |
|
$args[] =& $arg[0]; |
531
|
1 |
|
} else { |
532
|
|
|
$args[] = $arg; |
533
|
|
|
} |
534
|
2 |
|
|
535
|
2 |
|
$numArgs = \func_num_args(); |
536
|
2 |
|
|
537
|
2 |
|
for ($a = 2; $a < $numArgs; $a++) { |
538
|
|
|
$args[] = \func_get_arg($a); |
539
|
2 |
|
} |
540
|
|
|
|
541
|
|
|
// Sort |
542
|
2 |
View Code Duplication |
if (!isset($this->merged_filters[$tag])) { |
|
|
|
|
543
|
2 |
|
\ksort($this->filters[$tag]); |
544
|
|
|
$this->merged_filters[$tag] = true; |
545
|
2 |
|
} |
546
|
|
|
|
547
|
|
|
\reset($this->filters[$tag]); |
548
|
|
|
|
549
|
|
View Code Duplication |
do { |
|
|
|
|
550
|
2 |
|
foreach ((array)\current($this->filters[$tag]) as $the_) { |
551
|
2 |
|
if (null !== $the_['function']) { |
552
|
2 |
|
|
553
|
2 |
|
if (null !== $the_['include_path']) { |
554
|
|
|
/** @noinspection PhpIncludeInspection */ |
555
|
2 |
|
include_once $the_['include_path']; |
556
|
|
|
} |
557
|
2 |
|
|
558
|
|
|
\call_user_func_array($the_['function'], $args); |
559
|
|
|
} |
560
|
|
|
} |
561
|
|
|
} while (\next($this->filters[$tag]) !== false); |
562
|
|
|
|
563
|
|
|
\array_pop($this->current_filter); |
564
|
|
|
|
565
|
|
|
return true; |
566
|
|
|
} |
567
|
|
|
|
568
|
1 |
|
/** |
569
|
|
|
* Execute functions hooked on a specific action hook, specifying arguments in an array. |
570
|
1 |
|
* |
571
|
|
|
* @param string $tag <p>The name of the action to be executed.</p> |
572
|
|
|
* @param array $args <p>The arguments supplied to the functions hooked to <tt>$tag</tt></p> |
573
|
|
|
* |
574
|
1 |
|
* @return bool <p>Will return false if $tag does not exist in $filter array.</p> |
575
|
1 |
|
*/ |
576
|
1 |
|
public function do_action_ref_array(string $tag, array $args): bool |
577
|
1 |
|
{ |
578
|
|
|
if (!\is_array($this->actions)) { |
579
|
|
|
$this->actions = []; |
580
|
|
|
} |
581
|
1 |
|
|
582
|
1 |
View Code Duplication |
if (isset($this->actions[$tag])) { |
|
|
|
|
583
|
1 |
|
++$this->actions[$tag]; |
584
|
1 |
|
} else { |
585
|
1 |
|
$this->actions[$tag] = 1; |
586
|
|
|
} |
587
|
1 |
|
|
588
|
1 |
|
// Do 'all' actions first |
589
|
|
View Code Duplication |
if (isset($this->filters['all'])) { |
|
|
|
|
590
|
|
|
$this->current_filter[] = $tag; |
591
|
|
|
$all_args = \func_get_args(); |
592
|
1 |
|
$this->_call_all_hook($all_args); |
593
|
|
|
} |
594
|
|
|
|
595
|
1 |
View Code Duplication |
if (!isset($this->filters[$tag])) { |
|
|
|
|
596
|
|
|
if (isset($this->filters['all'])) { |
597
|
|
|
\array_pop($this->current_filter); |
598
|
|
|
} |
599
|
|
|
|
600
|
1 |
|
return false; |
601
|
1 |
|
} |
602
|
1 |
|
|
603
|
1 |
|
if (!isset($this->filters['all'])) { |
604
|
|
|
$this->current_filter[] = $tag; |
605
|
1 |
|
} |
606
|
|
|
|
607
|
|
|
// Sort |
608
|
1 |
View Code Duplication |
if (!isset($this->merged_filters[$tag])) { |
|
|
|
|
609
|
1 |
|
\ksort($this->filters[$tag]); |
610
|
|
|
$this->merged_filters[$tag] = true; |
611
|
1 |
|
} |
612
|
|
|
|
613
|
|
|
\reset($this->filters[$tag]); |
614
|
|
|
|
615
|
|
View Code Duplication |
do { |
|
|
|
|
616
|
1 |
|
foreach ((array)\current($this->filters[$tag]) as $the_) { |
617
|
1 |
|
if (null !== $the_['function']) { |
618
|
1 |
|
|
619
|
1 |
|
if (null !== $the_['include_path']) { |
620
|
|
|
/** @noinspection PhpIncludeInspection */ |
621
|
1 |
|
include_once $the_['include_path']; |
622
|
|
|
} |
623
|
1 |
|
|
624
|
|
|
\call_user_func_array($the_['function'], $args); |
625
|
|
|
} |
626
|
|
|
} |
627
|
|
|
} while (\next($this->filters[$tag]) !== false); |
628
|
|
|
|
629
|
|
|
\array_pop($this->current_filter); |
630
|
|
|
|
631
|
|
|
return true; |
632
|
|
|
} |
633
|
1 |
|
|
634
|
|
|
/** |
635
|
1 |
|
* Retrieve the number of times an action has fired. |
636
|
|
|
* |
637
|
|
|
* @param string $tag <p>The name of the action hook.</p> |
638
|
|
|
* |
639
|
1 |
|
* @return int <p>The number of times action hook <tt>$tag</tt> is fired.</p> |
640
|
|
|
*/ |
641
|
|
|
public function did_action(string $tag): int |
642
|
|
|
{ |
643
|
|
|
if (!\is_array($this->actions) || !isset($this->actions[$tag])) { |
644
|
|
|
return 0; |
645
|
|
|
} |
646
|
|
|
|
647
|
|
|
return $this->actions[$tag]; |
648
|
|
|
} |
649
|
|
|
|
650
|
|
|
/** |
651
|
|
|
* Retrieve the name of the current filter or action. |
652
|
|
|
* |
653
|
|
|
* @return string <p>Hook name of the current filter or action.</p> |
654
|
|
|
*/ |
655
|
|
|
public function current_filter(): string |
656
|
|
|
{ |
657
|
|
|
return \end($this->current_filter); |
658
|
|
|
} |
659
|
|
|
|
660
|
|
|
/** |
661
|
|
|
* Build Unique ID for storage and retrieval. |
662
|
|
|
* |
663
|
7 |
|
* @param string|array|object $function <p>Used for creating unique id.</p> |
664
|
|
|
* |
665
|
7 |
|
* @return string|false <p> |
666
|
3 |
|
* Unique ID for usage as array key or false if |
667
|
|
|
* $priority === false and $function is an |
668
|
|
|
* object reference, and it does not already have a unique id. |
669
|
4 |
|
* </p> |
670
|
|
|
*/ |
671
|
|
|
private function _filter_build_unique_id($function) |
672
|
2 |
|
{ |
673
|
2 |
|
if (\is_string($function)) { |
674
|
2 |
|
return $function; |
675
|
2 |
|
} |
676
|
2 |
|
|
677
|
|
|
if (\is_object($function)) { |
678
|
|
|
// Closures are currently implemented as objects |
679
|
4 |
|
$function = [ |
680
|
|
|
$function, |
681
|
4 |
|
'', |
682
|
|
|
]; |
683
|
|
|
} else { |
684
|
|
|
$function = (array)$function; |
685
|
|
|
} |
686
|
|
|
|
687
|
|
|
if (\is_object($function[0])) { |
688
|
|
|
// Object Class Calling |
689
|
|
|
return \spl_object_hash($function[0]) . $function[1]; |
690
|
|
|
} |
691
|
|
|
|
692
|
|
|
if (\is_string($function[0])) { |
693
|
|
|
// Static Calling |
694
|
|
|
return $function[0] . $function[1]; |
695
|
|
|
} |
696
|
|
|
|
697
|
1 |
|
return false; |
698
|
|
|
} |
699
|
1 |
|
|
700
|
|
|
/** |
701
|
|
|
* Call "All" Hook |
702
|
1 |
|
* |
703
|
1 |
|
* @param array $args |
704
|
|
|
*/ |
705
|
1 |
|
public function _call_all_hook(array $args) |
706
|
|
|
{ |
707
|
|
|
\reset($this->filters['all']); |
708
|
|
|
|
709
|
|
View Code Duplication |
do { |
|
|
|
|
710
|
1 |
|
foreach ((array)\current($this->filters['all']) as $the_) { |
711
|
1 |
|
if (null !== $the_['function']) { |
712
|
1 |
|
|
713
|
1 |
|
if (null !== $the_['include_path']) { |
714
|
1 |
|
/** @noinspection PhpIncludeInspection */ |
715
|
|
|
include_once $the_['include_path']; |
716
|
|
|
} |
717
|
|
|
|
718
|
|
|
\call_user_func_array($the_['function'], $args); |
719
|
|
|
} |
720
|
|
|
} |
721
|
|
|
} while (\next($this->filters['all']) !== false); |
722
|
|
|
} |
723
|
|
|
|
724
|
|
|
/** @noinspection MagicMethodsValidityInspection */ |
725
|
|
|
/** |
726
|
|
|
* @param array $args |
727
|
|
|
* |
728
|
|
|
* @deprecated use "this->_call_all_hook()" |
729
|
|
|
*/ |
730
|
|
|
public function __call_all_hook(array $args) |
731
|
|
|
{ |
732
|
|
|
// <-- refactoring "__call_all_hook()" into "_call_all_hook()" is a breaking change (BC), |
733
|
|
|
// so we will only deprecate the usage |
734
|
|
|
|
735
|
|
|
$this->_call_all_hook($args); |
736
|
|
|
} |
737
|
|
|
|
738
|
|
|
/** |
739
|
|
|
* Add hook for shortcode tag. |
740
|
|
|
* |
741
|
|
|
* <p> |
742
|
|
|
* <br /> |
743
|
|
|
* There can only be one hook for each shortcode. Which means that if another |
744
|
|
|
* plugin has a similar shortcode, it will override yours or yours will override |
745
|
|
|
* theirs depending on which order the plugins are included and/or ran. |
746
|
|
|
* <br /> |
747
|
|
|
* <br /> |
748
|
|
|
* </p> |
749
|
|
|
* |
750
|
|
|
* Simplest example of a shortcode tag using the API: |
751
|
|
|
* |
752
|
|
|
* <code> |
753
|
|
|
* // [footag foo="bar"] |
754
|
|
|
* function footag_func($atts) { |
755
|
|
|
* return "foo = {$atts[foo]}"; |
756
|
|
|
* } |
757
|
|
|
* add_shortcode('footag', 'footag_func'); |
758
|
|
|
* </code> |
759
|
|
|
* |
760
|
|
|
* Example with nice attribute defaults: |
761
|
|
|
* |
762
|
|
|
* <code> |
763
|
|
|
* // [bartag foo="bar"] |
764
|
|
|
* function bartag_func($atts) { |
765
|
|
|
* $args = shortcode_atts(array( |
766
|
|
|
* 'foo' => 'no foo', |
767
|
|
|
* 'baz' => 'default baz', |
768
|
|
|
* ), $atts); |
769
|
|
|
* |
770
|
|
|
* return "foo = {$args['foo']}"; |
771
|
|
|
* } |
772
|
|
|
* add_shortcode('bartag', 'bartag_func'); |
773
|
|
|
* </code> |
774
|
|
|
* |
775
|
|
|
* Example with enclosed content: |
776
|
|
|
* |
777
|
|
|
* <code> |
778
|
|
|
* // [baztag]content[/baztag] |
779
|
|
|
* function baztag_func($atts, $content='') { |
780
|
|
|
* return "content = $content"; |
781
|
|
|
* } |
782
|
2 |
|
* add_shortcode('baztag', 'baztag_func'); |
783
|
|
|
* </code> |
784
|
2 |
|
* |
785
|
2 |
|
* @param string $tag <p>Shortcode tag to be searched in post content.</p> |
786
|
|
|
* @param callable $func <p>Hook to run when shortcode is found.</p> |
787
|
2 |
|
* |
788
|
|
|
* @return bool |
789
|
|
|
*/ |
790
|
|
|
public function add_shortcode(string $tag, $func): bool |
791
|
|
|
{ |
792
|
|
|
if (\is_callable($func)) { |
793
|
|
|
self::$shortcode_tags[$tag] = $func; |
794
|
|
|
|
795
|
|
|
return true; |
796
|
|
|
} |
797
|
|
|
|
798
|
|
|
return false; |
799
|
|
|
} |
800
|
1 |
|
|
801
|
|
|
/** |
802
|
1 |
|
* Removes hook for shortcode. |
803
|
1 |
|
* |
804
|
|
|
* @param string $tag <p>shortcode tag to remove hook for.</p> |
805
|
1 |
|
* |
806
|
|
|
* @return bool |
807
|
|
|
*/ |
808
|
|
|
public function remove_shortcode(string $tag): bool |
809
|
|
|
{ |
810
|
|
|
if (isset(self::$shortcode_tags[$tag])) { |
811
|
|
|
unset(self::$shortcode_tags[$tag]); |
812
|
|
|
|
813
|
|
|
return true; |
814
|
|
|
} |
815
|
|
|
|
816
|
|
|
return false; |
817
|
|
|
} |
818
|
1 |
|
|
819
|
|
|
/** |
820
|
1 |
|
* This function is simple, it clears all of the shortcode tags by replacing the |
821
|
|
|
* shortcodes by a empty array. This is actually a very efficient method |
822
|
1 |
|
* for removing all shortcodes. |
823
|
|
|
* |
824
|
|
|
* @return bool |
825
|
|
|
*/ |
826
|
|
|
public function remove_all_shortcodes(): bool |
827
|
|
|
{ |
828
|
|
|
self::$shortcode_tags = []; |
829
|
|
|
|
830
|
|
|
return true; |
831
|
|
|
} |
832
|
1 |
|
|
833
|
|
|
/** |
834
|
1 |
|
* Whether a registered shortcode exists named $tag |
835
|
|
|
* |
836
|
|
|
* @param string $tag |
837
|
|
|
* |
838
|
|
|
* @return bool |
839
|
|
|
*/ |
840
|
|
|
public function shortcode_exists(string $tag): bool |
841
|
|
|
{ |
842
|
|
|
return \array_key_exists($tag, self::$shortcode_tags); |
843
|
|
|
} |
844
|
|
|
|
845
|
|
|
/** |
846
|
|
|
* Whether the passed content contains the specified shortcode. |
847
|
|
|
* |
848
|
|
|
* @param string $content |
849
|
|
|
* @param string $tag |
850
|
|
|
* |
851
|
|
|
* @return bool |
852
|
|
|
*/ |
853
|
|
|
public function has_shortcode(string $content, string $tag): bool |
854
|
|
|
{ |
855
|
|
|
if (false === \strpos($content, '[')) { |
856
|
|
|
return false; |
857
|
|
|
} |
858
|
|
|
|
859
|
|
|
if ($this->shortcode_exists($tag)) { |
860
|
|
|
\preg_match_all('/' . $this->get_shortcode_regex() . '/s', $content, $matches, PREG_SET_ORDER); |
861
|
|
|
if (empty($matches)) { |
862
|
|
|
return false; |
863
|
|
|
} |
864
|
|
|
|
865
|
|
|
foreach ($matches as $shortcode) { |
866
|
|
|
if ($tag === $shortcode[2]) { |
867
|
|
|
return true; |
868
|
|
|
} |
869
|
|
|
|
870
|
|
|
if (!empty($shortcode[5]) && $this->has_shortcode($shortcode[5], $tag)) { |
871
|
|
|
return true; |
872
|
|
|
} |
873
|
|
|
} |
874
|
|
|
} |
875
|
|
|
|
876
|
|
|
return false; |
877
|
|
|
} |
878
|
|
|
|
879
|
|
|
/** |
880
|
|
|
* Search content for shortcodes and filter shortcodes through their hooks. |
881
|
|
|
* |
882
|
|
|
* <p> |
883
|
|
|
* <br /> |
884
|
|
|
* If there are no shortcode tags defined, then the content will be returned |
885
|
2 |
|
* without any filtering. This might cause issues when plugins are disabled but |
886
|
|
|
* the shortcode will still show up in the post or content. |
887
|
2 |
|
* </p> |
888
|
1 |
|
* |
889
|
|
|
* @param string $content <p>Content to search for shortcodes.</p> |
890
|
|
|
* |
891
|
2 |
|
* @return string <p>Content with shortcodes filtered out.</p> |
892
|
|
|
*/ |
893
|
2 |
View Code Duplication |
public function do_shortcode(string $content): string |
|
|
|
|
894
|
2 |
|
{ |
895
|
|
|
if (empty(self::$shortcode_tags) || !\is_array(self::$shortcode_tags)) { |
896
|
2 |
|
return $content; |
897
|
2 |
|
} |
898
|
2 |
|
|
899
|
|
|
$pattern = $this->get_shortcode_regex(); |
900
|
2 |
|
|
901
|
|
|
return \preg_replace_callback( |
902
|
|
|
"/$pattern/s", |
903
|
|
|
[ |
904
|
|
|
$this, |
905
|
|
|
'_do_shortcode_tag', |
906
|
|
|
], |
907
|
|
|
$content |
908
|
|
|
); |
909
|
|
|
} |
910
|
|
|
|
911
|
|
|
/** |
912
|
|
|
* Retrieve the shortcode regular expression for searching. |
913
|
|
|
* |
914
|
|
|
* <p> |
915
|
|
|
* <br /> |
916
|
|
|
* The regular expression combines the shortcode tags in the regular expression |
917
|
|
|
* in a regex class. |
918
|
|
|
* <br /><br /> |
919
|
|
|
* |
920
|
|
|
* The regular expression contains 6 different sub matches to help with parsing. |
921
|
|
|
* <br /><br /> |
922
|
|
|
* |
923
|
|
|
* 1 - An extra [ to allow for escaping shortcodes with double [[]]<br /> |
924
|
|
|
* 2 - The shortcode name<br /> |
925
|
2 |
|
* 3 - The shortcode argument list<br /> |
926
|
|
|
* 4 - The self closing /<br /> |
927
|
2 |
|
* 5 - The content of a shortcode when it wraps some content.<br /> |
928
|
2 |
|
* 6 - An extra ] to allow for escaping shortcodes with double [[]]<br /> |
929
|
|
|
* </p> |
930
|
|
|
* |
931
|
|
|
* @return string The shortcode search regular expression |
932
|
|
|
*/ |
933
|
|
|
public function get_shortcode_regex(): string |
934
|
|
|
{ |
935
|
2 |
|
$tagnames = \array_keys(self::$shortcode_tags); |
936
|
2 |
|
$tagregexp = \implode('|', \array_map('preg_quote', $tagnames)); |
937
|
2 |
|
|
938
|
2 |
|
// WARNING! Do not change this regex without changing __do_shortcode_tag() and __strip_shortcode_tag() |
939
|
2 |
|
// Also, see shortcode_unautop() and shortcode.js. |
940
|
2 |
|
return |
941
|
2 |
|
'\\[' // Opening bracket |
942
|
2 |
|
. '(\\[?)' // 1: Optional second opening bracket for escaping shortcodes: [[tag]] |
943
|
2 |
|
. "($tagregexp)" // 2: Shortcode name |
944
|
2 |
|
. '(?![\\w-])' // Not followed by word character or hyphen |
945
|
2 |
|
. '(' // 3: Unroll the loop: Inside the opening shortcode tag |
946
|
2 |
|
. '[^\\]\\/]*' // Not a closing bracket or forward slash |
947
|
2 |
|
. '(?:' |
948
|
2 |
|
. '\\/(?!\\])' // A forward slash not followed by a closing bracket |
949
|
2 |
|
. '[^\\]\\/]*' // Not a closing bracket or forward slash |
950
|
2 |
|
. ')*?' |
951
|
2 |
|
. ')' |
952
|
2 |
|
. '(?:' |
953
|
2 |
|
. '(\\/)' // 4: Self closing tag ... |
954
|
2 |
|
. '\\]' // ... and closing bracket |
955
|
2 |
|
. '|' |
956
|
2 |
|
. '\\]' // Closing bracket |
957
|
2 |
|
. '(?:' |
958
|
2 |
|
. '(' // 5: Unroll the loop: Optionally, anything between the opening and closing shortcode tags |
959
|
2 |
|
. '[^\\[]*+' // Not an opening bracket |
960
|
2 |
|
. '(?:' |
961
|
|
|
. '\\[(?!\\/\\2\\])' // An opening bracket not followed by the closing shortcode tag |
962
|
|
|
. '[^\\[]*+' // Not an opening bracket |
963
|
|
|
. ')*+' |
964
|
|
|
. ')' |
965
|
|
|
. '\\[\\/\\2\\]' // Closing shortcode tag |
966
|
|
|
. ')?' |
967
|
|
|
. ')' |
968
|
|
|
. '(\\]?)'; // 6: Optional second closing brocket for escaping shortcodes: [[tag]] |
969
|
|
|
} |
970
|
|
|
|
971
|
|
|
/** |
972
|
2 |
|
* Regular Expression callable for do_shortcode() for calling shortcode hook. |
973
|
|
|
* |
974
|
|
|
* @see self::get_shortcode_regex for details of the match array contents. |
975
|
2 |
|
* |
976
|
|
|
* @param array $m <p>regular expression match array</p> |
977
|
|
|
* |
978
|
|
|
* @return mixed <p><strong>false</strong> on failure</p> |
979
|
2 |
|
*/ |
980
|
2 |
|
private function _do_shortcode_tag(array $m) |
981
|
|
|
{ |
982
|
|
|
// allow [[foo]] syntax for escaping a tag |
983
|
2 |
View Code Duplication |
if ($m[1] == '[' && $m[6] == ']') { |
|
|
|
|
984
|
2 |
|
return \substr($m[0], 1, -1); |
985
|
|
|
} |
986
|
|
|
|
987
|
|
|
$tag = $m[2]; |
988
|
|
|
$attr = $this->shortcode_parse_atts($m[3]); |
989
|
|
|
|
990
|
|
|
// enclosing tag - extra parameter |
991
|
|
|
if (isset($m[5])) { |
992
|
|
|
return $m[1] . \call_user_func(self::$shortcode_tags[$tag], $attr, $m[5], $tag) . $m[6]; |
993
|
|
|
} |
994
|
|
|
|
995
|
|
|
// self-closing tag |
996
|
|
|
return $m[1] . \call_user_func(self::$shortcode_tags[$tag], $attr, null, $tag) . $m[6]; |
997
|
|
|
} |
998
|
|
|
|
999
|
|
|
/** |
1000
|
|
|
* Retrieve all attributes from the shortcodes tag. |
1001
|
|
|
* |
1002
|
|
|
* <p> |
1003
|
|
|
* <br /> |
1004
|
|
|
* The attributes list has the attribute name as the key and the value of the |
1005
|
2 |
|
* attribute as the value in the key/value pair. This allows for easier |
1006
|
|
|
* retrieval of the attributes, since all attributes have to be known. |
1007
|
2 |
|
* </p> |
1008
|
2 |
|
* |
1009
|
2 |
|
* @param string $text |
1010
|
2 |
|
* |
1011
|
2 |
|
* @return array <p>List of attributes and their value.</p> |
1012
|
2 |
|
*/ |
1013
|
1 |
|
public function shortcode_parse_atts(string $text): array |
1014
|
2 |
|
{ |
1015
|
|
|
$atts = []; |
1016
|
1 |
|
$pattern = '/(\w+)\s*=\s*"([^"]*)"(?:\s|$)|(\w+)\s*=\s*\'([^\']*)\'(?:\s|$)|(\w+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/'; |
1017
|
1 |
|
$text = \preg_replace("/[\x{00a0}\x{200b}]+/u", ' ', $text); |
1018
|
1 |
|
$matches = []; |
1019
|
|
|
if (\preg_match_all($pattern, $text, $matches, PREG_SET_ORDER)) { |
1020
|
|
|
foreach ($matches as $m) { |
1021
|
|
|
if (!empty($m[1])) { |
1022
|
|
|
$atts[\strtolower($m[1])] = \stripcslashes($m[2]); |
1023
|
2 |
|
} elseif (!empty($m[3])) { |
1024
|
2 |
|
$atts[\strtolower($m[3])] = \stripcslashes($m[4]); |
1025
|
|
|
} elseif (!empty($m[5])) { |
1026
|
|
|
$atts[\strtolower($m[5])] = \stripcslashes($m[6]); |
1027
|
|
|
} elseif (isset($m[7]) && $m[7] !== '') { |
1028
|
2 |
|
$atts[] = \stripcslashes($m[7]); |
1029
|
|
|
} elseif (isset($m[8])) { |
1030
|
|
|
$atts[] = \stripcslashes($m[8]); |
1031
|
|
|
} |
1032
|
|
|
} |
1033
|
|
|
} else { |
1034
|
|
|
$atts = \ltrim($text); |
1035
|
|
|
} |
1036
|
|
|
|
1037
|
|
|
return $atts; |
1038
|
|
|
} |
1039
|
|
|
|
1040
|
|
|
/** |
1041
|
|
|
* Combine user attributes with known attributes and fill in defaults when needed. |
1042
|
|
|
* |
1043
|
|
|
* <p> |
1044
|
|
|
* <br /> |
1045
|
|
|
* The pairs should be considered to be all of the attributes which are |
1046
|
|
|
* supported by the caller and given as a list. The returned attributes will |
1047
|
|
|
* only contain the attributes in the $pairs list. |
1048
|
|
|
* |
1049
|
|
|
* <br /><br /> |
1050
|
|
|
* If the $atts list has unsupported attributes, then they will be ignored and |
1051
|
2 |
|
* removed from the final returned list. |
1052
|
|
|
* </p> |
1053
|
2 |
|
* |
1054
|
2 |
|
* @param array $pairs <p>Entire list of supported attributes and their defaults.</p> |
1055
|
2 |
|
* @param array $atts <p>User defined attributes in shortcode tag.</p> |
1056
|
2 |
|
* @param string $shortcode <p>[optional] The name of the shortcode, provided for context to enable filtering.</p> |
1057
|
1 |
|
* |
1058
|
1 |
|
* @return array <p>Combined and filtered attribute list.</p> |
1059
|
2 |
|
*/ |
1060
|
|
|
public function shortcode_atts($pairs, $atts, $shortcode = ''): array |
1061
|
2 |
|
{ |
1062
|
|
|
$atts = (array)$atts; |
1063
|
|
|
$out = []; |
1064
|
|
|
foreach ($pairs as $name => $default) { |
1065
|
|
|
if (array_key_exists($name, $atts)) { |
1066
|
|
|
$out[$name] = $atts[$name]; |
1067
|
|
|
} else { |
1068
|
|
|
$out[$name] = $default; |
1069
|
|
|
} |
1070
|
|
|
} |
1071
|
|
|
|
1072
|
|
|
/** |
1073
|
|
|
* Filter a shortcode's default attributes. |
1074
|
|
|
* |
1075
|
2 |
|
* <p> |
1076
|
|
|
* <br /> |
1077
|
|
|
* If the third parameter of the shortcode_atts() function is present then this filter is available. |
1078
|
|
|
* The third parameter, $shortcode, is the name of the shortcode. |
1079
|
|
|
* </p> |
1080
|
|
|
* |
1081
|
|
|
* @param array $out <p>The output array of shortcode attributes.</p> |
1082
|
|
|
* @param array $pairs <p>The supported attributes and their defaults.</p> |
1083
|
|
|
* @param array $atts <p>The user defined shortcode attributes.</p> |
1084
|
2 |
|
*/ |
1085
|
|
|
if ($shortcode) { |
1086
|
|
|
$out = $this->apply_filters( |
1087
|
|
|
"shortcode_atts_{$shortcode}", |
1088
|
|
|
$out, |
1089
|
|
|
$pairs, |
1090
|
|
|
$atts |
1091
|
|
|
); |
1092
|
|
|
} |
1093
|
|
|
|
1094
|
1 |
|
return $out; |
1095
|
|
|
} |
1096
|
|
|
|
1097
|
1 |
|
/** |
1098
|
|
|
* Remove all shortcode tags from the given content. |
1099
|
|
|
* |
1100
|
|
|
* @param string $content <p>Content to remove shortcode tags.</p> |
1101
|
1 |
|
* |
1102
|
|
|
* @return string <p>Content without shortcode tags.</p> |
1103
|
1 |
|
*/ |
1104
|
1 |
View Code Duplication |
public function strip_shortcodes(string $content): string |
|
|
|
|
1105
|
|
|
{ |
1106
|
1 |
|
|
1107
|
1 |
|
if (empty(self::$shortcode_tags) || !\is_array(self::$shortcode_tags)) { |
1108
|
1 |
|
return $content; |
1109
|
|
|
} |
1110
|
1 |
|
|
1111
|
|
|
$pattern = $this->get_shortcode_regex(); |
1112
|
|
|
|
1113
|
|
|
return preg_replace_callback( |
1114
|
|
|
"/$pattern/s", |
1115
|
|
|
[ |
1116
|
|
|
$this, |
1117
|
|
|
'_strip_shortcode_tag', |
1118
|
|
|
], |
1119
|
|
|
$content |
1120
|
1 |
|
); |
1121
|
|
|
} |
1122
|
|
|
|
1123
|
1 |
|
/** |
1124
|
|
|
* Strip shortcode by tag. |
1125
|
|
|
* |
1126
|
|
|
* @param array $m |
1127
|
1 |
|
* |
1128
|
|
|
* @return string |
1129
|
|
|
*/ |
1130
|
|
|
private function _strip_shortcode_tag(array $m): string |
1131
|
|
|
{ |
1132
|
|
|
// allow [[foo]] syntax for escaping a tag |
1133
|
|
View Code Duplication |
if ($m[1] == '[' && $m[6] == ']') { |
|
|
|
|
1134
|
|
|
return substr($m[0], 1, -1); |
1135
|
|
|
} |
1136
|
|
|
|
1137
|
|
|
return $m[1] . $m[6]; |
1138
|
|
|
} |
1139
|
|
|
|
1140
|
|
|
} |
1141
|
|
|
|
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.