PluginProbe
Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts / 2.7.7
Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts v2.7.7
2.7.7 2.7.6 2.7.5 2.7.4 trunk 1.3 2.0.4 2.0.6 2.1.91 2.2.4 2.2.7 2.2.9 2.3.1 2.3.10 2.4.10 2.4.2 2.4.4 2.4.5 2.4.6 2.4.7 2.4.8 2.4.9 2.6.0 2.6.1 2.7.0 All 28 releases
insert-php / includes / shortcodes / shortcodes.php

shortcodes.php in Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts 2.7.7, at includes/shortcodes/shortcodes.php

244 lines 6.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * A base shortcode for all snippets
4 *
5 * @since 1.0.0
6 */
7
8 // Exit if accessed directly
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 /**
14 * Base shortcode class for all snippet shortcodes
15 */
16 class WINP_SnippetShortcode {
17
18 /**
19 * Plugin instance
20 *
21 * @var WINP_Plugin
22 */
23 public $plugin;
24
25 /**
26 * Shortcode name(s)
27 *
28 * @var string|array<string>
29 */
30 public $shortcode_name = 'wbcr_php_snippet';
31
32 /**
33 * Includes assets in header
34 *
35 * @var bool
36 */
37 public $assets_in_header = true;
38
39 /**
40 * Constructor
41 *
42 * @param WINP_Plugin $plugin Plugin instance.
43 */
44 public function __construct( $plugin ) {
45 $this->plugin = $plugin;
46
47 // Ensure shortcode_name is an array.
48 if ( ! is_array( $this->shortcode_name ) ) {
49 $this->shortcode_name = [ $this->shortcode_name ];
50 }
51
52 // Register shortcode(s) with WordPress.
53 foreach ( $this->shortcode_name as $name ) {
54 if ( ! empty( $name ) ) {
55 add_shortcode( $name, [ $this, 'render' ] );
56 }
57 }
58
59 // Enqueue assets in header if needed.
60 if ( $this->assets_in_header ) {
61 add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_assets' ] );
62 }
63 }
64
65 /**
66 * Enqueue assets if needed.
67 *
68 * @return void
69 */
70 public function enqueue_assets() {
71 // Override in child classes if needed.
72 }
73
74 /**
75 * Shortcode render callback.
76 *
77 * @param array<string, mixed> $attr Shortcode attributes.
78 * @param string|null $content Shortcode content.
79 * @param string $tag Shortcode tag.
80 *
81 * @return string
82 */
83 public function render( $attr, $content, $tag ) {
84 if ( WINP_Helper::is_safe_mode() ) {
85 return '';
86 }
87
88 ob_start();
89 $result = $this->html( $attr, $content ?? '', $tag );
90 $html = ob_get_clean();
91
92 if ( is_string( $result ) ) {
93 $html = ( false !== $html ? $html : '' ) . $result;
94 }
95
96 return false !== $html ? $html : '';
97 }
98
99 /**
100 * Filter attributes
101 *
102 * @param array<string, mixed> $attr Shortcode attributes.
103 * @param int $post_id Post ID.
104 *
105 * @return array<string, mixed>
106 */
107 public function filter_attributes( $attr, $post_id ) {
108 if ( ! empty( $attr ) ) {
109 $available_tags = WINP_Helper::getMetaOption( $post_id, 'snippet_tags', null );
110
111 if ( ! empty( $available_tags ) ) {
112 $available_tags = explode( ',', $available_tags );
113 $available_tags = array_map( 'trim', $available_tags );
114 }
115
116 foreach ( $attr as $name => $value ) {
117 $is_allow_attr = in_array( $name, [ 'id', 'title' ] );
118 $validate_name = preg_match( '/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $name );
119
120 if ( ! $is_allow_attr && ( ( ! empty( $available_tags ) && ! in_array( $name, $available_tags ) ) || ! $validate_name ) ) {
121 unset( $attr[ $name ] );
122 } else {
123 // issue PCS-1
124 // before sending the value to the shortcode, using encodeURIComponent(val).replace(/\./g, ‘%2E’); fixes the issue. Will the next update stop this from working?
125 $value = urldecode( $value );
126
127 // Remove script tag
128 $value = preg_replace( '#<script(.*?)>(.*?)</script>#is', '', $value );
129
130 // Remove any attribute starting with "on" or xmlns
131 $value = preg_replace( '#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $value );
132
133 // Remove javascript: and vbscript: protocols
134 $value = preg_replace( '#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $value );
135 $value = preg_replace( '#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $value );
136 $value = preg_replace( '#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $value );
137
138 // Filter value
139 if ( version_compare( phpversion(), '7.3.0', '>=' ) ) {
140 $filter = FILTER_SANITIZE_ADD_SLASHES;
141 } else {
142 $filter = FILTER_SANITIZE_MAGIC_QUOTES;
143 }
144 $value = filter_var( $value, FILTER_SANITIZE_SPECIAL_CHARS );
145 $attr[ $name ] = filter_var( $value, $filter );
146 }
147 }
148 }
149
150 return $attr;
151 }
152
153 /**
154 * Get snippet id
155 *
156 * @param array<string, mixed> $attr Shortcode attributes.
157 * @param string $type Snippet type.
158 *
159 * @return int|null
160 */
161 public function get_snippet_id( $attr, $type ) {
162 $id = isset( $attr['id'] ) ? (int) $attr['id'] : null;
163
164 $snippet_type = null;
165
166 // Only resolve snippet type when a valid (truthy) ID is provided to avoid
167 // unnecessary request parsing or database lookups for invalid IDs.
168 if ( $id ) {
169 $snippet_type = WINP_Helper::get_snippet_type( $id );
170
171 // Security: Reject if get_snippet_type() returned false (invalid post type)
172 // or if the snippet type doesn't match the expected type.
173 if ( false === $snippet_type || $snippet_type !== $type ) {
174 $id = 0;
175 }
176 }
177
178 return $id;
179 }
180
181 /**
182 * Get snippet activate
183 *
184 * @param array<string, mixed> $snippet_meta Snippet metadata.
185 *
186 * @return bool
187 */
188 public function get_snippet_activate( $snippet_meta ) {
189 // WPML Compatibility.
190 if ( defined( 'WPML_PLUGIN_FILE' ) ) {
191 $wpml_langs = isset( $snippet_meta['wbcr_inp_snippet_wpml_lang'][0] ) ? $snippet_meta['wbcr_inp_snippet_wpml_lang'][0] : '';
192 if ( $wpml_langs !== '' && defined( 'ICL_LANGUAGE_CODE' ) ) {
193 if ( ! in_array( ICL_LANGUAGE_CODE, explode( ',', $wpml_langs ) ) ) {
194 return false;
195 }
196 }
197 }
198
199 return isset( $snippet_meta['wbcr_inp_snippet_activate'] ) && $snippet_meta['wbcr_inp_snippet_activate'][0];
200 }
201
202 /**
203 * Get snippet scope
204 *
205 * @param array<string, mixed> $snippet_meta Snippet metadata.
206 *
207 * @return string|null
208 */
209 public function get_snippet_scope( $snippet_meta ) {
210 return isset( $snippet_meta['wbcr_inp_snippet_scope'] ) ? $snippet_meta['wbcr_inp_snippet_scope'][0] : null;
211 }
212
213 /**
214 * Get snippet content
215 *
216 * @param WP_Post $snippet Snippet post object.
217 * @param array<string, mixed> $snippet_meta Snippet metadata.
218 * @param int $id Snippet ID.
219 *
220 * @return string|null
221 */
222 public function get_snippet_content( $snippet, $snippet_meta, $id ) {
223 $snippet_code = WINP_Helper::get_snippet_code( $snippet );
224
225 if ( get_option( 'wbcr_inp_execute_shortcode' ) ) {
226 $snippet_code = do_shortcode( $snippet_code );
227 }
228
229 return WINP_Plugin::app()->get_execute_object()->prepareCode( $snippet_code, $id );
230 }
231
232 /**
233 * Content render
234 *
235 * @param array<string, mixed> $attr Shortcode attributes.
236 * @param string $content Shortcode content.
237 * @param string $tag Shortcode tag.
238 *
239 * @return mixed Rendered content when returned directly, if any.
240 */
241 public function html( $attr, $content, $tag ) {
242 }
243 }
244