PluginProbe
Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts / 2.7.0
Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts v2.7.0
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 / admin / includes / class.actions.snippet.php

class.actions.snippet.php in Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts 2.7.0, at admin/includes/class.actions.snippet.php

612 lines 16.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Export/clone snippet
4
5 * @package Woody_Code_Snippets
6 */
7
8 // Exit if accessed directly.
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 /**
14 * Class WINP_Actions_Snippet
15 */
16 class WINP_Actions_Snippet {
17
18 /**
19 * WINP_Actions_Snippet constructor.
20 */
21 public function __construct() {
22 $this->register_hooks();
23 }
24
25 /**
26 * Register hooks
27 *
28 * @return void
29 */
30 public function register_hooks() {
31 add_filter( 'post_row_actions', [ $this, 'post_row_actions' ], 10, 2 );
32 add_filter( 'bulk_actions-edit-' . WINP_SNIPPETS_POST_TYPE, [ $this, 'action_bulk_edit_post' ] );
33 add_filter(
34 'handle_bulk_actions-edit-' . WINP_SNIPPETS_POST_TYPE,
35 [
36 $this,
37 'handle_action_bulk_edit_post',
38 ],
39 10,
40 3
41 );
42
43 add_action( 'post_submitbox_start', [ $this, 'post_submitbox_start' ] );
44 add_action( 'admin_init', [ $this, 'admin_init' ] );
45 add_action( 'current_screen', [ $this, 'current_screen' ] );
46 add_action( 'admin_enqueue_scripts', [ $this, 'admin_enqueue_scripts' ] );
47 }
48
49 /**
50 * Get export url
51 *
52 * @param int $post_id Post ID.
53 *
54 * @return string
55 */
56 private function get_export_url( $post_id ) {
57 $url = admin_url( 'post.php?post=' . $post_id );
58
59 return add_query_arg(
60 [
61 'action' => 'export',
62 '_wpnonce' => wp_create_nonce( 'WINP_Actions_Snippet_' . $post_id ),
63 ],
64 $url
65 );
66 }
67
68 /**
69 * Get close url
70 *
71 * @param int $post_id Post ID.
72 *
73 * @return string
74 */
75 private function get_close_url( $post_id ) {
76 $url = admin_url( 'post.php?post=' . $post_id );
77
78 return add_query_arg(
79 [
80 'action' => 'close',
81 '_wpnonce' => wp_create_nonce( 'winp_close_snippet_' . $post_id ),
82 ],
83 $url
84 );
85 }
86
87 /**
88 * Get clone url
89 *
90 * @param int $post_id Post ID.
91 *
92 * @return string
93 */
94 private function get_clone_url( $post_id ) {
95 $url = admin_url( 'post.php?post=' . $post_id );
96
97 return add_query_arg(
98 [
99 'action' => 'clone',
100 '_wpnonce' => wp_create_nonce( 'winp_clone_snippet_' . $post_id ),
101 ],
102 $url
103 );
104 }
105
106 /**
107 * Post row actions
108 *
109 * @param array<string, string> $actions Array of row actions.
110 * @param WP_Post $post WP_Post object.
111 *
112 * @return mixed
113 */
114 public function post_row_actions( $actions, $post ) {
115 if ( WINP_SNIPPETS_POST_TYPE === $post->post_type ) {
116 $export_link = $this->get_export_url( $post->ID );
117 $clone_link = $this->get_clone_url( $post->ID );
118
119 if ( isset( $actions['trash'] ) ) {
120 $trash = $actions['trash'];
121 unset( $actions['trash'] );
122 }
123
124 $actions['export'] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( $export_link ), esc_html( __( 'Export', 'insert-php' ) ) );
125 $actions['clone'] = sprintf( '<a href="%1$s">%2$s</a>', esc_url( $clone_link ), esc_html( __( 'Clone', 'insert-php' ) ) );
126
127 if ( isset( $trash ) ) {
128 $actions['trash'] = $trash;
129 }
130 }
131
132 return $actions;
133 }
134
135 /**
136 * Action bulk_edit_post
137 *
138 * @param array<string, string> $bulk_actions Array of bulk actions.
139 *
140 * @return mixed
141 */
142 public function action_bulk_edit_post( $bulk_actions ) {
143 $bulk_actions['activate'] = __( 'Activate', 'insert-php' );
144 $bulk_actions['deactivate'] = __( 'Deactivate', 'insert-php' );
145 $bulk_actions['exportsnp'] = __( 'Export', 'insert-php' );
146
147 // Don't show delete action for posts already in trash.
148 $current_screen = get_current_screen();
149 if ( ! $current_screen || ( isset( $_GET['post_status'] ) && 'trash' !== $_GET['post_status'] ) || ( ! isset( $_GET['post_status'] ) ) ) {
150 $bulk_actions['deletesnp'] = __( 'Delete', 'insert-php' );
151 $bulk_actions['clonenp'] = __( 'Clone', 'insert-php' );
152 }
153
154 return $bulk_actions;
155 }
156
157 /**
158 * Handle action bulk edit post
159 *
160 * @param string $redirect_to URL to redirect to.
161 * @param string $doaction Do action.
162 * @param array<int> $post_ids Array of post IDs.
163 *
164 * @return mixed
165 */
166 public function handle_action_bulk_edit_post( $redirect_to, $doaction, $post_ids ) {
167 if ( ! WINP_Plugin::app()->current_user_car() ) {
168 return false;
169 }
170
171 check_admin_referer( 'bulk-posts' );
172
173 $actions = [
174 'exportsnp' => 1,
175 'deletesnp' => 1,
176 'deactivate' => 1,
177 'activate' => 1,
178 'clonenp' => 1,
179 ];
180
181 if ( ! isset( $actions[ $doaction ] ) ) {
182 return $redirect_to;
183 }
184
185 if ( count( $post_ids ) ) {
186 switch ( $doaction ) {
187 case 'exportsnp':
188 $this->quick_export_snippets( $post_ids );
189 break;
190
191 case 'clonenp':
192 $this->clone_snippets( $post_ids );
193 break;
194
195 case 'deletesnp':
196 $this->delete_snippets( $post_ids );
197 break;
198
199 case 'deactivate':
200 $this->deactivate_snippets( $post_ids );
201 break;
202
203 case 'activate':
204 $this->activate_snippets( $post_ids );
205 break;
206 }
207 }
208
209 return $redirect_to;
210 }
211
212 /**
213 * Post submitbox start
214 *
215 * @return void
216 */
217 public function post_submitbox_start() {
218 global $post;
219
220 if ( $post && WINP_SNIPPETS_POST_TYPE == $post->post_type ) {
221 if ( WINP_Helper::getMetaOption( $post->ID, 'snippet_draft', false ) ) {
222 $close_link = $this->get_close_url( $post->ID );
223 echo "<div id='winp-close-action'>" . sprintf( '<a href="%1$s" class="button button-large">%2$s</a>', esc_url( $close_link ), esc_html( __( 'Close', 'insert-php' ) ) ) . '</div>';
224 } else {
225 $export_link = $this->get_export_url( $post->ID );
226 echo "<div id='winp-export-action'>" . sprintf( '<a href="%1$s">%2$s</a>', esc_url( $export_link ), esc_html( __( 'Export', 'insert-php' ) ) ) . '</div>';
227 }
228 }
229 }
230
231 /**
232 * Prepare data
233 *
234 * @param array<int> $ids Snippet IDs.
235 *
236 * @return array<mixed>
237 */
238 private function prepare_data( $ids ) {
239 $snippets = [];
240
241 if ( count( $ids ) ) {
242 foreach ( $ids as $id ) {
243 $post = get_post( $id );
244
245 if ( ! $post ) {
246 continue;
247 }
248
249 $snippet = [
250 'name' => $post->post_name,
251 'title' => $post->post_title,
252 'content' => $post->post_content,
253 'location' => $this->get_meta( $id, 'snippet_location' ),
254 'type' => $this->get_meta( $id, 'snippet_type' ),
255 'filters' => $this->get_meta( $id, 'snippet_filters' ),
256 'changed_filters' => $this->get_meta( $id, 'changed_filters' ),
257 'scope' => $this->get_meta( $id, 'snippet_scope' ),
258 'priority' => $this->get_meta( $id, 'snippet_priority' ),
259 'description' => $this->get_meta( $id, 'snippet_description' ),
260 'attributes' => $this->get_meta( $id, 'snippet_tags' ),
261 'tags' => $this->get_taxonomy_tags( $id ),
262 ];
263
264 $snippets[] = apply_filters( 'wbcr/inp/snippet/prepare_data', $snippet, $id, $this );
265 }
266 }
267
268 return $snippets;
269 }
270
271 /**
272 * Get file name
273 *
274 * @param string $format File format.
275 * @param array<int> $ids Snippet IDs.
276 * @param array<mixed> $snippets Snippets data.
277 *
278 * @return string
279 */
280 public function get_filename( $format, $ids, $snippets ) {
281 $snippets = empty( $snippets ) ? $this->prepare_data( $ids ) : $snippets;
282
283 /* Build the export filename */
284 if ( 1 == count( $ids ) ) {
285 $name = $snippets[0]['title'];
286 $title = strtolower( $name );
287 } else {
288 /* Otherwise, use the site name as set in Settings > General */
289 $title = strtolower( get_bloginfo( 'name' ) );
290 }
291
292 $filename = "{$title}.php-code-snippets.{$format}";
293
294 return $filename;
295 }
296
297 /**
298 * Export snippets - prepare and return export data
299 *
300 * @param array<int> $ids Snippet IDs to export.
301 * @param bool $zip Whether to create a zip file.
302 * @return array<mixed> Export data with filename, data, and count.
303 */
304 public function export_snippets( $ids, $zip = false ) {
305 $snippets = $this->prepare_data( $ids );
306 $filename = $this->get_filename( 'json', $ids, $snippets );
307
308 $data = [
309 'generator' => 'PHP Code Snippets v' . WINP_PLUGIN_VERSION,
310 'date_created' => gmdate( 'Y-m-d H:i' ),
311 'snippets' => $snippets,
312 ];
313
314 if ( $zip ) {
315 $zipname = str_replace( '.json', '.zip', $filename );
316 $upload_dir = wp_upload_dir();
317 $zippath = $upload_dir['path'] . '/' . $zipname;
318
319 $zip_archive = new ZipArchive();
320 if ( true === $zip_archive->open( $zippath, ZipArchive::CREATE | ZipArchive::OVERWRITE ) ) {
321 // Add individual JSON file for each snippet.
322 foreach ( $snippets as $snippet ) {
323 $snippet_data = [
324 'generator' => 'PHP Code Snippets v' . WINP_PLUGIN_VERSION,
325 'date_created' => gmdate( 'Y-m-d H:i' ),
326 'snippets' => [ $snippet ],
327 ];
328 $json_content = wp_json_encode( $snippet_data, JSON_PRETTY_PRINT );
329
330 if ( false === $json_content ) {
331 continue;
332 }
333
334 $snippet_filename = sanitize_file_name( strtolower( $snippet['title'] ) ) . '.php-code-snippets.json';
335 $zip_archive->addFromString( $snippet_filename, $json_content );
336 }
337
338 $zip_archive->close();
339 // phpcs:ignore WordPressVIPMinimum.Performance.FetchingRemoteData.FileGetContentsUnknown -- Reading local file from wp_upload_dir(), not remote.
340 $zip_content = file_get_contents( $zippath );
341
342 // Cleanup temporary file.
343 // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.file_ops_unlink -- Deleting temporary files in wp_upload_dir().
344 unlink( $zippath );
345
346 return [
347 'filename' => $zipname,
348 'data' => $zip_content,
349 'count' => count( $snippets ),
350 'is_zip' => true,
351 ];
352 }
353 }
354
355 return [
356 'filename' => $filename,
357 'data' => $data,
358 'count' => count( $snippets ),
359 'is_zip' => false,
360 ];
361 }
362
363 /**
364 * Export snippets in JSON format
365 *
366 * @param array<int> $ids Snippet IDs.
367 *
368 * @return void
369 */
370 public function quick_export_snippets( $ids ) {
371 $snippets = $this->export_snippets( $ids, count( $ids ) > 1 );
372
373 $filename = $snippets['filename'];
374 $data = $snippets['data'];
375 $is_zip = $snippets['is_zip'];
376 $mime_type = $is_zip ? 'application/zip' : 'application/json';
377
378 /* Set HTTP headers */
379 header( 'Content-Disposition: attachment; filename=' . sanitize_file_name( $filename ) );
380 header( "Content-Type: $mime_type; charset=" . get_bloginfo( 'charset' ) );
381
382 // For zip files, output raw binary data. For JSON, encode the data.
383 if ( $is_zip ) {
384 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Binary zip file content, escaping would corrupt the file.
385 echo $data;
386 } else {
387 echo wp_json_encode( $data, JSON_PRETTY_PRINT );
388 }
389 exit;
390 }
391
392 /**
393 * Clone snippets
394 *
395 * @param array<int> $ids Snippet IDs.
396 *
397 * @return void
398 */
399 public function clone_snippets( $ids ) {
400 $snippets = $this->prepare_data( $ids );
401
402 if ( $snippets ) {
403 foreach ( $snippets as $snippet ) {
404 $data = [
405 'post_title' => $snippet['title'] . ' copy',
406 'post_content' => $snippet['content'],
407 'post_status' => 'draft',
408 'post_type' => WINP_SNIPPETS_POST_TYPE,
409 ];
410
411 $snippet['id'] = wp_insert_post( $data );
412
413 update_post_meta( $snippet['id'], 'wbcr_inp_snippet_location', $snippet['location'] );
414 update_post_meta( $snippet['id'], 'wbcr_inp_snippet_type', $snippet['type'] );
415 update_post_meta( $snippet['id'], 'wbcr_inp_snippet_filters', $snippet['filters'] );
416 update_post_meta( $snippet['id'], 'wbcr_inp_changed_filters', $snippet['changed_filters'] );
417 update_post_meta( $snippet['id'], 'wbcr_inp_snippet_scope', $snippet['scope'] );
418 update_post_meta( $snippet['id'], 'wbcr_inp_snippet_priority', $snippet['priority'] );
419 update_post_meta( $snippet['id'], 'wbcr_inp_snippet_description', $snippet['description'] );
420 update_post_meta( $snippet['id'], 'wbcr_inp_snippet_tags', $snippet['attributes'] );
421 update_post_meta( $snippet['id'], 'wbcr_inp_snippet_activate', 0 );
422 $this->update_taxonomy_tags( $snippet['id'], $snippet['tags'] );
423
424 do_action( 'wbcr/inp/snippet/clone_meta', $snippet['id'], $snippet, $this );
425 }
426 }
427 }
428
429 /**
430 * Action admin_init
431 *
432 * @return void
433 */
434 public function admin_init() {
435 if ( ! WINP_Plugin::app()->current_user_car() ) {
436 return;
437 }
438
439 $post_id = WINP_HTTP::get( 'post', 0, 'intval' );
440 $action = WINP_HTTP::get( 'action' );
441
442 if ( ! empty( $action ) && ! empty( $post_id ) ) {
443 switch ( $action ) {
444 case 'export':
445 check_admin_referer( 'WINP_Actions_Snippet_' . $post_id );
446 $this->quick_export_snippets( [ $post_id ] );
447 break;
448
449 case 'clone':
450 check_admin_referer( 'winp_clone_snippet_' . $post_id );
451 $this->clone_snippets( [ $post_id ] );
452 wp_safe_redirect( admin_url( 'edit.php?post_type=' . WINP_SNIPPETS_POST_TYPE ) );
453 exit();
454
455 case 'close':
456 check_admin_referer( 'winp_close_snippet_' . $post_id );
457 wp_delete_post( $post_id );
458 wp_safe_redirect( admin_url( 'edit.php?post_type=' . WINP_SNIPPETS_POST_TYPE . '&page=snippet-library' ) );
459 exit();
460
461 default:
462 return;
463 }
464 }
465 }
466
467 /**
468 * Action current_screen
469 * Add script for disabled export button
470 *
471 * @return void
472 */
473 public function current_screen() {
474 $current_screen = get_current_screen();
475
476 if ( null === $current_screen ) {
477 return;
478 }
479
480 if ( 'edit-wbcr-snippets' === $current_screen->id && WINP_SNIPPETS_POST_TYPE === $current_screen->post_type && ! WINP_Plugin::app()->get_api_object()->is_key() ) {
481 do_action( 'themeisle_internal_page', WINP_PLUGIN_SLUG, 'wbcr-snippets' );
482 }
483 }
484
485 /**
486 * Add style for close button for auto-draft snippet (preview)
487 *
488 * @return void
489 */
490 public function admin_enqueue_scripts() {
491 global $post;
492
493 $current_screen = get_current_screen();
494
495 if ( null === $current_screen ) {
496 return;
497 }
498
499 if ( 'wbcr-snippets' === $current_screen->id && WINP_SNIPPETS_POST_TYPE === $post->post_type && WINP_Helper::getMetaOption( get_the_ID(), 'snippet_draft', false ) ) {
500 wp_enqueue_style( 'winp-snippet-preview', WINP_PLUGIN_URL . '/admin/assets/css/snippet-preview.css', [], WINP_PLUGIN_VERSION );
501
502 // Remove Clear cache button for WP-Rocket plugin in preview snippet page.
503 remove_action( 'post_submitbox_start', 'rocket_post_submitbox_start' );
504 }
505 }
506
507 /**
508 * Delete snippets
509 *
510 * @param array<int> $ids Snippet IDs.
511 *
512 * @return void
513 */
514 private function delete_snippets( $ids ) {
515 if ( count( $ids ) ) {
516 foreach ( $ids as $id ) {
517 wp_trash_post( $id );
518 }
519 }
520 }
521
522 /**
523 * Deactivate snippets
524 *
525 * @param array<int> $ids Snippet IDs.
526 *
527 * @return void
528 */
529 private function deactivate_snippets( $ids ) {
530 if ( count( $ids ) ) {
531 foreach ( $ids as $id ) {
532 update_post_meta( $id, 'wbcr_inp_snippet_activate', 0 );
533 }
534 }
535 }
536
537 /**
538 * Activate snippets
539 *
540 * @param array<int> $ids Snippet IDs.
541 *
542 * @return void
543 */
544 private function activate_snippets( $ids ) {
545 if ( count( $ids ) ) {
546 foreach ( $ids as $id ) {
547 $is_activate = (int) WINP_Helper::getMetaOption( $id, 'snippet_activate', 0 );
548 $snippet_scope = WINP_Helper::getMetaOption( $id, 'snippet_scope' );
549 $snippet_type = WINP_Helper::get_snippet_type( $id );
550
551 if ( ( 'evrywhere' === $snippet_scope || 'auto' === $snippet_scope ) && ! $is_activate && WINP_SNIPPET_TYPE_TEXT !== $snippet_type && WINP_SNIPPET_TYPE_AD !== $snippet_type && WINP_Plugin::app()->get_execute_object()->getSnippetError( $id ) ) {
552 continue;
553 }
554
555 update_post_meta( $id, 'wbcr_inp_snippet_activate', 1 );
556 }
557 }
558 }
559
560
561 /**
562 * Get taxonomy tags
563 *
564 * @param int $snippet_id Snippet ID.
565 *
566 * @return array<string>
567 */
568 private function get_taxonomy_tags( $snippet_id ) {
569 $tags = [];
570
571 if ( $snippet_id ) {
572 $terms = wp_get_post_terms( $snippet_id, WINP_SNIPPETS_TAXONOMY, [ 'fields' => 'slugs' ] );
573 if ( ! is_wp_error( $terms ) ) {
574 return $terms;
575 }
576 }
577
578 return $tags;
579 }
580
581 /**
582 * Update taxonomy tags
583 *
584 * @param int $snippet_id Snippet ID.
585 * @param array<string> $tags Tags array.
586 *
587 * @return void
588 */
589 private function update_taxonomy_tags( $snippet_id, $tags ) {
590 if ( ! empty( $tags ) ) {
591 foreach ( $tags as $tag_slug ) {
592 $term = get_term_by( 'slug', $tag_slug, WINP_SNIPPETS_TAXONOMY );
593 if ( $term ) {
594 wp_set_post_terms( $snippet_id, [ $term->term_id ], WINP_SNIPPETS_TAXONOMY, true );
595 }
596 }
597 }
598 }
599
600 /**
601 * Get post meta
602 *
603 * @param int $post_id Post ID.
604 * @param string $meta_name Meta name.
605 *
606 * @return mixed
607 */
608 private function get_meta( $post_id, $meta_name ) {
609 return get_post_meta( $post_id, 'wbcr_inp_' . $meta_name, true );
610 }
611 }
612