PluginProbe
Code Snippets / 2.10.0
Code Snippets v2.10.0
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.10.0, at php/snippet-ops.php

599 lines 16.7 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 * @return array An array of Snippet objects
20 */
21 function get_snippets( array $ids = array(), $multisite = null ) {
22 /** @var wpdb $wpdb */
23 global $wpdb;
24
25 $db = code_snippets()->db;
26 $multisite = $db->validate_network_param( $multisite );
27 $table = $db->get_table_name( $multisite );
28
29 $ids_count = count( $ids );
30
31 /* If only one ID has been passed in, defer to the get_snippet() function */
32 if ( 1 == $ids_count ) {
33 return array( get_snippet( $ids[0] ) );
34 }
35
36 /* Build a query containing the specified IDs if there are any */
37 if ( $ids_count > 1 ) {
38 $sql = sprintf(
39 'SELECT * FROM %s WHERE id IN (%s);',
40 $table,
41 implode( ',', array_fill( 0, $ids_count, '%d' ) )
42 );
43 $sql = $wpdb->prepare( $sql, $ids );
44
45 } else {
46 $sql = "SELECT * FROM $table;";
47 }
48
49 /* Retrieve the results from the database */
50 $snippets = $wpdb->get_results( $sql, ARRAY_A );
51
52 /* Convert snippets to snippet objects */
53 foreach ( $snippets as $index => $snippet ) {
54 $snippet['network'] = $multisite;
55 $snippets[ $index ] = new Code_Snippet( $snippet );
56 }
57
58 return apply_filters( 'code_snippets/get_snippets', $snippets, $multisite );
59 }
60
61 /**
62 * Gets all of the used tags from the database
63 * @since 2.0
64 */
65 function get_all_snippet_tags() {
66 /** @var wpdb $wpdb */
67 global $wpdb;
68
69 /* Grab all tags from the database */
70 $tags = array();
71 $table = code_snippets()->db->get_table_name();
72 $all_tags = $wpdb->get_col( "SELECT `tags` FROM $table" );
73
74 /* Merge all tags into a single array */
75 foreach ( $all_tags as $snippet_tags ) {
76 $snippet_tags = code_snippets_build_tags_array( $snippet_tags );
77 $tags = array_merge( $snippet_tags, $tags );
78 }
79
80 /* Remove duplicate tags */
81 return array_values( array_unique( $tags, SORT_REGULAR ) );
82 }
83 /**
84 * Make sure that the tags are a valid array
85 * @since 2.0
86 *
87 * @param mixed $tags The tags to convert into an array
88 * @return array The converted tags
89 */
90 function code_snippets_build_tags_array( $tags ) {
91
92 /* If there are no tags set, return an empty array */
93 if ( empty( $tags ) ) {
94 return array();
95 }
96
97 /* If the tags are set as a string, convert them into an array */
98 if ( is_string( $tags ) ) {
99 $tags = strip_tags( $tags );
100 $tags = str_replace( ', ', ',', $tags );
101 $tags = explode( ',', $tags );
102 }
103
104 /* If we still don't have an array, just convert whatever we do have into one */
105 return (array) $tags;
106 }
107
108 /**
109 * Retrieve a single snippets from the database.
110 * Will return empty snippet object if no snippet
111 * ID is specified
112 *
113 * @since 2.0
114 *
115 * @uses $wpdb to query the database for snippets
116 * @uses code_snippets()->db->get_table_name() to dynamically retrieve the snippet table name
117 *
118 * @param int $id The ID of the snippet to retrieve. 0 to build a new snippet
119 * @param boolean|null $multisite Retrieve a multisite-wide or site-wide snippet?
120 *
121 * @return Code_Snippet A single snippet object
122 */
123 function get_snippet( $id = 0, $multisite = null ) {
124 /** @var wpdb $wpdb */
125 global $wpdb;
126
127 $id = absint( $id );
128 $table = code_snippets()->db->get_table_name( $multisite );
129
130 if ( 0 !== $id ) {
131
132 /* Retrieve the snippet from the database */
133 $snippet = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table WHERE id = %d", $id ) );
134
135 /* Unescape the snippet data, ready for use */
136 $snippet = new Code_Snippet( $snippet );
137
138 } else {
139
140 /* Get an empty snippet object */
141 $snippet = new Code_Snippet();
142 }
143
144 $snippet->network = $multisite;
145
146 return apply_filters( 'code_snippets/get_snippet', $snippet, $id, $multisite );
147 }
148
149 /**
150 * Activates a snippet
151 *
152 * @since 2.0
153 *
154 * @uses $wpdb to set the snippet's active status
155 *
156 * @param int $id The ID of the snippet to activate
157 * @param bool|null $multisite Are the snippets multisite-wide or site-wide?
158 */
159 function activate_snippet( $id, $multisite = null ) {
160 /** @var wpdb $wpdb */
161 global $wpdb;
162 $table = code_snippets()->db->get_table_name( $multisite );
163
164 $wpdb->update(
165 $table,
166 array( 'active' => '1' ),
167 array( 'id' => $id ),
168 array( '%d' ),
169 array( '%d' )
170 );
171
172 /* Remove snippet from shared network snippet list if it was Network Activated */
173 if ( $table == $wpdb->ms_snippets && $shared_network_snippets = get_site_option( 'shared_network_snippets', false ) ) {
174 $shared_network_snippets = array_diff( $shared_network_snippets, array( $id ) );
175 update_site_option( 'shared_network_snippets', $shared_network_snippets );
176 }
177
178 do_action( 'code_snippets/activate_snippet', $id, $multisite );
179 }
180
181 /**
182 * Deactivate a snippet
183 *
184 * @since 2.0
185 *
186 * @uses $wpdb to set the snippets' active status
187 *
188 * @param int $id The ID of the snippet to deactivate
189 * @param bool|null $multisite Are the snippets multisite-wide or site-wide?
190 */
191 function deactivate_snippet( $id, $multisite = null ) {
192 /** @var wpdb $wpdb */
193 global $wpdb;
194 $table = code_snippets()->db->get_table_name( $multisite );
195
196 /* Set the snippet to active */
197
198 $wpdb->update(
199 $table,
200 array( 'active' => '0' ),
201 array( 'id' => $id ),
202 array( '%d' ),
203 array( '%d' )
204 );
205
206 /* Update the recently active list */
207
208 $recently_active = array( $id => time() );
209
210 if ( $table === $wpdb->ms_snippets ) {
211
212 update_site_option(
213 'recently_activated_snippets',
214 $recently_active + (array) get_site_option( 'recently_activated_snippets' )
215 );
216 } elseif ( $table === $wpdb->snippets ) {
217
218 update_option(
219 'recently_activated_snippets',
220 $recently_active + (array) get_option( 'recently_activated_snippets' )
221 );
222 }
223
224 do_action( 'code_snippets/deactivate_snippet', $id, $multisite );
225 }
226
227 /**
228 * Deletes a snippet from the database
229 *
230 * @since 2.0
231 * @uses $wpdb to access the database
232 * @uses code_snippets()->db->get_table_name() to dynamically retrieve the name of the snippet table
233 *
234 * @param int $id The ID of the snippet to delete
235 * @param bool|null $multisite Delete from site-wide or network-wide table?
236 */
237 function delete_snippet( $id, $multisite = null ) {
238 /** @var wpdb $wpdb */
239 global $wpdb;
240
241 $wpdb->delete(
242 code_snippets()->db->get_table_name( $multisite ),
243 array( 'id' => $id ),
244 array( '%d' )
245 );
246
247 do_action( 'code_snippets/delete_snippet', $id, $multisite );
248 }
249
250 /**
251 * Saves a snippet to the database.
252 *
253 * @since 2.0
254 *
255 * @uses $wpdb to update/add the snippet to the database
256 * @uses code_snippets()->db->get_table_name() To dynamically retrieve the name of the snippet table
257 *
258 * @param Code_Snippet $snippet The snippet to add/update to the database
259 *
260 * @return int The ID of the snippet
261 */
262 function save_snippet( Code_Snippet $snippet ) {
263 /** @var wpdb $wpdb */
264 global $wpdb;
265
266 $table = code_snippets()->db->get_table_name( $snippet->network );
267
268 /* Build array of data to insert */
269 $data = array(
270 'name' => $snippet->name,
271 'description' => $snippet->desc,
272 'code' => $snippet->code,
273 'tags' => $snippet->tags_list,
274 'scope' => $snippet->scope,
275 'active' => intval( $snippet->active ),
276 );
277
278 /* Create a new snippet if the ID is not set */
279 if ( 0 == $snippet->id ) {
280
281 $wpdb->insert( $table, $data, '%s' );
282 $snippet->id = $wpdb->insert_id;
283
284 do_action( 'code_snippets/create_snippet', $snippet->id, $table );
285 } else {
286
287 /* Otherwise update the snippet data */
288 $wpdb->update( $table, $data, array( 'id' => $snippet->id ), null, array( '%d' ) );
289
290 do_action( 'code_snippets/update_snippet', $snippet->id, $table );
291 }
292
293 return $snippet->id;
294 }
295
296 /**
297 * Update a snippet entry given a list of fields
298 *
299 * @param int $snippet_id The ID of the snippet to update
300 * @param array $fields An array of fields mapped to their values
301 * @param bool $network Whether the snippet is network-wide or site-wide
302 */
303 function update_snippet_fields( $snippet_id, $fields, $network = null ) {
304 /** @var wpdb $wpdb */
305 global $wpdb;
306
307 $table = code_snippets()->db->get_table_name( $network );
308
309 /* Build a new snippet object for the validation */
310 $snippet = new Code_Snippet();
311 $snippet->id = $snippet_id;
312
313 /* Validate fields through the snippet class and copy them into a clean array */
314 $clean_fields = array();
315
316 foreach ( $fields as $field => $value ) {
317
318 if ( $snippet->set_field( $field, $value ) ) {
319 $clean_fields[ $field ] = $snippet->$field;
320 }
321 }
322
323 /* Update the snippet in the database */
324 $wpdb->update( $table, $clean_fields, array( 'id' => $snippet->id ), null, array( '%d' ) );
325 do_action( 'code_snippets/update_snippet', $snippet->id, $table );
326 }
327
328 /**
329 * Imports snippets from a JSON file
330 *
331 * @since 2.9.7
332 *
333 * @uses save_snippet() to add the snippets to the database
334 *
335 * @param string $file The path to the file to import
336 * @param bool|null $multisite Import into network-wide table or site-wide table?
337 * @param string $dup_action Action to take if duplicate snippets are detected. Can be 'skip', 'ignore', or 'replace'
338 *
339 * @return array|bool An array of imported snippet IDs on success, false on failure
340 */
341 function import_snippets_json( $file, $multisite = null, $dup_action = 'ignore' ) {
342
343 if ( ! file_exists( $file ) || ! is_file( $file ) ) {
344 return false;
345 }
346
347 $raw_data = file_get_contents( $file );
348 $data = json_decode( $raw_data, true );
349
350 $imported = array();
351
352 /* Get a list of existing snippet names keyed to their IDs */
353 $existing_snippets = array();
354 if ( 'replace' == $dup_action || 'skip' === $dup_action ) {
355 $all_snippets = get_snippets( array(), $multisite );
356
357 foreach ( $all_snippets as $snippet ) {
358 if ( $snippet->name ) {
359 $existing_snippets[ $snippet->name ] = $snippet->id;
360 }
361 }
362 }
363
364 /* Loop through all snippets */
365
366 /** @var DOMElement $snippet_xml */
367 foreach ( $data['snippets'] as $snippet ) {
368 $snippet = new Code_Snippet( $snippet );
369 $snippet->network = $multisite;
370
371 if ( 'ignore' !== $dup_action && isset( $existing_snippets[ $snippet->name ] ) ) {
372
373 if ( 'replace' === $dup_action ) {
374 $snippet->id = $existing_snippets[ $snippet->name ];
375 } elseif ( 'skip' === $dup_action ) {
376 continue;
377 }
378 }
379
380 /* Save the snippet and increase the counter if successful */
381 if ( $snippet_id = save_snippet( $snippet ) ) {
382 $imported[] = $snippet_id;
383 }
384 }
385
386 do_action( 'code_snippets/import/json', $file, $multisite );
387 return $imported;
388 }
389
390 /**
391 * Imports snippets from an XML file
392 *
393 * @since 2.0
394 *
395 * @uses save_snippet() to add the snippets to the database
396 *
397 * @param string $file The path to the file to import
398 * @param bool|null $multisite Import into network-wide table or site-wide table?
399 * @param string $dup_action Action to take if duplicate snippets are detected. Can be 'skip', 'ignore', or 'replace'
400 *
401 * @return array|bool An array of imported snippet IDs on success, false on failure
402 */
403 function import_snippets_xml( $file, $multisite = null, $dup_action = 'ignore' ) {
404
405 if ( ! file_exists( $file ) || ! is_file( $file ) ) {
406 return false;
407 }
408
409 $dom = new DOMDocument( '1.0', get_bloginfo( 'charset' ) );
410 $dom->load( $file );
411
412 $snippets_xml = $dom->getElementsByTagName( 'snippet' );
413 $fields = array( 'name', 'description', 'desc', 'code', 'tags', 'scope' );
414 $imported = array();
415
416 /* Get a list of existing snippet names keyed to their IDs */
417 $existing_snippets = array();
418 if ( 'replace' == $dup_action || 'skip' === $dup_action ) {
419 $all_snippets = get_snippets( array(), $multisite );
420
421 foreach ( $all_snippets as $snippet ) {
422 if ( $snippet->name ) {
423 $existing_snippets[ $snippet->name ] = $snippet->id;
424 }
425 }
426 }
427
428 /* Loop through all snippets */
429
430 /** @var DOMElement $snippet_xml */
431 foreach ( $snippets_xml as $snippet_xml ) {
432 $snippet = new Code_Snippet();
433 $snippet->network = $multisite;
434
435 /* Build a snippet object by looping through the field names */
436 foreach ( $fields as $field_name ) {
437
438 /* Fetch the field element from the document */
439 $field = $snippet_xml->getElementsByTagName( $field_name )->item( 0 );
440
441 /* If the field element exists, add it to the snippet object */
442 if ( isset( $field->nodeValue ) ) {
443 $snippet->set_field( $field_name, $field->nodeValue );
444 }
445 }
446
447 /* Get scope from attribute */
448 $scope = $snippet_xml->getAttribute( 'scope' );
449 if ( ! empty( $scope ) ) {
450 $snippet->scope = $scope;
451 }
452
453 if ( 'ignore' !== $dup_action && isset( $existing_snippets[ $snippet->name ] ) ) {
454 if ( 'replace' === $dup_action ) {
455 $snippet->id = $existing_snippets[ $snippet->name ];
456 } elseif ( 'skip' === $dup_action ) {
457 continue;
458 }
459 }
460
461 /* Save the snippet and increase the counter if successful */
462 if ( $snippet_id = save_snippet( $snippet ) ) {
463 $imported[] = $snippet_id;
464 }
465 }
466
467 do_action( 'code_snippets/import/xml', $file, $multisite );
468 return $imported;
469 }
470
471 /**
472 * Exports snippets as an XML, JSON or PHP file
473 *
474 * @since 2.0
475 * @uses Code_Snippets_Export to export selected snippets
476 * @uses code_snippets()->db->get_table_name() to dynamically retrieve the name of the snippet table
477 *
478 * @param array $ids The IDs of the snippets to export
479 * @param bool|null $multisite Is the snippet a network-wide or site-wide snippet?
480 * @param string $format Export to json, xml or php?
481 */
482 function export_snippets( $ids, $multisite = null, $format = 'json' ) {
483 $table = code_snippets()->db->get_table_name( $multisite );
484
485 if ( ! class_exists( 'Code_Snippets_Export' ) ) {
486 require_once plugin_dir_path( CODE_SNIPPETS_FILE ) . 'php/class-export.php';
487 }
488
489 $class = new Code_Snippets_Export( $ids, $table, $format );
490 $class->do_export();
491 }
492
493 /**
494 * Execute a snippet
495 *
496 * Code must NOT be escaped, as
497 * it will be executed directly
498 *
499 * @since 2.0
500 *
501 * @param string $code The snippet code to execute
502 * @param int $id The snippet ID
503 * @param bool $catch_output Whether to attempt to suppress the output of execution using buffers
504 *
505 * @return mixed The result of the code execution
506 */
507 function execute_snippet( $code, $id = 0, $catch_output = true ) {
508
509 if ( empty( $code ) ) {
510 return false;
511 }
512
513 if ( $catch_output ) {
514 ob_start();
515 }
516
517 $result = eval( $code );
518
519 if ( $catch_output ) {
520 ob_end_clean();
521 }
522
523 do_action( 'code_snippets/after_execute_snippet', $id, $code, $result );
524
525 return $result;
526 }
527
528 /**
529 * Run the active snippets
530 *
531 * @since 2.0
532 *
533 * @return bool true on success, false on failure
534 */
535 function execute_active_snippets() {
536
537 if ( ! apply_filters( 'code_snippets/execute_snippets', true ) ) {
538 return false;
539 }
540
541 /** @var wpdb $wpdb */
542 global $wpdb;
543
544 $current_scope = is_admin() ? 'admin' : 'front-end';
545 $queries = array();
546
547 $sql_format = "SELECT id, code, scope FROM %s WHERE scope IN ('global', 'single-use', %%s) ";
548
549 /* Fetch snippets from site table */
550 if ( $wpdb->get_var( "SHOW TABLES LIKE '$wpdb->snippets'" ) === $wpdb->snippets ) {
551 $queries[ $wpdb->snippets ] = $wpdb->prepare( sprintf( $sql_format, $wpdb->snippets ) . 'AND active=1', $current_scope );
552 }
553
554 /* Fetch snippets from the network table */
555 if ( is_multisite() && $wpdb->get_var( "SHOW TABLES LIKE '$wpdb->ms_snippets'" ) === $wpdb->ms_snippets ) {
556 $active_shared_ids = get_option( 'active_shared_network_snippets', array() );
557
558 /* If there are active shared snippets, include them in the query */
559 if ( count( $active_shared_ids ) ) {
560
561 /* Build a list of "%d, %d, %d ..." for every active network shared snippet we have */
562 $active_shared_ids_format = implode( ',', array_fill( 0, count( $active_shared_ids ), '%d' ) );
563
564 /* Include them in the query */
565 $sql = sprintf( $sql_format, $wpdb->ms_snippets ) . " AND (active=1 OR id IN ($active_shared_ids_format))";
566
567 /* Add the scope number to the IDs array, so that it is the first variable in the query */
568 array_unshift( $active_shared_ids, $current_scope );
569 $queries[ $wpdb->ms_snippets ] = $wpdb->prepare( $sql, $active_shared_ids );
570
571 } else {
572 $sql = sprintf( $sql_format, $wpdb->ms_snippets ) . 'AND active=1';
573 $queries[ $wpdb->ms_snippets ] = $wpdb->prepare( $sql, $current_scope );
574 }
575 }
576
577 foreach ( $queries as $table_name => $query ) {
578 $active_snippets = $wpdb->get_results( $query, ARRAY_A );
579
580 /* Loop through the returned snippets and execute the PHP code */
581 foreach ( $active_snippets as $snippet ) {
582 $snippet_id = intval( $snippet['id'] );
583 $code = $snippet['code'];
584
585 if ( 'single-use' === $snippet['scope'] ) {
586 $wpdb->update( $table_name, array( 'active' => '0' ), array( 'id' => $snippet_id ), array( '%d' ), array( '%d' ) );
587 }
588
589 if ( apply_filters( 'code_snippets/allow_execute_snippet', true, $snippet_id, $table_name ) ) {
590 execute_snippet( $code, $snippet_id );
591 }
592 }
593 }
594
595 return true;
596 }
597
598
599