PluginProbe
Code Snippets / 2.13.2
Code Snippets v2.13.2
4.0.0-beta.2 3.10.2 3.10.1 3.10.0 3.10.0-beta.2 3.10.0-beta.1 4.0.0-beta.1 3.9.6 trunk 2.10.0 2.10.1 2.12.0 2.12.1 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.14.1 2.14.2 2.14.3 2.14.4 2.14.5 2.14.6 3.0.0 All 65 releases
code-snippets / php / snippet-ops.php

snippet-ops.php in Code Snippets 2.13.2, at php/snippet-ops.php

457 lines 12.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Functions to perform snippet operations
5 *
6 * @package Code_Snippets
7 */
8
9 /**
10 * Retrieve a list of snippets from the database
11 *
12 * @since 2.0
13 *
14 * @uses $wpdb to query the database for snippets
15 * @uses code_snippets()->db->get_table_name() to dynamically retrieve the snippet table name
16 *
17 * @param array $ids The IDs of the snippets to fetch
18 * @param bool|null $multisite Retrieve multisite-wide or site-wide snippets?
19 *
20 * @return array An array of Snippet objects
21 */
22 function get_snippets( array $ids = array(), $multisite = null ) {
23 /** @var wpdb $wpdb */
24 global $wpdb;
25
26 $db = code_snippets()->db;
27 $multisite = $db->validate_network_param( $multisite );
28 $table = $db->get_table_name( $multisite );
29
30 $ids_count = count( $ids );
31
32 /* If only one ID has been passed in, defer to the get_snippet() function */
33 if ( 1 == $ids_count ) {
34 return array( get_snippet( $ids[0] ) );
35 }
36
37 /* Build a query containing the specified IDs if there are any */
38 if ( $ids_count > 1 ) {
39 $sql = sprintf(
40 'SELECT * FROM %s WHERE id IN (%s);',
41 $table,
42 implode( ',', array_fill( 0, $ids_count, '%d' ) )
43 );
44 $sql = $wpdb->prepare( $sql, $ids );
45
46 } else {
47 $sql = "SELECT * FROM $table;";
48 }
49
50 /* Retrieve the results from the database */
51 $snippets = $wpdb->get_results( $sql, ARRAY_A );
52
53 /* Convert snippets to snippet objects */
54 foreach ( $snippets as $index => $snippet ) {
55 $snippet['network'] = $multisite;
56 $snippets[ $index ] = new Code_Snippet( $snippet );
57 }
58
59 return apply_filters( 'code_snippets/get_snippets', $snippets, $multisite );
60 }
61
62 /**
63 * Gets all of the used tags from the database
64 * @since 2.0
65 */
66 function get_all_snippet_tags() {
67 /** @var wpdb $wpdb */
68 global $wpdb;
69
70 /* Grab all tags from the database */
71 $tags = array();
72 $table = code_snippets()->db->get_table_name();
73 $all_tags = $wpdb->get_col( "SELECT `tags` FROM $table" );
74
75 /* Merge all tags into a single array */
76 foreach ( $all_tags as $snippet_tags ) {
77 $snippet_tags = code_snippets_build_tags_array( $snippet_tags );
78 $tags = array_merge( $snippet_tags, $tags );
79 }
80
81 /* Remove duplicate tags */
82
83 return array_values( array_unique( $tags, SORT_REGULAR ) );
84 }
85
86 /**
87 * Make sure that the tags are a valid array
88 * @since 2.0
89 *
90 * @param mixed $tags The tags to convert into an array
91 *
92 * @return array The converted tags
93 */
94 function code_snippets_build_tags_array( $tags ) {
95
96 /* If there are no tags set, return an empty array */
97 if ( empty( $tags ) ) {
98 return array();
99 }
100
101 /* If the tags are set as a string, convert them into an array */
102 if ( is_string( $tags ) ) {
103 $tags = strip_tags( $tags );
104 $tags = str_replace( ', ', ',', $tags );
105 $tags = explode( ',', $tags );
106 }
107
108 /* If we still don't have an array, just convert whatever we do have into one */
109
110 return (array) $tags;
111 }
112
113 /**
114 * Retrieve a single snippets from the database.
115 * Will return empty snippet object if no snippet
116 * ID is specified
117 *
118 * @since 2.0
119 *
120 * @uses $wpdb to query the database for snippets
121 * @uses code_snippets()->db->get_table_name() to dynamically retrieve the snippet table name
122 *
123 * @param int $id The ID of the snippet to retrieve. 0 to build a new snippet
124 * @param boolean|null $multisite Retrieve a multisite-wide or site-wide snippet?
125 *
126 * @return Code_Snippet A single snippet object
127 */
128 function get_snippet( $id = 0, $multisite = null ) {
129 /** @var wpdb $wpdb */
130 global $wpdb;
131
132 $id = absint( $id );
133 $table = code_snippets()->db->get_table_name( $multisite );
134
135 if ( 0 !== $id ) {
136
137 /* Retrieve the snippet from the database */
138 $snippet = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table WHERE id = %d", $id ) );
139
140 /* Unescape the snippet data, ready for use */
141 $snippet = new Code_Snippet( $snippet );
142
143 } else {
144
145 /* Get an empty snippet object */
146 $snippet = new Code_Snippet();
147 }
148
149 $snippet->network = $multisite;
150
151 return apply_filters( 'code_snippets/get_snippet', $snippet, $id, $multisite );
152 }
153
154 /**
155 * Activates a snippet
156 *
157 * @since 2.0
158 *
159 * @uses $wpdb to set the snippet's active status
160 *
161 * @param int $id The ID of the snippet to activate
162 * @param bool|null $multisite Are the snippets multisite-wide or site-wide?
163 */
164 function activate_snippet( $id, $multisite = null ) {
165 /** @var wpdb $wpdb */
166 global $wpdb;
167 $db = code_snippets()->db;
168 $table = $db->get_table_name( $multisite );
169
170 $wpdb->update(
171 $table,
172 array( 'active' => '1' ),
173 array( 'id' => $id ),
174 array( '%d' ),
175 array( '%d' )
176 );
177
178 /* Remove snippet from shared network snippet list if it was Network Activated */
179 if ( $table === $db && $shared_network_snippets = get_site_option( 'shared_network_snippets', false ) ) {
180 $shared_network_snippets = array_diff( $shared_network_snippets, array( $id ) );
181 update_site_option( 'shared_network_snippets', $shared_network_snippets );
182 }
183
184 do_action( 'code_snippets/activate_snippet', $id, $multisite );
185 }
186
187 /**
188 * Deactivate a snippet
189 *
190 * @since 2.0
191 *
192 * @uses $wpdb to set the snippets' active status
193 *
194 * @param int $id The ID of the snippet to deactivate
195 * @param bool|null $multisite Are the snippets multisite-wide or site-wide?
196 */
197 function deactivate_snippet( $id, $multisite = null ) {
198 /** @var wpdb $wpdb */
199 global $wpdb;
200 $db = code_snippets()->db;
201 $table = $db->get_table_name( $multisite );
202
203 /* Set the snippet to active */
204
205 $wpdb->update(
206 $table,
207 array( 'active' => '0' ),
208 array( 'id' => $id ),
209 array( '%d' ),
210 array( '%d' )
211 );
212
213 /* Update the recently active list */
214
215 $recently_active = array( $id => time() );
216
217 if ( $table === $db->table ) {
218
219 update_option(
220 'recently_activated_snippets',
221 $recently_active + (array) get_option( 'recently_activated_snippets', array() )
222 );
223
224 } elseif ( $table === $db->ms_table ) {
225
226 update_site_option(
227 'recently_activated_snippets',
228 $recently_active + (array) get_site_option( 'recently_activated_snippets', array() )
229 );
230 }
231
232 do_action( 'code_snippets/deactivate_snippet', $id, $multisite );
233 }
234
235 /**
236 * Deletes a snippet from the database
237 *
238 * @since 2.0
239 * @uses $wpdb to access the database
240 * @uses code_snippets()->db->get_table_name() to dynamically retrieve the name of the snippet table
241 *
242 * @param int $id The ID of the snippet to delete
243 * @param bool|null $multisite Delete from site-wide or network-wide table?
244 */
245 function delete_snippet( $id, $multisite = null ) {
246 /** @var wpdb $wpdb */
247 global $wpdb;
248
249 $wpdb->delete(
250 code_snippets()->db->get_table_name( $multisite ),
251 array( 'id' => $id ),
252 array( '%d' )
253 );
254
255 do_action( 'code_snippets/delete_snippet', $id, $multisite );
256 }
257
258 /**
259 * Saves a snippet to the database.
260 *
261 * @since 2.0
262 *
263 * @uses $wpdb to update/add the snippet to the database
264 * @uses code_snippets()->db->get_table_name() To dynamically retrieve the name of the snippet table
265 *
266 * @param Code_Snippet $snippet The snippet to add/update to the database
267 *
268 * @return int The ID of the snippet
269 */
270 function save_snippet( Code_Snippet $snippet ) {
271 /** @var wpdb $wpdb */
272 global $wpdb;
273
274 $table = code_snippets()->db->get_table_name( $snippet->network );
275
276 /* Build array of data to insert */
277 $data = array(
278 'name' => $snippet->name,
279 'description' => $snippet->desc,
280 'code' => $snippet->code,
281 'tags' => $snippet->tags_list,
282 'scope' => $snippet->scope,
283 'priority' => $snippet->priority,
284 'active' => intval( $snippet->active ),
285 );
286
287 /* Create a new snippet if the ID is not set */
288 if ( 0 == $snippet->id ) {
289
290 $wpdb->insert( $table, $data, '%s' );
291 $snippet->id = $wpdb->insert_id;
292
293 do_action( 'code_snippets/create_snippet', $snippet->id, $table );
294 } else {
295
296 /* Otherwise update the snippet data */
297 $wpdb->update( $table, $data, array( 'id' => $snippet->id ), null, array( '%d' ) );
298
299 do_action( 'code_snippets/update_snippet', $snippet->id, $table );
300 }
301
302 return $snippet->id;
303 }
304
305 /**
306 * Update a snippet entry given a list of fields
307 *
308 * @param int $snippet_id The ID of the snippet to update
309 * @param array $fields An array of fields mapped to their values
310 * @param bool $network Whether the snippet is network-wide or site-wide
311 */
312 function update_snippet_fields( $snippet_id, $fields, $network = null ) {
313 /** @var wpdb $wpdb */
314 global $wpdb;
315
316 $table = code_snippets()->db->get_table_name( $network );
317
318 /* Build a new snippet object for the validation */
319 $snippet = new Code_Snippet();
320 $snippet->id = $snippet_id;
321
322 /* Validate fields through the snippet class and copy them into a clean array */
323 $clean_fields = array();
324
325 foreach ( $fields as $field => $value ) {
326
327 if ( $snippet->set_field( $field, $value ) ) {
328 $clean_fields[ $field ] = $snippet->$field;
329 }
330 }
331
332 /* Update the snippet in the database */
333 $wpdb->update( $table, $clean_fields, array( 'id' => $snippet->id ), null, array( '%d' ) );
334 do_action( 'code_snippets/update_snippet', $snippet->id, $table );
335 }
336
337 /**
338 * Execute a snippet
339 *
340 * Code must NOT be escaped, as
341 * it will be executed directly
342 *
343 * @since 2.0
344 *
345 * @param string $code The snippet code to execute
346 * @param int $id The snippet ID
347 * @param bool $catch_output Whether to attempt to suppress the output of execution using buffers
348 *
349 * @return mixed The result of the code execution
350 */
351 function execute_snippet( $code, $id = 0, $catch_output = true ) {
352
353 if ( empty( $code ) ) {
354 return false;
355 }
356
357 if ( $catch_output ) {
358 ob_start();
359 }
360
361 $result = eval( $code );
362
363 if ( $catch_output ) {
364 ob_end_clean();
365 }
366
367 do_action( 'code_snippets/after_execute_snippet', $id, $code, $result );
368
369 return $result;
370 }
371
372 /**
373 * Run the active snippets
374 *
375 * @since 2.0
376 *
377 * @return bool true on success, false on failure
378 */
379 function execute_active_snippets() {
380
381 /* Bail early if safe mode is active */
382 if ( defined( 'CODE_SNIPPETS_SAFE_MODE' ) && CODE_SNIPPETS_SAFE_MODE || ! apply_filters( 'code_snippets/execute_snippets', true ) ) {
383 return false;
384 }
385
386 /** @var wpdb $wpdb */
387 global $wpdb;
388 $db = code_snippets()->db;
389
390 $current_scope = is_admin() ? 'admin' : 'front-end';
391 $queries = array();
392
393 $sql_format = "SELECT id, code, scope FROM %s WHERE scope IN ('global', 'single-use', %%s) ";
394 $order = 'ORDER BY priority ASC, id ASC';
395
396 /* Fetch snippets from site table */
397 if ( $wpdb->get_var( "SHOW TABLES LIKE '$db->table'" ) === $db->table ) {
398 $queries[ $db->table ] = $wpdb->prepare( sprintf( $sql_format, $db->table ) . 'AND active=1 ' . $order, $current_scope );
399 }
400
401 /* Fetch snippets from the network table */
402 if ( is_multisite() && $wpdb->get_var( "SHOW TABLES LIKE '$db->ms_table'" ) === $db->ms_table ) {
403 $active_shared_ids = get_option( 'active_shared_network_snippets', array() );
404
405 /* If there are active shared snippets, include them in the query */
406 if ( is_array( $active_shared_ids ) && count( $active_shared_ids ) ) {
407
408 /* Build a list of "%d, %d, %d ..." for every active network shared snippet we have */
409 $active_shared_ids_format = implode( ',', array_fill( 0, count( $active_shared_ids ), '%d' ) );
410
411 /* Include them in the query */
412 $sql = sprintf( $sql_format, $db->ms_table ) . " AND (active=1 OR id IN ($active_shared_ids_format)) $order";
413
414 /* Add the scope number to the IDs array, so that it is the first variable in the query */
415 array_unshift( $active_shared_ids, $current_scope );
416 $queries[ $db->ms_table ] = $wpdb->prepare( $sql, $active_shared_ids );
417 array_shift( $active_shared_ids ); // remove it afterwards as we need this variable later
418
419 } else {
420 $sql = sprintf( $sql_format, $db->ms_table ) . 'AND active=1 ' . $order;
421 $queries[ $db->ms_table ] = $wpdb->prepare( $sql, $current_scope );
422 }
423 }
424
425 foreach ( $queries as $table_name => $query ) {
426 $active_snippets = $wpdb->get_results( $query, 'ARRAY_A' );
427
428 if ( ! is_array( $active_snippets ) ) {
429 continue;
430 }
431
432 /* Loop through the returned snippets and execute the PHP code */
433 foreach ( $active_snippets as $snippet ) {
434 $snippet_id = intval( $snippet['id'] );
435 $code = $snippet['code'];
436
437 // if the snippet is a single-use snippet, deactivate it before execution to ensure that the process always happens
438 if ( 'single-use' === $snippet['scope'] ) {
439 if ( $table_name === $db->ms_table && isset( $active_shared_ids ) &&
440 false !== ( $key = array_search( $snippet_id, $active_shared_ids ) ) ) {
441 unset( $active_shared_ids[ $key ] );
442 $active_shared_ids = array_values( $active_shared_ids );
443 update_option( 'active_shared_network_snippets', $active_shared_ids );
444 } else {
445 $wpdb->update( $table_name, array( 'active' => '0' ), array( 'id' => $snippet_id ), array( '%d' ), array( '%d' ) );
446 }
447 }
448
449 if ( apply_filters( 'code_snippets/allow_execute_snippet', true, $snippet_id, $table_name ) ) {
450 execute_snippet( $code, $snippet_id );
451 }
452 }
453 }
454
455 return true;
456 }
457