PluginProbe ʕ •ᴥ•ʔ
Widget Options – Advanced Conditional Visibility for Gutenberg Blocks & Classic Widgets / 4.1.3
Widget Options – Advanced Conditional Visibility for Gutenberg Blocks & Classic Widgets v4.1.3
4.2.5 4.2.4 trunk 3.7.10 3.7.11 3.7.12 3.7.13 3.7.14 3.7.2 3.7.5 3.7.6 3.7.7 3.7.8 3.7.9 3.8 3.8.1 3.8.10 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.8.8 3.8.9 3.8.9.1 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.0.5 4.0.5.1 4.0.6 4.0.6.1 4.0.7 4.0.8 4.0.9 4.1.0 4.1.1 4.1.2 4.1.3 4.2.0 4.2.1 4.2.2 4.2.3
widget-options / includes / extras.php
widget-options / includes Last commit date
admin 8 months ago pagebuilders 8 months ago widgets 8 months ago ajax-functions.php 8 months ago extras.php 8 months ago install.php 2 years ago scripts.php 8 months ago transient.php 2 years ago
extras.php
914 lines
1 <?php
2
3 /**
4 * Extra Functions
5 *
6 * Collections of extra functions to avoid repeatition
7 *
8 * @copyright Copyright (c) 2016, Jeffrey Carandang
9 * @since 4.0
10 */
11
12 function widgetopts_sanitize_array(&$array)
13 {
14 foreach ($array as &$value) {
15 if (!is_array($value)) {
16 // sanitize if value is not an array
17 $value = sanitize_text_field($value);
18 } else {
19 // go inside this function again
20 widgetopts_sanitize_array($value);
21 }
22 }
23
24 return $array;
25 }
26
27 function widgetopts_is_checked($array, $key)
28 {
29 return (isset($array[$key]) && '1' == $array[$key]) ? 'checked="checked"' : '';
30 }
31
32 /*
33 * Check if http or https available on link
34 */
35 function widgetopts_addhttp($url)
36 {
37 if (!preg_match("~^(?:f|ht)tps?://~i", $url)) {
38 $url = "http://" . $url;
39 }
40 return $url;
41 }
42
43
44 /**
45 * Register Global Variables for easier access
46 *
47 *
48 * @since 5.0
49 * @return array
50 */
51 function widgetopts_global_taxonomies()
52 {
53 $taxonomies = get_option('widgetopts_global_taxonomies');
54
55 if (empty($taxonomies)) {
56
57 $tax_args = array(
58 'public' => true
59 );
60 $tax_output = 'objects'; // or objects
61 $tax_operator = 'and'; // 'and' or 'or'
62 $taxonomies = get_taxonomies($tax_args, $tax_output, $tax_operator);
63 unset($taxonomies['post_format']);
64
65 // Let's let devs alter that value coming in
66 $taxonomies = apply_filters('widgetopts_update_global_taxonomies', $taxonomies);
67 update_option('widgetopts_global_taxonomies', $taxonomies);
68 }
69
70 return apply_filters('widgetopts_get_global_taxonomies', $taxonomies);
71 }
72
73 function widgetopts_global_types()
74 {
75 /*$types = get_option( 'widgetopts_global_types' );
76 if( empty( $types ) ) {
77 $types = get_post_types( array(
78 'public' => true,
79 ), 'object' );
80 // Let's let devs alter that value coming in
81 $types = apply_filters( 'widgetopts_update_global_types', $types );
82 update_option( 'widgetopts_global_types', $types );
83 }*/
84
85 $types = get_post_types(array('public' => true), 'object');
86 $types = apply_filters('widgetopts_update_global_types', $types);
87
88 return apply_filters('widgetopts_get_global_types', $types);
89 }
90
91 function widgetopts_global_pages()
92 {
93 $pages = get_option('widgetopts_global_all_pages');
94
95 //old pages object
96 // if( empty( $pages ) ) {
97 // $pages = get_posts( array(
98 // 'post_type' => 'page',
99 // 'post_status' => 'publish',
100 // 'numberposts' => -1,
101 // 'orderby' => 'title',
102 // 'order' => 'ASC',
103 // 'fields' => array('ID', 'name')
104 // ));
105 //
106 // // Let's let devs alter that value coming in
107 // $pages = apply_filters( 'widgetopts_update_global_pages', $pages );
108 // update_option( 'widgetopts_global_pages', $pages );
109 // }
110
111 //create new pages object
112 if (empty($pages)) {
113 global $wpdb;
114
115 $pages = $wpdb->get_results("SELECT ID, post_title, post_parent FROM $wpdb->posts WHERE post_type = 'page' AND post_status = 'publish' ORDER BY post_title ASC ");
116
117 // Let's let devs alter that value coming in
118 $pages = apply_filters('widgetopts_update_global_pages', $pages);
119 update_option('widgetopts_global_all_pages', $pages);
120 }
121
122 return apply_filters('widgetopts_get_global_pages', $pages);
123 }
124
125 function widgetopts_global_categories()
126 {
127 $categories = get_option('widgetopts_global_categories');
128
129 if (empty($categories)) {
130 $categories = get_categories(array(
131 'hide_empty' => false
132 ));
133
134 // Let's let devs alter that value coming in
135 $categories = apply_filters('widgetopts_update_global_categories', $categories);
136 update_option('widgetopts_global_categories', $categories);
137 }
138
139 return apply_filters('widgetopts_global_categories', $categories);
140 }
141
142 /*
143 Page Walker Class
144 */
145 if (!class_exists('WidgetOpts_Pages_Checkboxes')) :
146 class WidgetOpts_Pages_Checkboxes extends Walker_Page
147 {
148
149 function start_lvl(&$output, $depth = 0, $args = array())
150 {
151 $output .= "\n<div class='widgetopts-chldrn'>\n";
152 }
153
154 function end_lvl(&$output, $depth = 0, $args = array())
155 {
156 $output .= "</div>\n";
157 }
158
159 function start_el(&$output, $page, $depth = 0, $args = array(), $current_page = 0)
160 {
161 if ($depth) {
162 $indent = str_repeat('&mdash; ', $depth);
163 } else {
164 $indent = '';
165 }
166
167
168
169 if ('' === $page->post_title) {
170 $page->post_title = sprintf(__('#%d (no title)', 'widget-options'), $page->ID);
171 }
172
173 $pages_values = array();
174 if (isset($args['params']['visibility']['pages'])) {
175 $pages_values = $args['params']['visibility']['pages'];
176 }
177
178 if (isset($pages_values[$page->ID]) && $pages_values[$page->ID] == '1') {
179 $checked = 'checked="checked"';
180 } else {
181 $checked = '';
182 }
183
184 $output .= '<p>' . $indent;
185
186 $output .= '<input type="checkbox" name="' . $args['namespace'] . '[extended_widget_opts][visibility][pages][' . $page->ID . ']" id="' . $args['id'] . '-opts-pages-' . $page->ID . '" value="1" ' . $checked . '/>';
187
188 $output .= '<label for="' . $args['id'] . '-opts-pages-' . $page->ID . '">' . $page->post_title . '</label>';
189 }
190
191 function end_el(&$output, $page, $depth = 0, $args = array())
192 {
193 $output .= "</p>\n";
194 }
195 }
196 endif;
197
198 function widgetopts_set_http_headers()
199 {
200 $httpheaders = [];
201 foreach ($_SERVER as $key => $value) {
202 if (substr($key, 0, 5) === 'HTTP_') {
203 $httpheaders[$key] = $value;
204 }
205 }
206 return $httpheaders;
207 }
208
209 /**
210 * Checks if the request is coming from a mobile device based on HTTP headers.
211 *
212 * @return bool True if the request is from a mobile device, false otherwise.
213 */
214 function widgetopts_is_mobile()
215 {
216 global $widgetopts_http_headers;
217
218 // Define mobile headers and their corresponding values
219 $mobile_headers = [
220 'HTTP_ACCEPT' => ['values' => ['application/x-obml2d', 'application/vnd.rim.html', 'text/vnd.wap.wml', 'application/vnd.wap.xhtml+xml']],
221 'HTTP_UA_CPU' => ['values' => ['ARM']],
222 'HTTP_X_WAP_PROFILE' => null,
223 'HTTP_PROFILE' => null,
224 'HTTP_X_HUAWEI_USERID' => null,
225 'HTTP_X_WAP_CLIENTID' => null,
226 'HTTP_WAP_CONNECTION' => null,
227 'HTTP_X_OPERAMINI_PHONE_UA' => null,
228 'HTTP_X_NOKIA_GATEWAY_ID' => null,
229 'HTTP_X_VODAFONE_3GPDPCONTEXT' => null,
230 'HTTP_X_ORANGE_ID' => null,
231 'HTTP_X_ATT_DEVICEID' => null,
232 'HTTP_UA_OS' => null,
233 'HTTP_X_MOBILE_GATEWAY' => null,
234 ];
235
236 // Check each mobile header for a match
237 foreach ($mobile_headers as $key => $value) {
238 if (isset($widgetopts_http_headers[$key])) {
239 if (isset($value['values']) && is_array($value['values'])) {
240 foreach ($value['values'] as $_match) {
241 if (strpos($widgetopts_http_headers[$key], $_match) !== false) {
242 return true; // Found a match, request is from a mobile device
243 }
244 }
245 } else {
246 return true; // Found a match, request is from a mobile device
247 }
248 }
249 }
250
251 // If no match is found, try another method
252 return widgetopts_is_mobile_or_tablet();
253 }
254
255 function widgetopts_is_mobile_or_tablet($tablet_only = false)
256 {
257 global $widgetopts_user_agent;
258 $user_agent = $widgetopts_user_agent;
259
260 // Check for common mobile and tablet User-Agent patterns
261 $mobile_patterns = array(
262 '/android/i',
263 '/iphone|ipod/i',
264 '/blackberry/i',
265 '/iemobile/i',
266 '/windows phone/i',
267 '/opera mini/i',
268 '/mobile safari/i'
269 );
270
271 $tablet_patterns = array(
272 '/ipad/i',
273 '/android(?!.*mobile)/i',
274 '/kindle|silk/i',
275 '/playbook/i',
276 '/tablet/i'
277 );
278
279 if ($tablet_only === false) {
280 // Check if the User-Agent matches any of the mobile patterns
281 foreach ($mobile_patterns as $pattern) {
282 if (preg_match($pattern, $user_agent)) {
283 return true; // Request is from a mobile device
284 }
285 }
286 }
287
288 // Check if the User-Agent matches any of the tablet patterns
289 foreach ($tablet_patterns as $pattern) {
290 if (preg_match($pattern, $user_agent)) {
291 return true; // Request is from a tablet device
292 }
293 }
294
295 // Additional checks for specific tablet devices or browsers
296 if (stripos($user_agent, 'Macintosh') !== false && stripos($user_agent, 'iPad') !== false) {
297 return true; // Request is from an iPad
298 }
299
300 return false; // Request is neither from a mobile nor tablet device (default to desktop)
301 }
302
303 /**
304 * Check if the device is tablet.
305 * Returns true if any type of tablet device detected
306 * @return bool
307 */
308 function widgetopts_is_tablet()
309 {
310 global $widgetopts_user_agent;
311
312 $tablets = array(
313 'NookTablet' => 'Android.*Nook|NookColor|nook browser|BNRV200|BNRV200A|BNTV250|BNTV250A|BNTV400|BNTV600|LogicPD Zoom2',
314 'ToshibaTablet' => 'Android.*(AT100|AT105|AT200|AT205|AT270|AT275|AT300|AT305|AT1S5|AT500|AT570|AT700|AT830)|TOSHIBA.*FOLIO',
315 'GoogleTablet' => 'Android.*Pixel C',
316 'NexusTablet' => 'Android.*Nexus[\s]+(7|9|10)',
317 'AcerTablet' => 'Android.*; \b(A100|A101|A110|A200|A210|A211|A500|A501|A510|A511|A700|A701|W500|W500P|W501|W501P|W510|W511|W700|G100|G100W|B1-A71|B1-710|B1-711|A1-810|A1-811|A1-830)\b|W3-810|\bA3-A10\b|\bA3-A11\b|\bA3-A20\b|\bA3-A30|A3-A40',
318 'SamsungTablet' => 'SAMSUNG.*Tablet|Galaxy.*Tab|SC-01C|GT-P1000|GT-P1003|GT-P1010|GT-P3105|GT-P6210|GT-P6800|GT-P6810|GT-P7100|GT-P7300|GT-P7310|GT-P7500|GT-P7510|SCH-I800|SCH-I815|SCH-I905|SGH-I957|SGH-I987|SGH-T849|SGH-T859|SGH-T869|SPH-P100|GT-P3100|GT-P3108|GT-P3110|GT-P5100|GT-P5110|GT-P6200|GT-P7320|GT-P7511|GT-N8000|GT-P8510|SGH-I497|SPH-P500|SGH-T779|SCH-I705|SCH-I915|GT-N8013|GT-P3113|GT-P5113|GT-P8110|GT-N8010|GT-N8005|GT-N8020|GT-P1013|GT-P6201|GT-P7501|GT-N5100|GT-N5105|GT-N5110|SHV-E140K|SHV-E140L|SHV-E140S|SHV-E150S|SHV-E230K|SHV-E230L|SHV-E230S|SHW-M180K|SHW-M180L|SHW-M180S|SHW-M180W|SHW-M300W|SHW-M305W|SHW-M380K|SHW-M380S|SHW-M380W|SHW-M430W|SHW-M480K|SHW-M480S|SHW-M480W|SHW-M485W|SHW-M486W|SHW-M500W|GT-I9228|SCH-P739|SCH-I925|GT-I9200|GT-P5200|GT-P5210|GT-P5210X|SM-T311|SM-T310|SM-T310X|SM-T210|SM-T210R|SM-T211|SM-P600|SM-P601|SM-P605|SM-P900|SM-P901|SM-T217|SM-T217A|SM-T217S|SM-P6000|SM-T3100|SGH-I467|XE500|SM-T110|GT-P5220|GT-I9200X|GT-N5110X|GT-N5120|SM-P905|SM-T111|SM-T2105|SM-T315|SM-T320|SM-T320X|SM-T321|SM-T520|SM-T525|SM-T530NU|SM-T230NU|SM-T330NU|SM-T900|XE500T1C|SM-P605V|SM-P905V|SM-T337V|SM-T537V|SM-T707V|SM-T807V|SM-P600X|SM-P900X|SM-T210X|SM-T230|SM-T230X|SM-T325|GT-P7503|SM-T531|SM-T330|SM-T530|SM-T705|SM-T705C|SM-T535|SM-T331|SM-T800|SM-T700|SM-T537|SM-T807|SM-P907A|SM-T337A|SM-T537A|SM-T707A|SM-T807A|SM-T237|SM-T807P|SM-P607T|SM-T217T|SM-T337T|SM-T807T|SM-T116NQ|SM-T116BU|SM-P550|SM-T350|SM-T550|SM-T9000|SM-P9000|SM-T705Y|SM-T805|GT-P3113|SM-T710|SM-T810|SM-T815|SM-T360|SM-T533|SM-T113|SM-T335|SM-T715|SM-T560|SM-T670|SM-T677|SM-T377|SM-T567|SM-T357T|SM-T555|SM-T561|SM-T713|SM-T719|SM-T813|SM-T819|SM-T580|SM-T355Y?|SM-T280|SM-T817A|SM-T820|SM-W700|SM-P580|SM-T587|SM-P350|SM-P555M|SM-P355M|SM-T113NU|SM-T815Y|SM-T585|SM-T285|SM-T825|SM-W708|SM-T835|SM-T830|SM-T837V|SM-T720|SM-T510|SM-T387V|SM-P610|SM-T290|SM-T515|SM-T590|SM-T595|SM-T725|SM-T817P|SM-P585N0|SM-T395|SM-T295|SM-T865|SM-P610N|SM-P615|SM-T970|SM-T380|SM-T5950|SM-T905|SM-T231|SM-T500|SM-T860|SM-T536|SM-T837A|SM-X200|SM-T220|SM-T870|SM-X906C',
319 'Kindle' => 'Kindle|Silk.*Accelerated|Android.*\b(KFOT|KFTT|KFJWI|KFJWA|KFOTE|KFSOWI|KFTHWI|KFTHWA|KFAPWI|KFAPWA|WFJWAE|KFSAWA|KFSAWI|KFASWI|KFARWI|KFFOWI|KFGIWI|KFMEWI)\b|Android.*Silk/[0-9.]+ like Chrome/[0-9.]+ (?!Mobile)',
320 'SurfaceTablet' => 'Windows NT [0-9.]+; ARM;.*(Tablet|ARMBJS)',
321 'HPTablet' => 'HP Slate (7|8|10)|HP ElitePad 900|hp-tablet|EliteBook.*Touch|HP 8|Slate 21|HP SlateBook 10',
322 'AsusTablet' => '^.*PadFone((?!Mobile).)*$|Transformer|TF101|TF101G|TF300T|TF300TG|TF300TL|TF700T|TF700KL|TF701T|TF810C|ME171|ME301T|ME302C|ME371MG|ME370T|ME372MG|ME172V|ME173X|ME400C|Slider SL101|\bK00F\b|\bK00C\b|\bK00E\b|\bK00L\b|TX201LA|ME176C|ME102A|\bM80TA\b|ME372CL|ME560CG|ME372CG|ME302KL| K01A | K010 | K011 | K017 | K01E |ME572C|ME103K|ME170C|ME171C|\bME70C\b|ME581C|ME581CL|ME8510C|ME181C|P01Y|PO1MA|P01Z|\bP027\b|\bP024\b|\bP00C\b',
323 'BlackBerryTablet' => 'PlayBook|RIM Tablet',
324 'HTCtablet' => 'HTC_Flyer_P512|HTC Flyer|HTC Jetstream|HTC-P715a|HTC EVO View 4G|PG41200|PG09410',
325 'MotorolaTablet' => 'xoom|sholest|MZ615|MZ605|MZ505|MZ601|MZ602|MZ603|MZ604|MZ606|MZ607|MZ608|MZ609|MZ615|MZ616|MZ617',
326 'LGTablet' => '\bL-06C|LG-V909|LG-V900|LG-V700|LG-V510|LG-V500|LG-V410|LG-V400|LG-VK810\b',
327 'FujitsuTablet' => 'Android.*\b(F-01D|F-02F|F-05E|F-10D|M532|Q572)\b',
328 'PrestigioTablet' => 'PMP3170B|PMP3270B|PMP3470B|PMP7170B|PMP3370B|PMP3570C|PMP5870C|PMP3670B|PMP5570C|PMP5770D|PMP3970B|PMP3870C|PMP5580C|PMP5880D|PMP5780D|PMP5588C|PMP7280C|PMP7280C3G|PMP7280|PMP7880D|PMP5597D|PMP5597|PMP7100D|PER3464|PER3274|PER3574|PER3884|PER5274|PER5474|PMP5097CPRO|PMP5097|PMP7380D|PMP5297C|PMP5297C_QUAD|PMP812E|PMP812E3G|PMP812F|PMP810E|PMP880TD|PMT3017|PMT3037|PMT3047|PMT3057|PMT7008|PMT5887|PMT5001|PMT5002',
329 'LenovoTablet' => 'Lenovo TAB|Idea(Tab|Pad)( A1|A10| K1|)|ThinkPad([ ]+)?Tablet|YT3-850M|YT3-X90L|YT3-X90F|YT3-X90X|Lenovo.*(S2109|S2110|S5000|S6000|K3011|A3000|A3500|A1000|A2107|A2109|A1107|A5500|A7600|B6000|B8000|B8080)(-|)(FL|F|HV|H|)|TB-X103F|TB-X304X|TB-X304F|TB-X304L|TB-X505F|TB-X505L|TB-X505X|TB-X605F|TB-X605L|TB-8703F|TB-8703X|TB-8703N|TB-8704N|TB-8704F|TB-8704X|TB-8704V|TB-7304F|TB-7304I|TB-7304X|Tab2A7-10F|Tab2A7-20F|TB2-X30L|YT3-X50L|YT3-X50F|YT3-X50M|YT-X705F|YT-X703F|YT-X703L|YT-X705L|YT-X705X|TB2-X30F|TB2-X30L|TB2-X30M|A2107A-F|A2107A-H|TB3-730F|TB3-730M|TB3-730X|TB-7504F|TB-7504X|TB-X704F|TB-X104F|TB3-X70F|TB-X705F|TB-8504F|TB3-X70L|TB3-710F|TB-X704L|TB-J606F|TB-X606F|TB-X306X|YT-J706X',
330 'DellTablet' => 'Venue 11|Venue 8|Venue 7|Dell Streak 10|Dell Streak 7',
331 'XiaomiTablet' => '21051182G',
332 'iPad' => 'iPad|iPad.*Mobile',
333 'YarvikTablet' => 'Android.*\b(TAB210|TAB211|TAB224|TAB250|TAB260|TAB264|TAB310|TAB360|TAB364|TAB410|TAB411|TAB420|TAB424|TAB450|TAB460|TAB461|TAB464|TAB465|TAB467|TAB468|TAB07-100|TAB07-101|TAB07-150|TAB07-151|TAB07-152|TAB07-200|TAB07-201-3G|TAB07-210|TAB07-211|TAB07-212|TAB07-214|TAB07-220|TAB07-400|TAB07-485|TAB08-150|TAB08-200|TAB08-201-3G|TAB08-201-30|TAB09-100|TAB09-211|TAB09-410|TAB10-150|TAB10-201|TAB10-211|TAB10-400|TAB10-410|TAB13-201|TAB274EUK|TAB275EUK|TAB374EUK|TAB462EUK|TAB474EUK|TAB9-200)\b',
334 'MedionTablet' => 'Android.*\bOYO\b|LIFE.*(P9212|P9514|P9516|S9512)|LIFETAB',
335 'ArnovaTablet' => '97G4|AN10G2|AN7bG3|AN7fG3|AN8G3|AN8cG3|AN7G3|AN9G3|AN7dG3|AN7dG3ST|AN7dG3ChildPad|AN10bG3|AN10bG3DT|AN9G2',
336 'IntensoTablet' => 'INM8002KP|INM1010FP|INM805ND|Intenso Tab|TAB1004',
337 'IRUTablet' => 'M702pro',
338 'MegafonTablet' => 'MegaFon V9|\bZTE V9\b|Android.*\bMT7A\b',
339 'EbodaTablet' => 'E-Boda (Supreme|Impresspeed|Izzycomm|Essential)',
340 'AllViewTablet' => 'Allview.*(Viva|Alldro|City|Speed|All TV|Frenzy|Quasar|Shine|TX1|AX1|AX2)',
341 'ArchosTablet' => '\b(101G9|80G9|A101IT)\b|Qilive 97R|Archos5|\bARCHOS (70|79|80|90|97|101|FAMILYPAD|)(b|c|)(G10| Cobalt| TITANIUM(HD|)| Xenon| Neon|XSK| 2| XS 2| PLATINUM| CARBON|GAMEPAD)\b',
342 'AinolTablet' => 'NOVO7|NOVO8|NOVO10|Novo7Aurora|Novo7Basic|NOVO7PALADIN|novo9-Spark',
343 'NokiaLumiaTablet' => 'Lumia 2520',
344 'SonyTablet' => 'Sony.*Tablet|Xperia Tablet|Sony Tablet S|SO-03E|SGPT12|SGPT13|SGPT114|SGPT121|SGPT122|SGPT123|SGPT111|SGPT112|SGPT113|SGPT131|SGPT132|SGPT133|SGPT211|SGPT212|SGPT213|SGP311|SGP312|SGP321|EBRD1101|EBRD1102|EBRD1201|SGP351|SGP341|SGP511|SGP512|SGP521|SGP541|SGP551|SGP621|SGP641|SGP612|SOT31|SGP771|SGP611|SGP612|SGP712',
345 'PhilipsTablet' => '\b(PI2010|PI3000|PI3100|PI3105|PI3110|PI3205|PI3210|PI3900|PI4010|PI7000|PI7100)\b',
346 'CubeTablet' => 'Android.*(K8GT|U9GT|U10GT|U16GT|U17GT|U18GT|U19GT|U20GT|U23GT|U30GT)|CUBE U8GT',
347 'CobyTablet' => 'MID1042|MID1045|MID1125|MID1126|MID7012|MID7014|MID7015|MID7034|MID7035|MID7036|MID7042|MID7048|MID7127|MID8042|MID8048|MID8127|MID9042|MID9740|MID9742|MID7022|MID7010',
348 'MIDTablet' => 'M9701|M9000|M9100|M806|M1052|M806|T703|MID701|MID713|MID710|MID727|MID760|MID830|MID728|MID933|MID125|MID810|MID732|MID120|MID930|MID800|MID731|MID900|MID100|MID820|MID735|MID980|MID130|MID833|MID737|MID960|MID135|MID860|MID736|MID140|MID930|MID835|MID733|MID4X10',
349 'MSITablet' => 'MSI \b(Primo 73K|Primo 73L|Primo 81L|Primo 77|Primo 93|Primo 75|Primo 76|Primo 73|Primo 81|Primo 91|Primo 90|Enjoy 71|Enjoy 7|Enjoy 10)\b',
350 'SMiTTablet' => 'Android.*(\bMID\b|MID-560|MTV-T1200|MTV-PND531|MTV-P1101|MTV-PND530)',
351 'PyleAudioTablet' => '\b(PTBL10CEU|PTBL10C|PTBL72BC|PTBL72BCEU|PTBL7CEU|PTBL7C|PTBL92BC|PTBL92BCEU|PTBL9CEU|PTBL9CUK|PTBL9C)\b',
352 'RockChipTablet' => 'Android.*(RK2818|RK2808A|RK2918|RK3066)|RK2738|RK2808A',
353 'FlyTablet' => 'IQ310|Fly Vision',
354 'bqTablet' => 'Android.*(bq)?.*\b(Elcano|Curie|Edison|Maxwell|Kepler|Pascal|Tesla|Hypatia|Platon|Newton|Livingstone|Cervantes|Avant|Aquaris ([E|M]10|M8))\b|Maxwell.*Lite|Maxwell.*Plus',
355 'HuaweiTablet' => 'MediaPad|MediaPad 7 Youth|IDEOS S7|S7-201c|S7-202u|S7-101|S7-103|S7-104|S7-105|S7-106|S7-201|S7-Slim|M2-A01L|BAH-L09|BAH-W09|AGS-L09|CMR-AL19|KOB2-L09|BG2-U01|BG2-W09|BG2-U03',
356 'NecTablet' => '\bN-06D|\bN-08D',
357 'PantechTablet' => 'Pantech.*P4100',
358 'BronchoTablet' => 'Broncho.*(N701|N708|N802|a710)',
359 'DanewTablet' => 'DSlide.*\b(700|701R|702|703R|704|802|970|971|972|973|974|1010|1012)\b',
360 'VersusTablet' => 'TOUCHPAD.*[78910]|\bTOUCHTAB\b',
361 'ZyncTablet' => 'z1000|Z99 2G|z930|z990|z909|Z919|z900',
362 'PositivoTablet' => 'TB07STA|TB10STA|TB07FTA|TB10FTA',
363 'NabiTablet' => 'Android.*\bNabi',
364 'KoboTablet' => 'Kobo Touch|\bK080\b|\bVox\b Build|\bArc\b Build',
365 'TexetTablet' => 'NaviPad|TB-772A|TM-7045|TM-7055|TM-9750|TM-7016|TM-7024|TM-7026|TM-7041|TM-7043|TM-7047|TM-8041|TM-9741|TM-9747|TM-9748|TM-9751|TM-7022|TM-7021|TM-7020|TM-7011|TM-7010|TM-7023|TM-7025|TM-7037W|TM-7038W|TM-7027W|TM-9720|TM-9725|TM-9737W|TM-1020|TM-9738W|TM-9740|TM-9743W|TB-807A|TB-771A|TB-727A|TB-725A|TB-719A|TB-823A|TB-805A|TB-723A|TB-715A|TB-707A|TB-705A|TB-709A|TB-711A|TB-890HD|TB-880HD|TB-790HD|TB-780HD|TB-770HD|TB-721HD|TB-710HD|TB-434HD|TB-860HD|TB-840HD|TB-760HD|TB-750HD|TB-740HD|TB-730HD|TB-722HD|TB-720HD|TB-700HD|TB-500HD|TB-470HD|TB-431HD|TB-430HD|TB-506|TB-504|TB-446|TB-436|TB-416|TB-146SE|TB-126SE',
366 'PlaystationTablet' => 'Playstation.*(Portable|Vita)',
367 'TrekstorTablet' => 'ST10416-1|VT10416-1|ST70408-1|ST702xx-1|ST702xx-2|ST80208|ST97216|ST70104-2|VT10416-2|ST10216-2A|SurfTab',
368 'AdvanTablet' => 'Android.* \b(E3A|T3X|T5C|T5B|T3E|T3C|T3B|T1J|T1F|T2A|T1H|T1i|E1C|T1-E|T5-A|T4|E1-B|T2Ci|T1-B|T1-D|O1-A|E1-A|T1-A|T3A|T4i)\b ',
369 'DanyTechTablet' => 'Genius Tab G3|Genius Tab S2|Genius Tab Q3|Genius Tab G4|Genius Tab Q4|Genius Tab G-II|Genius TAB GII|Genius TAB GIII|Genius Tab S1',
370 'GalapadTablet' => 'Android [0-9.]+; [a-z-]+; \bG1\b',
371 'MicromaxTablet' => 'Funbook|Micromax.*\b(P250|P560|P360|P362|P600|P300|P350|P500|P275)\b',
372 'KarbonnTablet' => 'Android.*\b(A39|A37|A34|ST8|ST10|ST7|Smart Tab3|Smart Tab2)\b',
373 'AllFineTablet' => 'Fine7 Genius|Fine7 Shine|Fine7 Air|Fine8 Style|Fine9 More|Fine10 Joy|Fine11 Wide',
374 'PROSCANTablet' => '\b(PEM63|PLT1023G|PLT1041|PLT1044|PLT1044G|PLT1091|PLT4311|PLT4311PL|PLT4315|PLT7030|PLT7033|PLT7033D|PLT7035|PLT7035D|PLT7044K|PLT7045K|PLT7045KB|PLT7071KG|PLT7072|PLT7223G|PLT7225G|PLT7777G|PLT7810K|PLT7849G|PLT7851G|PLT7852G|PLT8015|PLT8031|PLT8034|PLT8036|PLT8080K|PLT8082|PLT8088|PLT8223G|PLT8234G|PLT8235G|PLT8816K|PLT9011|PLT9045K|PLT9233G|PLT9735|PLT9760G|PLT9770G)\b',
375 'YONESTablet' => 'BQ1078|BC1003|BC1077|RK9702|BC9730|BC9001|IT9001|BC7008|BC7010|BC708|BC728|BC7012|BC7030|BC7027|BC7026',
376 'ChangJiaTablet' => 'TPC7102|TPC7103|TPC7105|TPC7106|TPC7107|TPC7201|TPC7203|TPC7205|TPC7210|TPC7708|TPC7709|TPC7712|TPC7110|TPC8101|TPC8103|TPC8105|TPC8106|TPC8203|TPC8205|TPC8503|TPC9106|TPC9701|TPC97101|TPC97103|TPC97105|TPC97106|TPC97111|TPC97113|TPC97203|TPC97603|TPC97809|TPC97205|TPC10101|TPC10103|TPC10106|TPC10111|TPC10203|TPC10205|TPC10503',
377 'GUTablet' => 'TX-A1301|TX-M9002|Q702|kf026',
378 'PointOfViewTablet' => 'TAB-P506|TAB-navi-7-3G-M|TAB-P517|TAB-P-527|TAB-P701|TAB-P703|TAB-P721|TAB-P731N|TAB-P741|TAB-P825|TAB-P905|TAB-P925|TAB-PR945|TAB-PL1015|TAB-P1025|TAB-PI1045|TAB-P1325|TAB-PROTAB[0-9]+|TAB-PROTAB25|TAB-PROTAB26|TAB-PROTAB27|TAB-PROTAB26XL|TAB-PROTAB2-IPS9|TAB-PROTAB30-IPS9|TAB-PROTAB25XXL|TAB-PROTAB26-IPS10|TAB-PROTAB30-IPS10',
379 'OvermaxTablet' => 'OV-(SteelCore|NewBase|Basecore|Baseone|Exellen|Quattor|EduTab|Solution|ACTION|BasicTab|TeddyTab|MagicTab|Stream|TB-08|TB-09)|Qualcore 1027',
380 'HCLTablet' => 'HCL.*Tablet|Connect-3G-2.0|Connect-2G-2.0|ME Tablet U1|ME Tablet U2|ME Tablet G1|ME Tablet X1|ME Tablet Y2|ME Tablet Sync',
381 'DPSTablet' => 'DPS Dream 9|DPS Dual 7',
382 'VistureTablet' => 'V97 HD|i75 3G|Visture V4( HD)?|Visture V5( HD)?|Visture V10',
383 'CrestaTablet' => 'CTP(-)?810|CTP(-)?818|CTP(-)?828|CTP(-)?838|CTP(-)?888|CTP(-)?978|CTP(-)?980|CTP(-)?987|CTP(-)?988|CTP(-)?989',
384 'MediatekTablet' => '\bMT8125|MT8389|MT8135|MT8377\b',
385 'ConcordeTablet' => 'Concorde([ ]+)?Tab|ConCorde ReadMan',
386 'GoCleverTablet' => 'GOCLEVER TAB|A7GOCLEVER|M1042|M7841|M742|R1042BK|R1041|TAB A975|TAB A7842|TAB A741|TAB A741L|TAB M723G|TAB M721|TAB A1021|TAB I921|TAB R721|TAB I720|TAB T76|TAB R70|TAB R76.2|TAB R106|TAB R83.2|TAB M813G|TAB I721|GCTA722|TAB I70|TAB I71|TAB S73|TAB R73|TAB R74|TAB R93|TAB R75|TAB R76.1|TAB A73|TAB A93|TAB A93.2|TAB T72|TAB R83|TAB R974|TAB R973|TAB A101|TAB A103|TAB A104|TAB A104.2|R105BK|M713G|A972BK|TAB A971|TAB R974.2|TAB R104|TAB R83.3|TAB A1042',
387 'ModecomTablet' => 'FreeTAB 9000|FreeTAB 7.4|FreeTAB 7004|FreeTAB 7800|FreeTAB 2096|FreeTAB 7.5|FreeTAB 1014|FreeTAB 1001 |FreeTAB 8001|FreeTAB 9706|FreeTAB 9702|FreeTAB 7003|FreeTAB 7002|FreeTAB 1002|FreeTAB 7801|FreeTAB 1331|FreeTAB 1004|FreeTAB 8002|FreeTAB 8014|FreeTAB 9704|FreeTAB 1003',
388 'VoninoTablet' => '\b(Argus[ _]?S|Diamond[ _]?79HD|Emerald[ _]?78E|Luna[ _]?70C|Onyx[ _]?S|Onyx[ _]?Z|Orin[ _]?HD|Orin[ _]?S|Otis[ _]?S|SpeedStar[ _]?S|Magnet[ _]?M9|Primus[ _]?94[ _]?3G|Primus[ _]?94HD|Primus[ _]?QS|Android.*\bQ8\b|Sirius[ _]?EVO[ _]?QS|Sirius[ _]?QS|Spirit[ _]?S)\b',
389 'ECSTablet' => 'V07OT2|TM105A|S10OT1|TR10CS1',
390 'StorexTablet' => 'eZee[_\']?(Tab|Go)[0-9]+|TabLC7|Looney Tunes Tab',
391 'VodafoneTablet' => 'SmartTab([ ]+)?[0-9]+|SmartTabII10|SmartTabII7|VF-1497|VFD 1400',
392 'EssentielBTablet' => 'Smart[ \']?TAB[ ]+?[0-9]+|Family[ \']?TAB2',
393 'RossMoorTablet' => 'RM-790|RM-997|RMD-878G|RMD-974R|RMT-705A|RMT-701|RME-601|RMT-501|RMT-711',
394 'iMobileTablet' => 'i-mobile i-note',
395 'TolinoTablet' => 'tolino tab [0-9.]+|tolino shine',
396 'AudioSonicTablet' => '\bC-22Q|T7-QC|T-17B|T-17P\b',
397 'AMPETablet' => 'Android.* A78 ',
398 'SkkTablet' => 'Android.* (SKYPAD|PHOENIX|CYCLOPS)',
399 'NexoTablet' => 'NEXO NOVA|NEXO 10|NEXO AVIO|NEXO FREE|NEXO GO|NEXO EVO|NEXO 3G|NEXO SMART|NEXO KIDDO|NEXO MOBI',
400 'TecnoTablet' => 'TECNO P9|TECNO DP8D',
401 'JXDTablet' => 'Android.* \b(F3000|A3300|JXD5000|JXD3000|JXD2000|JXD300B|JXD300|S5800|S7800|S602b|S5110b|S7300|S5300|S602|S603|S5100|S5110|S601|S7100a|P3000F|P3000s|P101|P200s|P1000m|P200m|P9100|P1000s|S6600b|S908|P1000|P300|S18|S6600|S9100)\b',
402 'iJoyTablet' => 'Tablet (Spirit 7|Essentia|Galatea|Fusion|Onix 7|Landa|Titan|Scooby|Deox|Stella|Themis|Argon|Unique 7|Sygnus|Hexen|Finity 7|Cream|Cream X2|Jade|Neon 7|Neron 7|Kandy|Scape|Saphyr 7|Rebel|Biox|Rebel|Rebel 8GB|Myst|Draco 7|Myst|Tab7-004|Myst|Tadeo Jones|Tablet Boing|Arrow|Draco Dual Cam|Aurix|Mint|Amity|Revolution|Finity 9|Neon 9|T9w|Amity 4GB Dual Cam|Stone 4GB|Stone 8GB|Andromeda|Silken|X2|Andromeda II|Halley|Flame|Saphyr 9,7|Touch 8|Planet|Triton|Unique 10|Hexen 10|Memphis 4GB|Memphis 8GB|Onix 10)',
403 'FX2Tablet' => 'FX2 PAD7|FX2 PAD10',
404 'XoroTablet' => 'KidsPAD 701|PAD[ ]?712|PAD[ ]?714|PAD[ ]?716|PAD[ ]?717|PAD[ ]?718|PAD[ ]?720|PAD[ ]?721|PAD[ ]?722|PAD[ ]?790|PAD[ ]?792|PAD[ ]?900|PAD[ ]?9715D|PAD[ ]?9716DR|PAD[ ]?9718DR|PAD[ ]?9719QR|PAD[ ]?9720QR|TelePAD1030|Telepad1032|TelePAD730|TelePAD731|TelePAD732|TelePAD735Q|TelePAD830|TelePAD9730|TelePAD795|MegaPAD 1331|MegaPAD 1851|MegaPAD 2151',
405 'ViewsonicTablet' => 'ViewPad 10pi|ViewPad 10e|ViewPad 10s|ViewPad E72|ViewPad7|ViewPad E100|ViewPad 7e|ViewSonic VB733|VB100a',
406 'VerizonTablet' => 'QTAQZ3|QTAIR7|QTAQTZ3|QTASUN1|QTASUN2|QTAXIA1',
407 'OdysTablet' => 'LOOX|XENO10|ODYS[ -](Space|EVO|Xpress|NOON)|\bXELIO\b|Xelio10Pro|XELIO7PHONETAB|XELIO10EXTREME|XELIOPT2|NEO_QUAD10',
408 'CaptivaTablet' => 'CAPTIVA PAD',
409 'KocasoTablet' => '\b(TB-1207)\b',
410 'HisenseTablet' => '\b(F5281|E2371)\b',
411 'IconbitTablet' => 'NetTAB|NT-3702|NT-3702S|NT-3702S|NT-3603P|NT-3603P|NT-0704S|NT-0704S|NT-3805C|NT-3805C|NT-0806C|NT-0806C|NT-0909T|NT-0909T|NT-0907S|NT-0907S|NT-0902S|NT-0902S',
412 'TeclastTablet' => 'T98 4G|\bP80\b|\bX90HD\b|X98 Air|X98 Air 3G|\bX89\b|P80 3G|\bX80h\b|P98 Air|\bX89HD\b|P98 3G|\bP90HD\b|P89 3G|X98 3G|\bP70h\b|P79HD 3G|G18d 3G|\bP79HD\b|\bP89s\b|\bA88\b|\bP10HD\b|\bP19HD\b|G18 3G|\bP78HD\b|\bA78\b|\bP75\b|G17s 3G|G17h 3G|\bP85t\b|\bP90\b|\bP11\b|\bP98t\b|\bP98HD\b|\bG18d\b|\bP85s\b|\bP11HD\b|\bP88s\b|\bA80HD\b|\bA80se\b|\bA10h\b|\bP89\b|\bP78s\b|\bG18\b|\bP85\b|\bA70h\b|\bA70\b|\bG17\b|\bP18\b|\bA80s\b|\bA11s\b|\bP88HD\b|\bA80h\b|\bP76s\b|\bP76h\b|\bP98\b|\bA10HD\b|\bP78\b|\bP88\b|\bA11\b|\bA10t\b|\bP76a\b|\bP76t\b|\bP76e\b|\bP85HD\b|\bP85a\b|\bP86\b|\bP75HD\b|\bP76v\b|\bA12\b|\bP75a\b|\bA15\b|\bP76Ti\b|\bP81HD\b|\bA10\b|\bT760VE\b|\bT720HD\b|\bP76\b|\bP73\b|\bP71\b|\bP72\b|\bT720SE\b|\bC520Ti\b|\bT760\b|\bT720VE\b|T720-3GE|T720-WiFi',
413 'OndaTablet' => '\b(V975i|Vi30|VX530|V701|Vi60|V701s|Vi50|V801s|V719|Vx610w|VX610W|V819i|Vi10|VX580W|Vi10|V711s|V813|V811|V820w|V820|Vi20|V711|VI30W|V712|V891w|V972|V819w|V820w|Vi60|V820w|V711|V813s|V801|V819|V975s|V801|V819|V819|V818|V811|V712|V975m|V101w|V961w|V812|V818|V971|V971s|V919|V989|V116w|V102w|V973|Vi40)\b[\s]+|V10 \b4G\b',
414 'JaytechTablet' => 'TPC-PA762',
415 'TelstraTablet' => 'T-Hub2',
416 'BlaupunktTablet' => 'Endeavour 800NG|Endeavour 1010',
417 'Hudl' => 'Hudl HT7S3|Hudl 2',
418 'DigmaTablet' => '\b(iDx10|iDx9|iDx8|iDx7|iDxD7|iDxD8|iDsQ8|iDsQ7|iDsQ8|iDsD10|iDnD7|3TS804H|iDsQ11|iDj7|iDs10)\b',
419 'EvolioTablet' => 'ARIA_Mini_wifi|Aria[ _]Mini|Evolio X10|Evolio X7|Evolio X8|\bEvotab\b|\bNeura\b',
420 'LavaTablet' => 'QPAD E704|\bIvoryS\b|E-TAB IVORY|\bE-TAB\b',
421 'GenericTablet' => 'Android.*\b97D\b|Tablet(?!.*PC)|BNTV250A|MID-WCDMA|LogicPD Zoom2|\bA7EB\b|CatNova8|A1_07|CT704|CT1002|\bM721\b|rk30sdk|\bEVOTAB\b|M758A|ET904|ALUMIUM10|Smartfren Tab|Endeavour 1010|Tablet-PC-4|Tagi Tab|\bM6pro\b|CT1020W|arc 10HD|\bTP750\b|\bQTAQZ3\b|WVT101|TM1088|KT107',
422 'AocTablet' => 'MW0811|MW0812|MW0922|MTK8382|MW1031|MW0831|MW0821|MW0931|MW0712',
423 'PocketBookTablet' => 'Pocketbook',
424 'MpmanTablet' => 'MP11 OCTA|MP10 OCTA|MPQC1114|MPQC1004|MPQC994|MPQC974|MPQC973|MPQC804|MPQC784|MPQC780|\bMPG7\b|MPDCG75|MPDCG71|MPDC1006|MP101DC|MPDC9000|MPDC905|MPDC706HD|MPDC706|MPDC705|MPDC110|MPDC100|MPDC99|MPDC97|MPDC88|MPDC8|MPDC77|MP709|MID701|MID711|MID170|MPDC703|MPQC1010',
425 'CelkonTablet' => 'CT695|CT888|CT[\s]?910|CT7 Tab|CT9 Tab|CT3 Tab|CT2 Tab|CT1 Tab|C820|C720|\bCT-1\b',
426 'WolderTablet' => 'miTab \b(DIAMOND|SPACE|BROOKLYN|NEO|FLY|MANHATTAN|FUNK|EVOLUTION|SKY|GOCAR|IRON|GENIUS|POP|MINT|EPSILON|BROADWAY|JUMP|HOP|LEGEND|NEW AGE|LINE|ADVANCE|FEEL|FOLLOW|LIKE|LINK|LIVE|THINK|FREEDOM|CHICAGO|CLEVELAND|BALTIMORE-GH|IOWA|BOSTON|SEATTLE|PHOENIX|DALLAS|IN 101|MasterChef)\b',
427 'MediacomTablet' => 'M-MPI10C3G|M-SP10EG|M-SP10EGP|M-SP10HXAH|M-SP7HXAH|M-SP10HXBH|M-SP8HXAH|M-SP8MXA',
428 'MiTablet' => '\bMI PAD\b|\bHM NOTE 1W\b',
429 'UbislateTablet' => 'UbiSlate[\s]?7C',
430 'NibiruTablet' => 'Nibiru M1|Nibiru Jupiter One',
431 'LeaderTablet' => 'TBLT10Q|TBLT10I|TBL-10WDKB|TBL-10WDKBO2013|TBL-W230V2|TBL-W450|TBL-W500|SV572|TBLT7I|TBA-AC7-8G|TBLT79|TBL-8W16|TBL-10W32|TBL-10WKB|TBL-W100',
432 );
433
434 $is_tablet = false;
435 foreach ($tablets as $brand => $pattern) {
436 // Check if the tablet matches the current brand's pattern
437 if (preg_match('#' . $pattern . '#i', $widgetopts_user_agent)) {
438 // Tablet matched, so echo the brand
439 $is_tablet = true;
440 break;
441 }
442 }
443
444 // If no match is found, try another method, check only the most common keyword
445 if (!$is_tablet) {
446 $is_tablet = widgetopts_is_mobile_or_tablet(true);
447 }
448
449 return $is_tablet;
450 }
451
452 /**
453 * Retrieves the user agent string from HTTP headers.
454 *
455 * @return string The concatenated user agent string.
456 */
457 function widgetopts_get_user_agent()
458 {
459 global $widgetopts_http_headers;
460
461 $user_agent = '';
462
463 // Define the user agent headers to check
464 $user_agents = [
465 'HTTP_USER_AGENT',
466 'HTTP_X_ORIGINAL_USER_AGENT',
467 'HTTP_X_OPERAMINI_PHONE_UA',
468 'HTTP_X_BOLT_PHONE_UA',
469 'HTTP_X_DEVICE_USER_AGENT',
470 'HTTP_X_SKYFIRE_PHONE',
471 'HTTP_X_UCBROWSER_DEVICE_UA',
472 'HTTP_DEVICE_STOCK_UA',
473 ];
474
475 // Concatenate user agents from available headers
476 foreach ($user_agents as $ua) {
477 if (isset($widgetopts_http_headers[$ua]) && !empty($widgetopts_http_headers[$ua])) {
478 $user_agent .= $widgetopts_http_headers[$ua] . " ";
479 }
480 }
481
482 return trim($user_agent); // Trim the concatenated user agent string and return
483 }
484
485 /**
486 * Safely evaluates a boolean expression and prevents any output from being printed.
487 *
488 * This function uses eval() to evaluate the provided expression. It performs
489 * basic validation to ensure that the expression consists of valid boolean logic.
490 * Output generated by the eval() is suppressed using output buffering.
491 *
492 * @param string $expression The boolean expression to evaluate.
493 * @return bool Returns true or false based on the evaluated expression, or false on error.
494 */
495 function widgetopts_safe_eval($expression)
496 {
497 if (widgetopts_is_widget_or_post_preview()) {
498 // Always return true for previews unless the user is an administrator
499 if (!current_user_can('administrator')) {
500 return true;
501 }
502 }
503
504 $validation_result = widgetopts_validate_expression($expression);
505
506 if ($validation_result['valid'] === false) {
507 return false;
508 }
509
510 if (stristr($expression, "return") === false) {
511 $expression = "return (" . $expression . ");";
512 }
513
514 ob_start();
515 try {
516 $result = (bool) (@eval($expression));
517 } catch (\Exception $e) {
518 $result = false;
519 } catch (\Error $e) {
520 $result = false;
521 } catch (\ParseError $e) {
522 $result = false;
523 } catch (\Throwable $e) {
524 $result = false;
525 }
526 ob_end_clean();
527
528 return $result;
529 }
530
531 /**
532 * Validate the expression if it contains dangerous and unallowed patterns.
533 */
534 function widgetopts_validate_expression($expression)
535 {
536 // Ensure the expression has no backtick execution
537 if (stripos($expression, '`') !== false) {
538 return ['valid' => false, 'message' => 'Backticks execution is not allowed.'];
539 }
540
541 // List of potentially harmful patterns and their messages
542 $dangerous_patterns = [
543 '/\b(insert|update|delete|replace|select|drop|alter|truncate|grant|revoke)\b/i' => 'Potential SQL injection detected.',
544 '/\b(wp_insert_post|wp_update_post|wp_delete_post|wp_insert_user|wp_update_user|wp_delete_user|add_option|update_option|delete_option|wpdb)\b/i' => 'Unsafe WordPress database functions found.',
545 '/\b(file_put_contents|file_get_contents|fopen|fwrite|unlink|rename|chmod|chown|chgrp|copy|scandir)\b/i' => 'File system manipulation functions are not allowed.',
546 '/\b(wp_remote_get|wp_remote_post|curl_init|curl_exec|curl_setopt|open_basedir|fsockopen|proc_nice|stream_socket_server|stream_socket_client)\b/i' => 'Potential remote execution functions detected.',
547 '/\b(eval|assert|system|exec|shell_exec|passthru|proc_open|popen|pcntl_exec|dl|include|require|include_once|require_once)\b/i' => 'Execution functions are not allowed.',
548 '/\b(base64_decode|hex2bin|mb_decode_mimeheader|str_rot13)\b/i' => 'Encoding/decoding functions that may be used for obfuscation are not allowed.',
549 '/\b(call_user_func|call_user_func_array|create_function|compact|extract|parse_str|ReflectionClass|ReflectionMethod|ReflectionProperty)\b/i' => 'Dynamic function execution is not allowed.',
550 '/\b(str_replace|str_ireplace|preg_replace|preg_replace_callback|preg_replace_callback_array)\b/i' => 'String replacement functions are restricted due to potential obfuscation.',
551 '/`[^`]*`/' => 'Backticks execution is not allowed.',
552 '/\[\s*[\'"]?[a-zA-Z0-9_]+\s*\.\s*[\'"]?[a-zA-Z0-9_]+\s*\]/i' => 'Concatenated function execution is not allowed.',
553 '/\b(str_replace|preg_replace|preg_replace_callback|preg_replace_callback_array)\s*\(\s*[\'"]\s*\.\s*[\'"]/' => 'Potential function name obfuscation detected.',
554 '/\$\w+\s*\[\s*[\'"]?\d+[\'"]?\s*\]\s*\(/' => 'Dynamic function execution using arrays is not allowed.',
555 ];
556
557 $is_valid = true;
558 // Check for dangerous patterns
559 foreach ($dangerous_patterns as $pattern => $message) {
560 if (preg_match($pattern, $expression)) {
561 $is_valid = false;
562 break;
563 }
564 }
565
566 if ($is_valid === false) {
567 return ['valid' => false, 'message' => $message];
568 }
569
570 // Retrieve allowed functions
571 $allowed_functions = array_merge(widgetopts_get_allowed_php_functions(), widgetopts_get_allowed_wp_functions());
572 $allowed_functions = apply_filters('widgetopts_allowed_php_functions', $allowed_functions);
573
574 // Validate using token-based function checking
575 $is_valid = widgetopts_validate_code_with_tokens($expression, $allowed_functions);
576 $is_valid = apply_filters('widgetopts_validate_allowed_commands', $is_valid);
577
578 // Return validation result
579 return $is_valid ? ['valid' => true, 'message' => 'Expression is safe.'] : ['valid' => false, 'message' => 'Expression contains disallowed function calls.'];
580 }
581
582 /**
583 * Returns a list of allowed PHP functions.
584 */
585 function widgetopts_get_allowed_php_functions()
586 {
587 return [
588 // String Manipulation
589 'strlen',
590 'substr',
591 'strtolower',
592 'strtoupper',
593 'trim',
594 'ltrim',
595 'rtrim',
596 'preg_match',
597 'explode',
598 'implode',
599 'htmlspecialchars',
600 'htmlentities',
601 'strip_tags',
602 'str_repeat',
603 'str_split',
604 'strpos',
605 'strrpos',
606 'stripos',
607 'strripos',
608 'substr_replace',
609 'wordwrap',
610
611 // Array Manipulation
612 'array_merge',
613 'array_diff',
614 'array_filter',
615 'array_map',
616 'array_keys',
617 'array_values',
618 'in_array',
619 'count',
620 'sizeof',
621 'array_slice',
622 'array_push',
623 'array_pop',
624 'array_reduce',
625 'array_intersect',
626 'array_unique',
627 'array_column',
628 'array_reverse',
629
630 // Math Functions
631 'abs',
632 'round',
633 'floor',
634 'ceil',
635 'min',
636 'max',
637 'pow',
638 'sqrt',
639 'rand',
640 'mt_rand',
641 'number_format',
642 'log',
643 'exp',
644 'bcadd',
645 'bcsub',
646 'bcmul',
647 'bcdiv',
648
649 // Date/Time
650 'time',
651 'date',
652 'strtotime',
653 'mktime',
654 'checkdate',
655 'date_default_timezone_get',
656 'gmdate',
657
658 // JSON Functions
659 'json_decode',
660 'json_encode',
661
662 // Variable Handling
663 'isset',
664 'empty',
665 'unset',
666 'is_array',
667 'is_bool',
668 'is_callable',
669 'is_countable',
670 'is_double',
671 'is_float',
672 'is_int',
673 'is_integer',
674 'is_iterable',
675 'is_long',
676 'is_null',
677 'is_numeric',
678 'is_object',
679 'is_real',
680 'is_scalar',
681 'is_string',
682 'is_subclass_of',
683 'is_uploaded_file',
684 'is_writable',
685 'is_readable',
686 'is_dir',
687 'is_file',
688 'is_link',
689 'intval',
690 'strval',
691 'floatval',
692 'doubleval',
693 'boolval',
694 'realpath',
695
696 // File Operations (Read-Only)
697 'filesize',
698 'pathinfo',
699 'basename',
700 'dirname',
701 'file_exists',
702 'readfile',
703 ];
704 }
705
706 /**
707 * Returns a list of allowed WordPress functions.
708 */
709 function widgetopts_get_allowed_wp_functions()
710 {
711 return [
712 // Database Operations
713 'get_option',
714 'get_post',
715 'get_user_meta',
716 'get_bloginfo',
717 'get_theme_mod',
718
719 // Escaping and Sanitizing
720 'esc_url',
721 'esc_html',
722 'esc_attr',
723 'esc_js',
724 'sanitize_text_field',
725 'sanitize_email',
726 'sanitize_title',
727 'sanitize_key',
728
729 // URL and Links
730 'get_permalink',
731 'get_home_url',
732 'get_site_url',
733 'get_admin_url',
734 'wp_parse_url',
735 'urlencode',
736 'urldecode',
737 'rawurlencode',
738 'rawurldecode',
739 'parse_url',
740 'http_build_query',
741
742 // Security and Authentication
743 'wp_verify_nonce',
744 'check_admin_referer',
745 'current_user_can',
746 'is_user_logged_in',
747 'wp_nonce_field',
748 'wp_nonce_url',
749
750 // Formatting
751 'wp_kses',
752 'wp_kses_post',
753 'wp_trim_words',
754 'wpautop',
755
756 // Retrieval of Metadata and Post Details
757 'get_post_meta',
758 'get_page_template_slug',
759 'get_the_author_meta',
760 'get_the_terms',
761 'get_comments',
762 'get_category',
763 'get_terms',
764 'get_nav_menu_locations',
765 'get_posts',
766 'get_post_status',
767 'get_comment_meta',
768 'get_taxonomy',
769 'get_object_taxonomies',
770 'get_post_type',
771 'get_the_ID',
772 'get_the_title',
773 'get_edit_post_link',
774
775 // Plugins and Themes
776 'is_plugin_active',
777 'get_plugins',
778 'get_theme_support',
779
780 // Utilities
781 'wp_generate_uuid4',
782
783 // User and Authentication
784 'get_userdata',
785 'get_user_by',
786 'get_users',
787 'get_author_posts_url',
788 'get_user_roles',
789 'get_users_by_role',
790 'wp_get_current_user',
791
792 // Media and Files
793 'wp_get_attachment_image_src',
794 'wp_get_attachment_url',
795 'wp_get_attachment_metadata',
796 'wp_get_attachment_image',
797 'wp_get_attachment_thumb_url',
798
799 // File Handling
800 'wp_get_upload_dir',
801 'wp_handle_upload',
802 'wp_check_filetype_and_ext',
803 'wp_get_file_upload_url',
804
805 // Taxonomies
806 'get_term_meta',
807 'get_the_category_list',
808 'get_the_tag_list',
809 'get_the_term_list',
810
811 // Checking Functions
812 'is_admin',
813 'is_network_admin',
814 'is_main_query',
815 'is_single',
816 'is_singular',
817 'is_category',
818 'is_tag',
819 'is_page',
820 'is_front_page',
821 'is_home',
822 'is_attachment',
823 'is_archive',
824 'is_date',
825 'is_year',
826 'is_month',
827 'is_day',
828 'is_author',
829 'is_search',
830 'is_404',
831 'is_multisite',
832 'is_customize_preview',
833 ];
834 }
835
836 /**
837 * Validate PHP code against allowed functions and detect obfuscated calls.
838 *
839 * @param string $code The PHP code to validate.
840 * @param array $allowed_functions List of explicitly allowed functions.
841 * @return bool Returns true if the code is considered safe, false otherwise.
842 */
843 function widgetopts_validate_code_with_tokens($code, $allowed_functions)
844 {
845 $code = stripslashes($code);
846 // Ensure correct PHP opening tag before tokenizing
847 if (strpos(trim($code), '<?php') !== 0) {
848 $code = "<?php " . $code;
849 }
850
851 $tokens = token_get_all($code);
852 $is_safe = true;
853 $last_token = null;
854
855 foreach ($tokens as $index => $token) {
856 if (is_array($token)) {
857 $token_type = $token[0];
858 $token_value = $token[1];
859
860 // **Fix: Properly detect function calls inside conditions**
861 if ($token_type === T_STRING) {
862 $function_name = strtolower($token_value);
863 $next_token = $tokens[$index + 1] ?? null;
864
865 if ($next_token === '(' || (is_array($next_token) && $next_token[0] === T_WHITESPACE && ($tokens[$index + 2] ?? null) === '(')) {
866 if (!in_array($function_name, array_map('strtolower', $allowed_functions))) {
867 $is_safe = false;
868 break;
869 }
870 }
871 }
872
873 // **Fix: Detect if T_ENCAPSED_AND_WHITESPACE is being treated as code**
874 if ($token_type === T_ENCAPSED_AND_WHITESPACE) {
875 $is_safe = false;
876 break;
877 }
878
879 // **Fix: Dynamic Function Execution (`$func()` or `['test']()`)**
880 if ($token_type === T_VARIABLE || $token_type === T_CONSTANT_ENCAPSED_STRING) {
881 $next_token = $tokens[$index + 1] ?? null;
882 if ($next_token === '(') {
883 $is_safe = false;
884 break;
885 }
886 }
887
888 $last_token = $token;
889 }
890 }
891
892 return $is_safe;
893 }
894
895 function widgetopts_is_widget_or_post_preview()
896 {
897 // Check if it's a block editor preview
898 if (defined('REST_REQUEST') && REST_REQUEST && isset($_GET['context']) && $_GET['context'] === 'edit') {
899 return true;
900 }
901
902 // Check if it's a post/page preview
903 if (is_preview() || (isset($_GET['preview']) && $_GET['preview'] == 'true')) {
904 return true;
905 }
906
907 // Check if it's a Customizer preview
908 if (is_customize_preview()) {
909 return true;
910 }
911
912 return false;
913 }
914