1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Jaybizzle\Shortcodes; |
4
|
|
|
|
5
|
|
|
class Shortcodes |
6
|
|
|
{ |
7
|
|
|
/** |
8
|
|
|
* Container for storing shortcode tags and their hook to call for the shortcode. |
9
|
|
|
* |
10
|
|
|
* @var array |
11
|
|
|
*/ |
12
|
|
|
public $shortcodeTags = []; |
13
|
|
|
|
14
|
|
|
/** |
15
|
|
|
* Add shortcode hooks. |
16
|
|
|
* |
17
|
|
|
* @param string $tag |
18
|
|
|
* @param string $class |
19
|
|
|
*/ |
20
|
|
|
public function add($tag, $class) |
21
|
|
|
{ |
22
|
|
|
$this->shortcodeTags[$tag] = $class; |
23
|
|
|
} |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Remove shortcode tag from shortcode container. |
27
|
|
|
* |
28
|
|
|
* @param string $tag |
29
|
|
|
*/ |
30
|
|
|
public function remove($tag) |
31
|
|
|
{ |
32
|
|
|
unset($this->shortcodeTags[$tag]); |
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Remove all shortcodes tags from the shortcode container. |
37
|
|
|
*/ |
38
|
|
|
public function removeAll() |
39
|
|
|
{ |
40
|
|
|
$this->shortcodeTags = []; |
41
|
|
|
} |
42
|
|
|
|
43
|
|
|
/** |
44
|
|
|
* Search content for shortcodes and filter shortcodes through their hooks. |
45
|
|
|
* |
46
|
|
|
* @param string $content |
47
|
|
|
* @return string |
48
|
|
|
*/ |
49
|
|
View Code Duplication |
public function parse($content) |
|
|
|
|
50
|
|
|
{ |
51
|
|
|
if (empty($this->shortcodeTags) || ! is_array($this->shortcodeTags)) { |
52
|
|
|
return $content; |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
$pattern = $this->getShortcodeRegex(); |
56
|
|
|
|
57
|
|
|
return preg_replace_callback('/'.$pattern.'/s', [$this, 'doShortcodeTag'], $content); |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* Retrieve the shortcode regular expression for searching. |
62
|
|
|
* |
63
|
|
|
* @return string |
64
|
|
|
*/ |
65
|
|
|
protected function getShortcodeRegex() |
66
|
|
|
{ |
67
|
|
|
$tagNames = array_keys($this->shortcodeTags); |
68
|
|
|
$tagRegexp = implode('|', array_map('preg_quote', $tagNames)); |
69
|
|
|
|
70
|
|
|
return $this->buildShortcodeRegex($tagRegexp); |
71
|
|
|
} |
72
|
|
|
|
73
|
|
|
/** |
74
|
|
|
* Build the shortcode regex for the specified tags. |
75
|
|
|
* |
76
|
|
|
* @param string $tags |
77
|
|
|
* @return string |
78
|
|
|
*/ |
79
|
|
|
protected function buildShortcodeRegex($tags) |
80
|
|
|
{ |
81
|
|
|
return '(.?)\[('.$tags.')\b(.*?)(?:(\/))?\](?:(.+?)\[\/\2\])?(.?)'; |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* Regular Expression callable for doShortcode() for calling shortcode hook. |
86
|
|
|
* |
87
|
|
|
* @param array $matches |
88
|
|
|
* @return string |
89
|
|
|
*/ |
90
|
|
|
protected function doShortcodeTag($matches) |
91
|
|
|
{ |
92
|
|
|
// allow [[foo]] syntax for escaping a tag |
93
|
|
|
if ($matches[1] == '[' && $matches[6] == ']') { |
94
|
|
|
return substr($matches[0], 1, -1); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
$tag = $matches[2]; |
98
|
|
|
$attr = $this->shortcodeParseAtts($matches[3]); |
99
|
|
|
|
100
|
|
|
$className = $this->shortcodeTags[$tag]; |
101
|
|
|
|
102
|
|
|
if (isset($matches[5])) { |
103
|
|
|
// enclosing tag - extra parameter |
104
|
|
|
$parsed = (new $className($attr, $matches[5], $tag))->parse(); |
105
|
|
|
|
106
|
|
|
return $matches[1].$parsed.$matches[6]; |
107
|
|
|
} else { |
108
|
|
|
// self-closing tag |
109
|
|
|
$parsed = (new $className($attr, null, $tag))->parse(); |
110
|
|
|
|
111
|
|
|
return $matches[1].$parsed.$matches[6]; |
112
|
|
|
} |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* Retrieve all attributes from the shortcode tag. |
117
|
|
|
* |
118
|
|
|
* @param string $text |
119
|
|
|
* @return array |
120
|
|
|
*/ |
121
|
|
|
protected function shortcodeParseAtts($text) |
122
|
|
|
{ |
123
|
|
|
$atts = []; |
124
|
|
|
$pattern = '/(\w+)\s*=\s*"([^"]*)"(?:\s|$)|(\w+)\s*=\s*\'([^\']*)\'(?:\s|$)|(\w+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/'; |
125
|
|
|
$text = preg_replace("/[\x{00a0}\x{200b}]+/u", ' ', $text); |
126
|
|
|
|
127
|
|
|
if (preg_match_all($pattern, $text, $match, PREG_SET_ORDER)) { |
128
|
|
|
foreach ($match as $m) { |
129
|
|
|
if (! empty($m[1])) { |
130
|
|
|
$atts[strtolower($m[1])] = stripcslashes($m[2]); |
131
|
|
|
} elseif (! empty($m[3])) { |
132
|
|
|
$atts[strtolower($m[3])] = stripcslashes($m[4]); |
133
|
|
|
} elseif (! empty($m[5])) { |
134
|
|
|
$atts[strtolower($m[5])] = stripcslashes($m[6]); |
135
|
|
|
} elseif (isset($m[7]) and strlen($m[7])) { |
|
|
|
|
136
|
|
|
$atts[] = stripcslashes($m[7]); |
137
|
|
|
} elseif (isset($m[8])) { |
138
|
|
|
$atts[] = stripcslashes($m[8]); |
139
|
|
|
} |
140
|
|
|
} |
141
|
|
|
} else { |
142
|
|
|
$atts = ltrim($text); |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
return $atts; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
/** |
149
|
|
|
* Remove all shortcode tags from the given content. |
150
|
|
|
* |
151
|
|
|
* @param string $content |
152
|
|
|
* @return string |
153
|
|
|
*/ |
154
|
|
View Code Duplication |
public function stripShortcodes($content) |
|
|
|
|
155
|
|
|
{ |
156
|
|
|
if (empty($this->shortcodeTags) || ! is_array($this->shortcodeTags)) { |
157
|
|
|
return $content; |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
$pattern = $this->getShortcodeRegex(); |
161
|
|
|
|
162
|
|
|
return preg_replace('/'.$pattern.'/s', ' ', $content); |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* Remove specified shortcode tag from the given content. |
167
|
|
|
* |
168
|
|
|
* @param string $content |
169
|
|
|
* @return string |
170
|
|
|
*/ |
171
|
|
|
public function stripShortcode($shortcode, $content) |
172
|
|
|
{ |
173
|
|
|
$pattern = $this->buildShortcodeRegex(preg_quote($shortcode)); |
174
|
|
|
|
175
|
|
|
return preg_replace('/'.$pattern.'/s', ' ', $content); |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
public function getShortcodes($content) |
179
|
|
|
{ |
180
|
|
|
foreach (array_keys($this->shortcodeTags) as $shortcode) { |
181
|
|
|
$tags[$shortcode] = $this->getShortcode($shortcode, $content); |
|
|
|
|
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
return $tags; |
|
|
|
|
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* Get attributes for the specified shortcodes. |
189
|
|
|
* |
190
|
|
|
* @param string $shortcode |
191
|
|
|
* @param string $content |
192
|
|
|
* @return array |
193
|
|
|
*/ |
194
|
|
|
public function getShortcode($shortcode, $content) |
195
|
|
|
{ |
196
|
|
|
$pattern = $this->buildShortcodeRegex($shortcode); |
197
|
|
|
|
198
|
|
|
preg_match_all('/'.$pattern.'/s', $content, $matches); |
199
|
|
|
|
200
|
|
|
if (empty($matches[3])) { |
201
|
|
|
return []; |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
foreach ($matches[3] as $m) { |
205
|
|
|
$data[] = $this->shortcodeParseAtts($m); |
|
|
|
|
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
return $data; |
|
|
|
|
209
|
|
|
} |
210
|
|
|
} |
211
|
|
|
|
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.