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 / admin / includes / class.common.snippet.php

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

887 lines 26.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Common functions for snippets
4 *
5 * @package Woody_Code_Snippets
6 */
7
8 // Exit if accessed directly.
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 /**
14 * Class for common snippet functions
15 */
16 class WINP_Common_Snippet {
17
18 /**
19 * Register hooks
20 *
21 * @return void
22 */
23 public function register_hooks() {
24 add_action( 'current_screen', [ $this, 'current_screen' ] );
25 add_action( 'edit_form_before_permalink', [ $this, 'edit_form_before_permalink' ] );
26 add_action( 'admin_notices', [ $this, 'create_uploads_directory' ] );
27 add_action( 'before_delete_post', [ $this, 'before_delete_post' ] );
28 add_action( 'save_post', [ $this, 'save_post' ] );
29 add_action( 'save_post_' . WINP_SNIPPETS_POST_TYPE, [ $this, 'save_snippet' ], 10, 3 );
30 add_action( 'auto-draft_to_publish', [ $this, 'publish_snippet' ] );
31
32 add_filter( 'script_loader_src', [ $this, 'unload_scripts' ], 10, 2 );
33 }
34
35 /**
36 * Create the custom-css-js dir in uploads directory
37 *
38 * Show a message if the directory is not writable
39 *
40 * Create an empty index.php file inside
41 *
42 * @return void
43 */
44 public function create_uploads_directory() {
45 $current_screen = get_current_screen();
46
47 // Check if we are editing a custom-css-js post.
48 if ( 'post' !== $current_screen->base || WINP_SNIPPETS_POST_TYPE !== $current_screen->post_type ) {
49 return;
50 }
51
52 $dir = WINP_UPLOAD_DIR;
53
54 // Create the dir if it doesn't exist.
55 if ( ! file_exists( $dir ) ) {
56 wp_mkdir_p( $dir );
57 }
58
59 // Show a message if it couldn't create the dir.
60 if ( ! file_exists( $dir ) ) { ?>
61 <div class="notice notice-error is-dismissible">
62 <?php
63 /* translators: %s: Directory name */
64 ?>
65 <p>
66 <?php
67 printf(
68 /* translators: %s: Directory path */
69 esc_html__( 'The %s directory could not be created', 'insert-php' ),
70 '<b>winp-css-js</b>'
71 );
72 ?>
73 </p>
74 <p><?php _e( 'Please run the following commands in order to make the directory', 'insert-php' ); ?>:
75 <br/><strong>mkdir <?php echo $dir; ?>; </strong><br/><strong>chmod 777 <?php echo $dir; ?>
76 ;</strong></p>
77 </div>
78 <?php
79 return;
80 }
81
82 // Show a message if the dir is not writable.
83 if ( ! wp_is_writable( $dir ) ) {
84 ?>
85 <div class="notice notice-error is-dismissible">
86 <p>
87 <?php
88 printf(
89 /* translators: %s: Directory path */
90 esc_html__( 'The %s directory is not writable, therefore the CSS and JS files cannot be saved.', 'insert-php' ),
91 '<b>' . esc_html( $dir ) . '</b>'
92 );
93 ?>
94 </p>
95 <p><?php _e( 'Please run the following command to make the directory writable', 'insert-php' ); ?>:<br/><strong>chmod
96 777 <?php echo $dir; ?> </strong></p>
97 </div>
98 <?php
99 return;
100 }
101
102 // Write a blank index.php.
103 if ( ! file_exists( $dir . '/index.php' ) ) {
104 $content = '<?php' . PHP_EOL . '// Silence is golden.';
105 @file_put_contents( $dir . '/index.php', $content );
106 }
107 }
108
109 /**
110 * Add quick buttons
111 *
112 * @return void
113 */
114 public function current_screen_edit() {
115 $strings = [
116 'php' => __( 'PHP Snippet', 'insert-php' ),
117 'css' => __( 'CSS Snippet', 'insert-php' ),
118 'js' => __( 'JS Snippet', 'insert-php' ),
119 'text' => __( 'Text Snippet', 'insert-php' ),
120 'html' => __( 'HTML Snippet', 'insert-php' ),
121 'advert' => __( 'Advertisement', 'insert-php' ),
122 'universal' => __( 'Universal', 'insert-php' ),
123 ];
124
125 $this->render_snippet_dropdown( $strings, __( 'New Snippet: PHP', 'insert-php' ) );
126 }
127
128 /**
129 * Add quick buttons
130 *
131 * @return void
132 */
133 public function current_screen_post() {
134 global $post;
135 $post_id = null;
136
137 if ( ! empty( $post ) && is_object( $post ) && isset( $post->ID ) ) {
138 $post_id = $post->ID;
139 } else {
140 $post_id = WINP_HTTP::get( 'post', null, 'absint' );
141 }
142
143 $type = WINP_Helper::get_snippet_type( $post_id );
144
145 $strings = [
146 'php' => __( 'PHP Snippet', 'insert-php' ),
147 'css' => __( 'CSS Snippet', 'insert-php' ),
148 'js' => __( 'JS Snippet', 'insert-php' ),
149 'text' => __( 'Text Snippet', 'insert-php' ),
150 'html' => __( 'HTML Snippet', 'insert-php' ),
151 'advert' => __( 'Advertisement', 'insert-php' ),
152 'universal' => __( 'Universal', 'insert-php' ),
153 ];
154
155 $label_map = [
156 'php' => __( 'New Snippet: PHP', 'insert-php' ),
157 'css' => __( 'New Snippet: CSS', 'insert-php' ),
158 'js' => __( 'New Snippet: JS', 'insert-php' ),
159 'text' => __( 'New Snippet: Text', 'insert-php' ),
160 'html' => __( 'New Snippet: HTML', 'insert-php' ),
161 'advert' => __( 'New Snippet: Advertisement', 'insert-php' ),
162 'universal' => __( 'New Snippet: Universal', 'insert-php' ),
163 ];
164
165 $button_label = isset( $label_map[ $type ] ) ? $label_map[ $type ] : __( 'New Snippet: PHP', 'insert-php' );
166
167 $this->render_snippet_dropdown( $strings, $button_label, ! empty( $post_id ) );
168 }
169
170 /**
171 * Render snippet type dropdown
172 *
173 * @param array<string, string> $strings Snippet type labels (type => label).
174 * @param string $button_label Button label text.
175 * @param bool $show_title Whether to show the edit title.
176 *
177 * @return void
178 */
179 private function render_snippet_dropdown( $strings, $button_label, $show_title = false ) {
180 $type_display_labels = [
181 'php' => __( 'PHP', 'insert-php' ),
182 'css' => __( 'CSS', 'insert-php' ),
183 'js' => __( 'JS', 'insert-php' ),
184 'text' => __( 'Text', 'insert-php' ),
185 'html' => __( 'HTML', 'insert-php' ),
186 'advert' => __( 'Advertisement', 'insert-php' ),
187 'universal' => __( 'Universal', 'insert-php' ),
188 ];
189
190 // Get edit title if needed.
191 $edit_title = '';
192 if ( $show_title ) {
193 global $post;
194 $post_id = null;
195
196 if ( ! empty( $post ) && is_object( $post ) && isset( $post->ID ) ) {
197 $post_id = $post->ID;
198 } else {
199 $post_id = WINP_HTTP::get( 'post', null, 'absint' );
200 }
201
202 if ( ! empty( $post_id ) ) {
203 $type = WINP_Helper::get_snippet_type( $post_id );
204 $edit_labels = [
205 'php' => __( 'Edit PHP Snippet', 'insert-php' ),
206 'css' => __( 'Edit CSS Snippet', 'insert-php' ),
207 'js' => __( 'Edit JS Snippet', 'insert-php' ),
208 'text' => __( 'Edit Text Snippet', 'insert-php' ),
209 'html' => __( 'Edit HTML Snippet', 'insert-php' ),
210 'advert' => __( 'Edit Advertisement Snippet', 'insert-php' ),
211 'universal' => __( 'Edit Universal Snippet', 'insert-php' ),
212 ];
213 $edit_title = isset( $edit_labels[ $type ] ) ? $edit_labels[ $type ] : '';
214 }
215 }
216 ?>
217 <style>
218 .winp-dropdown-button {
219 position: relative;
220 display: inline-flex;
221 margin-left: 10px;
222 }
223 .winp-main-button {
224 background: #6366f1;
225 color: #fff;
226 border: none;
227 border-radius: 3px 0 0 3px;
228 padding: 6px 12px;
229 font-size: 13px;
230 font-weight: 500;
231 cursor: pointer;
232 display: inline-flex;
233 align-items: center;
234 gap: 6px;
235 box-shadow: 0 1px 2px rgba(0,0,0,0.05);
236 text-decoration: none;
237 }
238 .winp-main-button:hover {
239 background: #4f46e5;
240 box-shadow: 0 2px 4px rgba(0,0,0,0.1);
241 color: #fff;
242 }
243 .winp-main-button .dashicons {
244 font-size: 16px;
245 width: 16px;
246 height: 16px;
247 }
248 .winp-dropdown-toggle {
249 background: #6366f1;
250 color: #fff;
251 border: none;
252 border-left: 1px solid rgba(255,255,255,0.2);
253 border-radius: 0 3px 3px 0;
254 padding: 6px 8px;
255 font-size: 13px;
256 font-weight: 500;
257 cursor: pointer;
258 display: inline-flex;
259 align-items: center;
260 box-shadow: 0 1px 2px rgba(0,0,0,0.05);
261 }
262 .winp-dropdown-toggle:hover {
263 background: #4f46e5;
264 box-shadow: 0 2px 4px rgba(0,0,0,0.1);
265 }
266 .winp-dropdown-toggle.active {
267 background: #4f46e5 !important;
268 border-color: rgba(255,255,255,0.2) !important;
269 color: #fff !important;
270 box-shadow: 0 2px 4px rgba(0,0,0,0.1) !important;
271 }
272 .winp-dropdown-toggle .dashicons {
273 font-size: 16px;
274 width: 16px;
275 height: 16px;
276 transition: transform 0.3s ease;
277 }
278 .winp-dropdown-toggle.active .dashicons-arrow-down-alt2 {
279 transform: rotate(180deg);
280 }
281 .winp-dropdown-menu {
282 display: block;
283 position: absolute;
284 top: 100%;
285 right: 0;
286 margin-top: 4px;
287 background: #fff;
288 border: 1px solid #ddd;
289 border-radius: 4px;
290 box-shadow: 0 4px 12px rgba(0,0,0,0.15);
291 min-width: 180px;
292 z-index: 99999;
293 opacity: 0;
294 visibility: hidden;
295 transform: translateY(-8px);
296 transition: all 0.2s ease;
297 overflow: hidden;
298 }
299 .winp-dropdown-menu.show {
300 opacity: 1;
301 visibility: visible;
302 transform: translateY(0);
303 }
304 .winp-dropdown-item {
305 display: flex;
306 align-items: center;
307 gap: 8px;
308 padding: 6px 12px;
309 cursor: pointer;
310 text-decoration: none;
311 color: #2c3338;
312 border-bottom: 1px solid #f0f0f1;
313 font-size: 13px;
314 position: relative;
315 }
316 .winp-dropdown-item:first-child {
317 border-top-left-radius: 4px;
318 border-top-right-radius: 4px;
319 }
320 .winp-dropdown-item:last-child {
321 border-bottom: none;
322 border-bottom-left-radius: 4px;
323 border-bottom-right-radius: 4px;
324 }
325 .winp-dropdown-item:hover,
326 .winp-dropdown-item:focus {
327 background: #eef2ff;
328 color: #6366f1;
329 outline: none;
330 }
331 .winp-snippet-icon {
332 width: 26px;
333 height: 26px;
334 border-radius: 3px;
335 display: flex;
336 align-items: center;
337 justify-content: center;
338 font-size: 10px;
339 font-weight: 700;
340 color: #fff;
341 flex-shrink: 0;
342 box-shadow: 0 1px 2px rgba(0,0,0,0.1);
343 }
344 .winp-snippet-icon.php { background: linear-gradient(135deg, #8892BF 0%, #7380b0 100%); }
345 .winp-snippet-icon.css { background: linear-gradient(135deg, #4A90E2 0%, #357abd 100%); }
346 .winp-snippet-icon.js { background: linear-gradient(135deg, #F7C948 0%, #e6b938 100%); color: #333; }
347 .winp-snippet-icon.text { background: linear-gradient(135deg, #7E8C8D 0%, #6d7a7b 100%); }
348 .winp-snippet-icon.html { background: linear-gradient(135deg, #E74C3C 0%, #d63c2d 100%); }
349 .winp-snippet-icon.advert { background: linear-gradient(135deg, #27AE60 0%, #229d56 100%); }
350 .winp-snippet-icon.universal { background: linear-gradient(135deg, #9B59B6 0%, #8a4aa5 100%); }
351
352 /* Keyboard navigation highlight */
353 .winp-dropdown-item.keyboard-focus {
354 background: #eef2ff;
355 color: #6366f1;
356 }
357 </style>
358 <script type="text/javascript">
359 /* <![CDATA[ */
360 jQuery(window).ready(function ($) {
361 $('#wpbody-content a.page-title-action').hide();
362
363 <?php if ( $show_title && ! empty( $edit_title ) ) : ?>
364 // Update the h1 with edit title
365 var currentH1 = $('#wpbody-content h1').text();
366 $('#wpbody-content h1').text('<?php echo esc_js( $edit_title ); ?>');
367 <?php endif; ?>
368
369 // Determine the initial selected type from the button label
370 var snippetTypes = {
371 <?php
372 $first = true;
373 foreach ( $strings as $type => $label ) :
374 if ( ! $first ) {
375 echo ',';
376 }
377 echo "'" . esc_js( $type ) . "': '" . esc_js( $label ) . "'";
378 $first = false;
379 endforeach;
380 ?>
381 };
382
383 var buttonLabel = '<?php echo esc_js( $button_label ); ?>';
384 var selectedType = 'php'; // default
385
386 // Try to determine the selected type from the button label
387 for (var type in snippetTypes) {
388 if (buttonLabel.indexOf(snippetTypes[type]) !== -1) {
389 selectedType = type;
390 break;
391 }
392 }
393
394 // Base URL for creating new snippets
395 var baseUrl = <?php echo wp_json_encode( admin_url( 'post-new.php?post_type=' . WINP_SNIPPETS_POST_TYPE . '&winp_item=' ) ); ?>;
396
397 var dropdownHtml = '<div class="winp-dropdown-button">';
398 dropdownHtml += '<a href="' + baseUrl + selectedType + '" class="winp-main-button" id="winp-main-action">';
399 dropdownHtml += '<span class="dashicons dashicons-plus-alt2"></span>';
400 dropdownHtml += '<span class="winp-button-text"><?php echo esc_js( $button_label ); ?></span>';
401 dropdownHtml += '</a>';
402 dropdownHtml += '<button class="winp-dropdown-toggle" type="button" aria-haspopup="true" aria-expanded="false">';
403 dropdownHtml += '<span class="dashicons dashicons-arrow-down-alt2"></span>';
404 dropdownHtml += '</button>';
405 dropdownHtml += '<div class="winp-dropdown-menu" role="menu">';
406 <?php foreach ( $strings as $type => $label ) : ?>
407 dropdownHtml += '<a href="#" class="winp-dropdown-item" data-type="<?php echo esc_js( $type ); ?>" role="menuitem" tabindex="-1">';
408 dropdownHtml += '<span class="winp-snippet-icon <?php echo esc_js( $type ); ?>"><?php echo esc_js( strtoupper( 'advert' === $type ? 'AD' : ( 'universal' === $type ? 'UNI' : $type ) ) ); ?></span>';
409 dropdownHtml += '<span><?php echo esc_js( $label ); ?></span>';
410 dropdownHtml += '</a>';
411 <?php endforeach; ?>
412 dropdownHtml += '</div>';
413 dropdownHtml += '</div>';
414
415 $('#wpbody-content h1').append(dropdownHtml);
416
417 var $toggle = $('.winp-dropdown-toggle');
418 var $mainButton = $('.winp-main-button');
419 var $buttonText = $('.winp-button-text');
420 var $menu = $('.winp-dropdown-menu');
421 var $items = $('.winp-dropdown-item');
422 var currentFocus = -1;
423 var currentSelectedType = selectedType;
424
425 // Type display labels from PHP
426 var typeLabels = {
427 <?php
428 $first = true;
429 foreach ( $type_display_labels as $type => $display_label ) :
430 if ( ! $first ) {
431 echo ',';
432 }
433 echo "'" . esc_js( $type ) . "': '" . esc_js( $display_label ) . "'";
434 $first = false;
435 endforeach;
436 ?>
437 };
438
439 // Handle dropdown item click
440 $items.on('click', function(e) {
441 e.preventDefault();
442 e.stopPropagation();
443
444 var type = $(this).data('type');
445 currentSelectedType = type;
446
447 // Update button text and href
448 if (typeLabels[type]) {
449 var newLabel = 'New Snippet: ' + typeLabels[type];
450 $buttonText.text(newLabel);
451 $mainButton.attr('href', baseUrl + type);
452 }
453
454 closeDropdown();
455 });
456
457 // Toggle dropdown
458 $toggle.on('click', function(e) {
459 e.stopPropagation();
460 var isOpen = $menu.hasClass('show');
461
462 if (isOpen) {
463 closeDropdown();
464 } else {
465 openDropdown();
466 }
467 });
468
469 function openDropdown() {
470 $menu.addClass('show');
471 $toggle.addClass('active').attr('aria-expanded', 'true');
472 $items.first().focus();
473 currentFocus = 0;
474 }
475
476 function closeDropdown() {
477 $menu.removeClass('show');
478 $toggle.removeClass('active').attr('aria-expanded', 'false');
479 $items.removeClass('keyboard-focus');
480 currentFocus = -1;
481 }
482
483 // Close on outside click
484 $(document).on('click', function(e) {
485 if (!$(e.target).closest('.winp-dropdown-button').length) {
486 closeDropdown();
487 }
488 });
489
490 // Keyboard navigation
491 $(document).on('keydown', function(e) {
492 if (!$menu.hasClass('show')) {
493 return;
494 }
495
496 // ESC key
497 if (e.keyCode === 27) {
498 e.preventDefault();
499 closeDropdown();
500 $toggle.focus();
501 }
502
503 // Arrow Down
504 if (e.keyCode === 40) {
505 e.preventDefault();
506 currentFocus++;
507 if (currentFocus >= $items.length) {
508 currentFocus = 0;
509 }
510 setFocus();
511 }
512
513 // Arrow Up
514 if (e.keyCode === 38) {
515 e.preventDefault();
516 currentFocus--;
517 if (currentFocus < 0) {
518 currentFocus = $items.length - 1;
519 }
520 setFocus();
521 }
522
523 // Enter or Space
524 if (e.keyCode === 13 || e.keyCode === 32) {
525 if (currentFocus > -1) {
526 e.preventDefault();
527 $items.eq(currentFocus).trigger('click');
528 }
529 }
530 });
531
532 function setFocus() {
533 $items.removeClass('keyboard-focus');
534 $items.eq(currentFocus).addClass('keyboard-focus').focus();
535 }
536
537 // Hover updates focus
538 $items.on('mouseenter', function() {
539 currentFocus = $items.index(this);
540 $items.removeClass('keyboard-focus');
541 });
542 });
543 /* ]]> */
544 </script>
545 <?php
546 }
547
548 /**
549 * Add quick buttons
550 *
551 * @param \WP_Screen $current_screen WordPress screen object.
552 *
553 * @return void
554 */
555 public function current_screen( $current_screen ) {
556 if ( WINP_SNIPPETS_POST_TYPE !== $current_screen->post_type ) {
557 return;
558 }
559
560 if ( 'post' === $current_screen->base ) {
561 add_action( 'admin_head', [ $this, 'current_screen_post' ] );
562 }
563
564 if ( 'edit' === $current_screen->base ) {
565 add_action( 'admin_head', [ $this, 'current_screen_edit' ] );
566 }
567 }
568
569 /**
570 * Show the Permalink edit form
571 *
572 * @param string|\WP_Post $filename Filename or post object.
573 * @param string $permalink Permalink URL.
574 * @param string $filetype File type.
575 *
576 * @return void
577 */
578 public function edit_form_before_permalink( $filename = '', $permalink = '', $filetype = 'css' ) {
579 $filetype = WINP_HTTP::get( 'winp_item', $filetype, true );
580
581 if ( ! in_array( $filetype, [ 'css', 'js' ] ) ) {
582 return;
583 }
584
585 if ( ! is_string( $filename ) ) {
586 global $post;
587
588 if ( ! is_object( $post ) ) {
589 return;
590 }
591
592 if ( WINP_SNIPPETS_POST_TYPE !== $post->post_type ) {
593 return;
594 }
595
596 $post = $filename;
597 $slug = WINP_Helper::getMetaOption( $post->ID, 'css_js_slug', '' );
598 $default_filetype = WINP_Helper::getMetaOption( $post->ID, 'filetype', '' );
599 if ( $default_filetype ) {
600 $filetype = $default_filetype;
601 } else {
602 $filetype = WINP_Helper::get_snippet_type( $post->ID );
603 }
604
605 if ( ! in_array( $filetype, [ 'css', 'js' ] ) ) {
606 return;
607 }
608
609 if ( ! @file_exists( WINP_UPLOAD_DIR . '/' . $slug . '.' . $filetype ) ) {
610 $slug = false;
611 }
612 $filename = ( $slug ) ? $slug : $post->ID;
613 }
614
615 if ( empty( $permalink ) ) {
616 $permalink = WINP_UPLOAD_URL . '/' . $filename . '.' . $filetype;
617 }
618 ?>
619 <div class="inside">
620 <div id="edit-slug-box" class="hide-if-no-js">
621 <strong><?php _e( 'Permalink', 'insert-php' ); ?>:</strong>
622 <span id="sample-permalink"><a
623 href="<?php echo esc_url( $permalink ); ?>"><?php echo esc_html( WINP_UPLOAD_URL ) . '/'; ?><span
624 id="editable-post-name"><?php echo esc_html( $filename ); ?></span>.<?php echo esc_html( $filetype ); ?></a></span>
625 <span id="winp-edit-slug-buttons"><button type="button"
626 class="winp-edit-slug button button-small hide-if-no-js"
627 aria-label="<?php _e( 'Edit URL Slug', 'insert-php' ); ?>"><?php _e( 'Edit', 'insert-php' ); ?></button></span>
628 <span id="editable-post-name-full"><?php echo esc_html( $filename ); ?></span>
629 </div>
630 <?php wp_nonce_field( 'winp-permalink', 'winp-permalink-nonce' ); ?>
631 </div>
632 <?php
633 }
634
635 /**
636 * Remove the JS/CSS file from the disk when deleting the post
637 *
638 * @param int $postid Post ID.
639 *
640 * @return void
641 */
642 public function before_delete_post( $postid ) {
643 global $post;
644
645 if ( ! is_object( $post ) ) {
646 return;
647 }
648 if ( WINP_SNIPPETS_POST_TYPE !== $post->post_type ) {
649 return;
650 }
651 if ( ! wp_is_writable( WINP_UPLOAD_DIR ) ) {
652 return;
653 }
654
655 $default_filetype = WINP_Helper::get_snippet_type( $post->ID );
656 $filetype = WINP_Helper::getMetaOption( $postid, 'filetype', $default_filetype );
657
658 if ( ! in_array( $filetype, [ 'css', 'js' ] ) ) {
659 return;
660 }
661
662 $slug = WINP_Helper::getMetaOption( $postid, 'css_js_slug' );
663 $file_name = $postid . '.' . $filetype;
664
665 @unlink( WINP_UPLOAD_DIR . '/' . $file_name );
666
667 if ( ! empty( $slug ) ) {
668 @unlink( WINP_UPLOAD_DIR . '/' . $slug . '.' . $filetype );
669 }
670 }
671
672 /**
673 * Save post
674 *
675 * @param int $post_id Post ID.
676 *
677 * @return void
678 */
679 public function save_post( $post_id ) {
680 $nonce = WINP_HTTP::post( 'winp-permalink-nonce' );
681
682 if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'winp-permalink' ) ) {
683 return;
684 }
685
686 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
687 return;
688 }
689
690 if ( WINP_SNIPPETS_POST_TYPE != WINP_HTTP::post( 'post_type' ) ) {
691 return;
692 }
693
694 $default_filetype = WINP_Helper::get_snippet_type( $post_id );
695 $filetype = WINP_Helper::getMetaOption( $post_id, 'filetype', $default_filetype );
696
697 if ( ! in_array( $filetype, [ 'css', 'js' ] ) ) {
698 return;
699 }
700
701 $plugin_title = __( 'Woody Code Snippets', 'insert-php' );
702 $before = $after = '';
703
704 $snippet_linking = WINP_HTTP::post( 'wbcr_inp_snippet_linking' );
705 $linking = ! empty( $snippet_linking ) ? $snippet_linking : 'external';
706 $content = get_post( $post_id )->post_content;
707
708 // Save the Custom Code in a file in `wp-content/uploads/winp-css-js`.
709 if ( 'inline' == $linking ) {
710 $before = '<!-- start ' . $plugin_title . ' CSS and JS -->' . PHP_EOL;
711 $after = '<!-- end ' . $plugin_title . ' CSS and JS -->' . PHP_EOL;
712
713 if ( 'css' == $filetype ) {
714 $before .= '<style type="text/css">' . PHP_EOL;
715 $after = '</style>' . PHP_EOL . $after;
716 }
717
718 if ( 'js' == $filetype ) {
719 if ( ! preg_match( '/<script\b[^>]*>([\s\S]*?)<\/script>/im', $content ) ) {
720 $before .= '<script type="text/javascript">' . PHP_EOL;
721 $after = PHP_EOL . '</script>' . PHP_EOL . $after;
722 } else {
723 // the content has a <script> tag, then remove the comments so they don't show up on the frontend.
724 $content = preg_replace( '@/\*[\s\S]*?\*/@', '', $content );
725 }
726 }
727 }
728
729 if ( 'external' == $linking ) {
730 $before = '/******* Do not edit this file *******' . PHP_EOL . $plugin_title . ' CSS and JS' . PHP_EOL . 'Saved: ' . date( 'M d Y | H:i:s' ) . ' */' . PHP_EOL;
731
732 // Save version for js and css file.
733 WINP_Helper::updateMetaOption( $post_id, 'css_js_version', time() );
734 }
735
736 if ( wp_is_writable( WINP_UPLOAD_DIR ) ) {
737 $file_content = $before . $content . $after;
738
739 // save the file as the Permalink slug.
740 $slug = WINP_Helper::getMetaOption( $post_id, 'css_js_slug' );
741 if ( $slug ) {
742 $file_name = $slug . '.' . $filetype;
743 $file_slug = $slug;
744 } else {
745 $file_name = $post_id . '.' . $filetype;
746 $file_slug = $post_id;
747 }
748
749 // Delete old file.
750 $old_slug = WINP_Helper::getMetaOption( $post_id, 'css_js_exist_slug' );
751 if ( $old_slug ) {
752 @unlink( WINP_UPLOAD_DIR . '/' . $old_slug . '.' . $filetype );
753 }
754
755 // Save exist file slug.
756 WINP_Helper::updateMetaOption( $post_id, 'css_js_exist_slug', $file_slug );
757
758 @file_put_contents( WINP_UPLOAD_DIR . '/' . $file_name, $file_content );
759 }
760 }
761
762 /**
763 * Action for pre saved snippet.
764 * Если это не обновление поста, если это "черновик", и есть параметр с id сниппета, то заполняем данные сниппета для просмотра
765 *
766 * @param int $post_ID Post ID.
767 * @param \WP_Post $current_post Current post object.
768 * @param bool $update Whether this is an existing post being updated.
769 *
770 * @return void
771 */
772 public function save_snippet( $post_ID, $current_post, $update ) {
773 $snippet_id = WINP_HTTP::get( 'snippet_id' );
774 $common = WINP_HTTP::get( 'common', false );
775
776 if ( ! $update && 'auto-draft' == $current_post->post_status && ! empty( $snippet_id ) && WINP_SNIPPETS_POST_TYPE == $current_post->post_type ) {
777 $snippet = [];
778 $saved_snippets = get_user_meta( get_current_user_id(), 'wbcr_inp_current_snippets', true );
779
780 if ( ! empty( $saved_snippets ) && isset( $saved_snippets[ $snippet_id ] ) ) {
781 $snippet = $saved_snippets[ $snippet_id ];
782 }
783
784 if ( empty( $snippet ) ) {
785 $_snippet = WINP_Plugin::app()->get_api_object()->get_snippet( $snippet_id, $common );
786 if ( ! empty( $_snippet ) ) {
787 $snippet = [
788 'title' => $_snippet->title,
789 'desc' => $_snippet->description,
790 'type' => $_snippet->type->slug,
791 'content' => $_snippet->content,
792 'type_id' => $_snippet->type_id,
793 'scope' => $_snippet->execute_everywhere,
794 'priority' => $_snippet->priority,
795 ];
796 }
797 }
798
799 if ( ! empty( $snippet ) ) {
800 $post_data = [
801 'ID' => $post_ID,
802 'post_title' => $snippet['title'],
803 'post_content' => $snippet['content'],
804 ];
805 wp_update_post( $post_data );
806
807 WINP_Helper::updateMetaOption( $post_ID, 'snippet_api_snippet', $snippet_id );
808 WINP_Helper::updateMetaOption( $post_ID, 'snippet_type', $snippet['type'] );
809 WINP_Helper::updateMetaOption( $post_ID, 'snippet_api_type', $snippet['type_id'] );
810 WINP_Helper::updateMetaOption( $post_ID, 'snippet_description', $snippet['desc'] );
811 WINP_Helper::updateMetaOption( $post_ID, 'snippet_draft', true );
812 WINP_Helper::updateMetaOption( $post_ID, 'snippet_scope', $snippet['scope'] );
813
814 if ( isset( $snippet['priority'] ) ) {
815 WINP_Helper::updateMetaOption( $post_ID, 'snippet_priority', $snippet['priority'] );
816 }
817
818 wp_safe_redirect( admin_url( 'post.php?post=' . $post_ID . '&action=edit' ) );
819 }
820 }
821 }
822
823 /**
824 * Delete auto-draft status after post snippet is publishing
825 *
826 * @param \WP_Post $post Post object.
827 *
828 * @return void
829 */
830 public function publish_snippet( $post ) {
831 if ( WINP_SNIPPETS_POST_TYPE == $post->post_type ) {
832 delete_post_meta( $post->ID, 'wbcr_inp_snippet_draft' );
833 }
834 }
835
836 /**
837 * Action admin_footer
838 *
839 * @return void
840 */
841 public function admin_footer() {
842 ?>
843 <script type="text/javascript">!function (e, t, n) {
844 function a() {
845 var e = t.getElementsByTagName("script")[0], n = t.createElement("script");
846 n.type = "text/javascript", n.async = !0, n.src = "https://beacon-v2.helpscout.net", e.parentNode.insertBefore(n, e)
847 }
848
849 if (e.Beacon = n = function (t, n, a) {
850 e.Beacon.readyQueue.push({
851 method: t,
852 options: n,
853 data: a
854 })
855 }, n.readyQueue = [], "complete" === t.readyState) {
856 return a();
857 }
858 e.attachEvent ? e.attachEvent("onload", a) : e.addEventListener("load", a, !1)
859 }(window, document, window.Beacon || function () {
860 });</script>
861 <script type="text/javascript">window.Beacon('init', '1a4078fd-3e77-4692-bcfa-47bb4da0cee5')</script>
862 <?php
863 }
864
865 /**
866 * Unload specific scripts
867 *
868 * @param string $src Script source URL.
869 * @param string $handle Script handle.
870 *
871 * @return bool|string False to prevent loading, otherwise the script source URL.
872 */
873 public function unload_scripts( $src, $handle ) {
874 global $post;
875
876 // Check if we are editing a snippet post.
877 if ( is_admin() && ! empty( $post ) && $post->post_type == WINP_SNIPPETS_POST_TYPE ) {
878 // Unload ckeditor.js from theme The Rex.
879 if ( 'bk-ckeditor-js' == $handle ) {
880 return false;
881 }
882 }
883
884 return $src;
885 }
886 }
887