PluginProbe
Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts / trunk
Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts vtrunk
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
← All changes | admin/includes/class.common.snippet.php +886 -530 2.4.7trunk View file →
@@ -1,530 +1,886 @@
1 -<?php
2 -/**
3 - * Common functions for snippets
4 - *
5 - * @author Webcraftic <wordpress.webraftic@gmail.com>
6 - * @copyright (c) 16.11.2018, Webcraftic
7 - * @version 1.0
8 - */
9 -
10 -// Exit if accessed directly
11 -if ( ! defined( 'ABSPATH' ) ) {
12 - exit;
13 -}
14 -
15 -class WINP_Common_Snippet {
16 -
17 - /**
18 - * WINP_Common_Snippet constructor.
19 - */
20 - public function __construct() {
21 - }
22 -
23 - /**
24 - * Register hooks
25 - */
26 - public function registerHooks() {
27 - add_action( 'current_screen', [ $this, 'currentScreen' ] );
28 - add_action( 'edit_form_before_permalink', [ $this, 'editFormBeforePermalink' ] );
29 - add_action( 'admin_notices', [ $this, 'createUploadsDirectory' ] );
30 - add_action( 'before_delete_post', [ $this, 'beforeDeletePost' ] );
31 - add_action( 'save_post', [ $this, 'savePost' ] );
32 - add_action( 'save_post_' . WINP_SNIPPETS_POST_TYPE, [ $this, 'save_snippet' ], 10, 3 );
33 - add_action( 'auto-draft_to_publish', [ $this, 'publish_snippet' ] );
34 -
35 - add_filter( 'script_loader_src', [ $this, 'unload_scripts' ], 10, 2 );
36 - }
37 -
38 - /**
39 - * Create the custom-css-js dir in uploads directory
40 - *
41 - * Show a message if the directory is not writable
42 - *
43 - * Create an empty index.php file inside
44 - */
45 - public function createUploadsDirectory() {
46 - $current_screen = get_current_screen();
47 -
48 - // Check if we are editing a custom-css-js post
49 - if ( $current_screen->base != 'post' || $current_screen->post_type != WINP_SNIPPETS_POST_TYPE ) {
50 - return false;
51 - }
52 -
53 - $dir = WINP_UPLOAD_DIR;
54 -
55 - // Create the dir if it doesn't exist
56 - if ( ! file_exists( $dir ) ) {
57 - wp_mkdir_p( $dir );
58 - }
59 -
60 - // Show a message if it couldn't create the dir
61 - if ( ! file_exists( $dir ) ) { ?>
62 - <div class="notice notice-error is-dismissible">
63 - <p><?php printf( __( 'The %s directory could not be created', 'insert-php' ), '<b>winp-css-js</b>' ); ?></p>
64 - <p><?php _e( 'Please run the following commands in order to make the directory', 'insert-php' ); ?>:
65 - <br/><strong>mkdir <?php echo $dir; ?>; </strong><br/><strong>chmod 777 <?php echo $dir; ?>
66 - ;</strong></p>
67 - </div>
68 - <?php return;
69 - }
70 -
71 - // Show a message if the dir is not writable
72 - if ( ! wp_is_writable( $dir ) ) { ?>
73 - <div class="notice notice-error is-dismissible">
74 - <p><?php printf( __( 'The %s directory is not writable, therefore the CSS and JS files cannot be saved.', 'insert-php' ), '<b>' . $dir . '</b>' ); ?></p>
75 - <p><?php _e( 'Please run the following command to make the directory writable', 'insert-php' ); ?>:<br/><strong>chmod
76 - 777 <?php echo $dir; ?> </strong></p>
77 - </div>
78 - <?php return;
79 - }
80 -
81 - // Write a blank index.php
82 - if ( ! file_exists( $dir . '/index.php' ) ) {
83 - $content = '<?php' . PHP_EOL . '// Silence is golden.';
84 - @file_put_contents( $dir . '/index.php', $content );
85 - }
86 - }
87 -
88 - /**
89 - * Add quick buttons
90 - */
91 - public function currentScreenEdit() {
92 - $strings = [
93 - 'php' => __( 'Php snippet', 'insert-php' ),
94 - 'text' => __( 'Text snippet', 'insert-php' ),
95 - 'css' => __( 'Css snippet', 'insert-php' ),
96 - 'js' => __( 'Js snippet', 'insert-php' ),
97 - 'html' => __( 'Html snippet', 'insert-php' ),
98 - 'universal' => __( 'Universal snippet', 'insert-php' ),
99 - 'advert' => __( 'Advertisement snippet', 'insert-php' ),
100 - ];
101 - $url = 'post-new.php?post_type=' . WINP_SNIPPETS_POST_TYPE . '&winp_item=';
102 - ?>
103 - <style>
104 - .wrap .winp-page-title-action {
105 - margin-left: 4px;
106 - padding: 4px 8px;
107 - position: relative;
108 - top: -3px;
109 - text-decoration: none;
110 - border: 1px solid #ccc;
111 - border-radius: 2px;
112 - background: #f7f7f7;
113 - text-shadow: none;
114 - font-weight: 600;
115 - font-size: 13px;
116 - line-height: normal;
117 - color: #0073aa;
118 - cursor: pointer;
119 - }
120 - </style>
121 - <script type="text/javascript">
122 - /* <![CDATA[ */
123 - jQuery(window).ready(function ($) {
124 - $('#wpbody-content a.page-title-action').hide();
125 - var h1 = '<?php _e( 'Woody snippets', 'insert-php' ); ?> ';
126 - h1 += ' <select class="winp-page-title-action">';
127 - h1 += '<option value="<?php echo $url; ?>php"><?php echo $strings['php']; ?></option>';
128 - h1 += '<option value="<?php echo $url; ?>text"><?php echo $strings['text']; ?></option>';
129 - h1 += '<option value="<?php echo $url; ?>css"><?php echo $strings['css']; ?></option>';
130 - h1 += '<option value="<?php echo $url; ?>js"><?php echo $strings['js']; ?></option>';
131 - h1 += '<option value="<?php echo $url; ?>html"><?php echo $strings['html']; ?></option>';
132 - h1 += '<option value="<?php echo $url; ?>universal"><?php echo $strings['universal']; ?></option>';
133 - h1 += '<option value="<?php echo $url; ?>advert"><?php echo $strings['advert']; ?></option>';
134 - h1 += '</select>';
135 - h1 += '<a href="#" id="winp-add-snippet-action" class="page-title-action"><?php _e( 'Add', 'insert-php' ); ?></a>';
136 - $('#wpbody-content h1').html(h1);
137 - $('#winp-add-snippet-action').click(function () {
138 - window.location.href = $('select.winp-page-title-action').val();
139 - });
140 - });
141 - </script>
142 - <?php
143 - }
144 -
145 - /**
146 - * Add quick buttons
147 - */
148 - public function currentScreenPost() {
149 - $strings = [
150 - 'add' => [
151 - 'php' => __( 'Php snippet', 'insert-php' ),
152 - 'text' => __( 'Text snippet', 'insert-php' ),
153 - 'css' => __( 'Css snippet', 'insert-php' ),
154 - 'js' => __( 'Js snippet', 'insert-php' ),
155 - 'html' => __( 'Html snippet', 'insert-php' ),
156 - 'universal' => __( 'Universal snippet', 'insert-php' ),
157 - 'advert' => __( 'Advertisement snippet', 'insert-php' ),
158 - ],
159 - 'edit' => [
160 - 'php' => __( 'Edit php snippet', 'insert-php' ),
161 - 'text' => __( 'Edit text snippet', 'insert-php' ),
162 - 'css' => __( 'Edit css snippet', 'insert-php' ),
163 - 'js' => __( 'Edit js snippet', 'insert-php' ),
164 - 'html' => __( 'Edit html snippet', 'insert-php' ),
165 - 'universal' => __( 'Edit universal snippet', 'insert-php' ),
166 - 'advert' => __( 'Edit advertisement snippet', 'insert-php' ),
167 - ]
168 - ];
169 -
170 - $post_id = WINP_Plugin::app()->request->get( 'post', null );
171 - if ( ! empty( $post_id ) ) {
172 - $action = 'edit';
173 - } else {
174 - $action = 'add';
175 - }
176 - $type = WINP_Helper::get_snippet_type( $post_id );
177 - $html = $strings[ $action ][ $type ];
178 -
179 - if ( 'edit' == $action ) {
180 - $url = 'post-new.php?post_type=' . WINP_SNIPPETS_POST_TYPE . '&winp_item=';
181 - $html .= ' <select class="winp-page-title-action">';
182 - $html .= '<option value="' . $url . 'php">' . $strings['add']['php'] . '</option>';
183 - $html .= '<option value="' . $url . 'text">' . $strings['add']['text'] . '</option>';
184 - $html .= '<option value="' . $url . 'css">' . $strings['add']['css'] . '</option>';
185 - $html .= '<option value="' . $url . 'js">' . $strings['add']['js'] . '</option>';
186 - $html .= '<option value="' . $url . 'html">' . $strings['add']['html'] . '</option>';
187 - $html .= '<option value="' . $url . 'universal">' . $strings['add']['universal'] . '</option>';
188 - $html .= '<option value="' . $url . 'advert">' . $strings['add']['advert'] . '</option>';
189 - $html .= '</select>';
190 - $html .= '<a href="#" id="winp-add-snippet-action" class="page-title-action">' . __( 'Add', 'insert-php' ) . '</a>';
191 - } ?>
192 - <script type="text/javascript">
193 - /* <![CDATA[ */
194 - jQuery(window).ready(function ($) {
195 - $('#wpbody-content a.page-title-action').hide();
196 - $('#wpbody-content h1').html('<?php echo $html; ?>');
197 - $('#winp-add-snippet-action').click(function () {
198 - window.location.href = $('select.winp-page-title-action').val();
199 - });
200 - });
201 - /* ]]> */
202 - </script>
203 - <?php
204 - }
205 -
206 - /**
207 - * Add quick buttons
208 - *
209 - * @param $current_screen
210 - */
211 - public function currentScreen( $current_screen ) {
212 - if ( WINP_SNIPPETS_POST_TYPE !== $current_screen->post_type ) {
213 - return;
214 - }
215 -
216 - // Код виджета поддержки пока что нужно скрыть
217 - // add_action( 'admin_footer', array( $this, 'admin_footer' ) );
218 -
219 - if ( $current_screen->base == 'post' ) {
220 - add_action( 'admin_head', [ $this, 'currentScreenPost' ] );
221 - }
222 -
223 - if ( $current_screen->base == 'edit' ) {
224 - add_action( 'admin_head', [ $this, 'currentScreenEdit' ] );
225 - }
226 - }
227 -
228 - /**
229 - * Show the Permalink edit form
230 - *
231 - * @param string $filename
232 - * @param string $permalink
233 - * @param string $filetype
234 - */
235 - public function editFormBeforePermalink( $filename = '', $permalink = '', $filetype = 'css' ) {
236 - $filetype = WINP_Plugin::app()->request->get( 'winp_item', $filetype, true );
237 -
238 - if ( ! in_array( $filetype, [ 'css', 'js' ] ) ) {
239 - return;
240 - }
241 -
242 - if ( ! is_string( $filename ) ) {
243 - global $post;
244 -
245 - if ( ! is_object( $post ) ) {
246 - return;
247 - }
248 -
249 - if ( WINP_SNIPPETS_POST_TYPE !== $post->post_type ) {
250 - return;
251 - }
252 -
253 - $post = $filename;
254 - $slug = WINP_Helper::getMetaOption( $post->ID, 'css_js_slug', '' );
255 - $default_filetype = WINP_Helper::getMetaOption( $post->ID, 'filetype', '' );
256 - if ( $default_filetype ) {
257 - $filetype = $default_filetype;
258 - } else {
259 - $filetype = WINP_Helper::get_snippet_type( $post->ID );
260 - }
261 -
262 - if ( ! in_array( $filetype, [ 'css', 'js' ] ) ) {
263 - return;
264 - }
265 -
266 - if ( ! @file_exists( WINP_UPLOAD_DIR . '/' . $slug . '.' . $filetype ) ) {
267 - $slug = false;
268 - }
269 - $filename = ( $slug ) ? $slug : $post->ID;
270 - }
271 -
272 - if ( empty( $permalink ) ) {
273 - $permalink = WINP_UPLOAD_URL . '/' . $filename . '.' . $filetype;
274 - } ?>
275 - <div class="inside">
276 - <div id="edit-slug-box" class="hide-if-no-js">
277 - <strong><?php _e( 'Permalink', 'insert-php' ) ?>:</strong>
278 - <span id="sample-permalink"><a
279 - href="<?php echo esc_url( $permalink ); ?>"><?php echo esc_html( WINP_UPLOAD_URL ) . '/'; ?><span
280 - id="editable-post-name"><?php echo esc_html( $filename ); ?></span>.<?php echo esc_html( $filetype ); ?></a></span>
281 - <span id="winp-edit-slug-buttons"><button type="button"
282 - class="winp-edit-slug button button-small hide-if-no-js"
283 - aria-label="<?php _e( 'Edit permalink', 'insert-php' ) ?>"><?php _e( 'Edit', 'insert-php' ) ?></button></span>
284 - <span id="editable-post-name-full"><?php echo esc_html( $filename ); ?></span>
285 - </div>
286 - <?php wp_nonce_field( 'winp-permalink', 'winp-permalink-nonce' ); ?>
287 - </div>
288 - <?php
289 - }
290 -
291 - /**
292 - * Remove the JS/CSS file from the disk when deleting the post
293 - *
294 - * @param $postid
295 - */
296 - public function beforeDeletePost( $postid ) {
297 - global $post;
298 -
299 - if ( ! is_object( $post ) ) {
300 - return;
301 - }
302 - if ( WINP_SNIPPETS_POST_TYPE !== $post->post_type ) {
303 - return;
304 - }
305 - if ( ! wp_is_writable( WINP_UPLOAD_DIR ) ) {
306 - return;
307 - }
308 -
309 - $default_filetype = WINP_Helper::get_snippet_type( $post->ID );
310 - $filetype = WINP_Helper::getMetaOption( $postid, 'filetype', $default_filetype );
311 -
312 - if ( ! in_array( $filetype, [ 'css', 'js' ] ) ) {
313 - return;
314 - }
315 -
316 - $slug = WINP_Helper::getMetaOption( $postid, 'css_js_slug' );
317 - $file_name = $postid . '.' . $filetype;
318 -
319 - @unlink( WINP_UPLOAD_DIR . '/' . $file_name );
320 -
321 - if ( ! empty( $slug ) ) {
322 - @unlink( WINP_UPLOAD_DIR . '/' . $slug . '.' . $filetype );
323 - }
324 - }
325 -
326 - /**
327 - * Save post
328 - *
329 - * @param $post_id
330 - */
331 - public function savePost( $post_id ) {
332 - $nonce = WINP_Plugin::app()->request->post( 'winp-permalink-nonce' );
333 -
334 - if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'winp-permalink' ) ) {
335 - return;
336 - }
337 -
338 - if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
339 - return;
340 - }
341 -
342 - if ( WINP_SNIPPETS_POST_TYPE != WINP_Plugin::app()->request->post( 'post_type' ) ) {
343 - return;
344 - }
345 -
346 - $default_filetype = WINP_Helper::get_snippet_type( $post_id );
347 - $filetype = WINP_Helper::getMetaOption( $post_id, 'filetype', $default_filetype );
348 -
349 - if ( ! in_array( $filetype, [ 'css', 'js' ] ) ) {
350 - return;
351 - }
352 -
353 - $plugin_title = WINP_Plugin::app()->getPluginTitle();
354 - $before = $after = '';
355 -
356 - $snippet_linking = WINP_Plugin::app()->request->post( WINP_Plugin::app()->getPrefix() . 'snippet_linking' );
357 - $linking = ! empty( $snippet_linking ) ? $snippet_linking : 'external';
358 - $content = get_post( $post_id )->post_content;
359 -
360 - // Save the Custom Code in a file in `wp-content/uploads/winp-css-js`
361 - if ( 'inline' == $linking ) {
362 - $before = '<!-- start ' . $plugin_title . ' CSS and JS -->' . PHP_EOL;
363 - $after = '<!-- end ' . $plugin_title . ' CSS and JS -->' . PHP_EOL;
364 -
365 - if ( 'css' == $filetype ) {
366 - $before .= '<style type="text/css">' . PHP_EOL;
367 - $after = '</style>' . PHP_EOL . $after;
368 - }
369 -
370 - if ( 'js' == $filetype ) {
371 - if ( ! preg_match( '/<script\b[^>]*>([\s\S]*?)<\/script>/im', $content ) ) {
372 - $before .= '<script type="text/javascript">' . PHP_EOL;
373 - $after = PHP_EOL . '</script>' . PHP_EOL . $after;
374 - } else {
375 - // the content has a <script> tag, then remove the comments so they don't show up on the frontend
376 - $content = preg_replace( '@/\*[\s\S]*?\*/@', '', $content );
377 - }
378 - }
379 - }
380 -
381 - if ( 'external' == $linking ) {
382 - $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;
383 -
384 - // Save version for js and css file
385 - WINP_Helper::updateMetaOption( $post_id, 'css_js_version', time() );
386 - }
387 -
388 - if ( wp_is_writable( WINP_UPLOAD_DIR ) ) {
389 - $file_content = $before . $content . $after;
390 -
391 - // save the file as the Permalink slug
392 - $slug = WINP_Helper::getMetaOption( $post_id, 'css_js_slug' );
393 - if ( $slug ) {
394 - $file_name = $slug . '.' . $filetype;
395 - $file_slug = $slug;
396 - } else {
397 - $file_name = $post_id . '.' . $filetype;
398 - $file_slug = $post_id;
399 - }
400 -
401 - // Delete old file
402 - $old_slug = WINP_Helper::getMetaOption( $post_id, 'css_js_exist_slug' );
403 - if ( $old_slug ) {
404 - @unlink( WINP_UPLOAD_DIR . '/' . $old_slug . '.' . $filetype );
405 - }
406 -
407 - // Save exist file slug
408 - WINP_Helper::updateMetaOption( $post_id, 'css_js_exist_slug', $file_slug );
409 -
410 - @file_put_contents( WINP_UPLOAD_DIR . '/' . $file_name, $file_content );
411 - }
412 - }
413 -
414 - /**
415 - * Action for pre saved snippet.
416 - * Если это не обновление поста, если это "черновик", и есть параметр с id сниппета, то заполняем данные сниппета для просмотра
417 - *
418 - * @param $post_ID
419 - * @param $current_post
420 - * @param $update
421 - */
422 - public function save_snippet( $post_ID, $current_post, $update ) {
423 - $snippet_id = WINP_Plugin::app()->request->get( 'snippet_id' );
424 - $common = WINP_Plugin::app()->request->get( 'common', false );
425 -
426 - if ( ! $update && 'auto-draft' == $current_post->post_status && ! empty( $snippet_id ) && WINP_SNIPPETS_POST_TYPE == $current_post->post_type ) {
427 - $snippet = [];
428 - $saved_snippets = get_user_meta( get_current_user_id(), WINP_Plugin::app()->getPrefix() . 'current_snippets', true );
429 -
430 - if ( ! empty( $saved_snippets ) && isset( $saved_snippets[ $snippet_id ] ) ) {
431 - $snippet = $saved_snippets[ $snippet_id ];
432 - }
433 -
434 - if ( empty( $snippet ) ) {
435 - $_snippet = WINP_Plugin::app()->get_api_object()->get_snippet( $snippet_id, $common );
436 - if ( ! empty( $_snippet ) ) {
437 - $snippet = [
438 - 'title' => $_snippet->title,
439 - 'desc' => $_snippet->description,
440 - 'type' => $_snippet->type->slug,
441 - 'content' => $_snippet->content,
442 - 'type_id' => $_snippet->type_id,
443 - 'scope' => $_snippet->execute_everywhere,
444 - 'priority' => $_snippet->priority,
445 - ];
446 - }
447 - }
448 -
449 - if ( ! empty( $snippet ) ) {
450 - $post_data = [
451 - 'ID' => $post_ID,
452 - 'post_title' => $snippet['title'],
453 - 'post_content' => $snippet['content'],
454 - ];
455 - wp_update_post( $post_data );
456 -
457 - WINP_Helper::updateMetaOption( $post_ID, 'snippet_api_snippet', $snippet_id );
458 - WINP_Helper::updateMetaOption( $post_ID, 'snippet_type', $snippet['type'] );
459 - WINP_Helper::updateMetaOption( $post_ID, 'snippet_api_type', $snippet['type_id'] );
460 - WINP_Helper::updateMetaOption( $post_ID, 'snippet_description', $snippet['desc'] );
461 - WINP_Helper::updateMetaOption( $post_ID, 'snippet_draft', true );
462 - WINP_Helper::updateMetaOption( $post_ID, 'snippet_scope', $snippet['scope'] );
463 - WINP_Helper::updateMetaOption( $post_ID, 'snippet_priority', $snippet['priority'] );
464 -
465 - wp_safe_redirect( admin_url( 'post.php?post=' . $post_ID . '&action=edit' ) );
466 - }
467 - }
468 - }
469 -
470 - /**
471 - * Delete auto-draft status after post snippet is publishing
472 - *
473 - * @param $post
474 - */
475 - public function publish_snippet( $post ) {
476 - if ( WINP_SNIPPETS_POST_TYPE == $post->post_type ) {
477 - delete_post_meta( $post->ID, WINP_Plugin::app()->getPrefix() . 'snippet_draft' );
478 - }
479 - }
480 -
481 - /**
482 - * Action admin_footer
483 - */
484 - public function admin_footer() {
485 - ?>
486 - <script type="text/javascript">!function (e, t, n) {
487 - function a() {
488 - var e = t.getElementsByTagName("script")[0], n = t.createElement("script");
489 - n.type = "text/javascript", n.async = !0, n.src = "https://beacon-v2.helpscout.net", e.parentNode.insertBefore(n, e)
490 - }
491 -
492 - if (e.Beacon = n = function (t, n, a) {
493 - e.Beacon.readyQueue.push({
494 - method: t,
495 - options: n,
496 - data: a
497 - })
498 - }, n.readyQueue = [], "complete" === t.readyState) {
499 - return a();
500 - }
501 - e.attachEvent ? e.attachEvent("onload", a) : e.addEventListener("load", a, !1)
502 - }(window, document, window.Beacon || function () {
503 - });</script>
504 - <script type="text/javascript">window.Beacon('init', '1a4078fd-3e77-4692-bcfa-47bb4da0cee5')</script>
505 - <?php
506 - }
507 -
508 - /**
509 - * Unload specific scrips
510 - *
511 - * @param string $src
512 - * @param string $handle
513 - *
514 - * @return bool|string
515 - */
516 - public function unload_scripts( $src, $handle ) {
517 - global $post;
518 -
519 - // Check if we are editing a snippet post
520 - if ( is_admin() && ! empty( $post ) && $post->post_type == WINP_SNIPPETS_POST_TYPE ) {
521 - // Unload ckeditor.js from theme The Rex
522 - if ( 'bk-ckeditor-js' == $handle ) {
523 - return false;
524 - }
525 - }
526 -
527 - return $src;
528 - }
529 -
530 -}
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 +}