PluginProbe
Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts / 2.3.1
Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts v2.3.1
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 / metaboxes / base-options.php

base-options.php in Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts 2.3.1, at admin/metaboxes/base-options.php

935 lines 33.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // Exit if accessed directly
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit;
6 }
7
8 class WINP_BaseOptionsMetaBox extends Wbcr_FactoryMetaboxes409_FormMetabox {
9
10 /**
11 * A visible title of the metabox.
12 *
13 * Inherited from the class FactoryMetabox.
14 *
15 * @link http://codex.wordpress.org/Function_Reference/add_meta_box
16 *
17 * @since 1.0.0
18 * @var string
19 */
20 public $title;
21
22 /**
23 * The priority within the context where the boxes should show ('high', 'core', 'default' or 'low').
24 *
25 * @link http://codex.wordpress.org/Function_Reference/add_meta_box
26 * Inherited from the class FactoryMetabox.
27 *
28 * @since 1.0.0
29 * @var string
30 */
31 public $priority = 'core';
32
33 public $css_class = 'factory-bootstrap-423 factory-fontawesome-000';
34
35 protected $errors = [];
36 protected $source_channel;
37 protected $facebook_group_id;
38 protected $paginate_url;
39
40 public function __construct( $plugin ) {
41 parent::__construct( $plugin );
42
43 $this->title = __( 'Base options', 'insert-php' );
44
45 add_action( 'admin_head', [ $this, 'removeMediaButton' ] );
46 add_action( 'admin_footer', [ $this, 'adminFooter' ] );
47 add_action( 'admin_enqueue_scripts', [ $this, 'deregisterDefaultEditorResourses' ] );
48
49 $snippet_type = WINP_Helper::get_snippet_type();
50
51 if ( $snippet_type !== WINP_SNIPPET_TYPE_TEXT ) {
52 add_action( 'admin_footer-post.php', [ $this, 'printCodeEditorScripts' ], 99 );
53 add_action( 'admin_footer-post-new.php', [ $this, 'printCodeEditorScripts' ], 99 );
54 add_action( 'edit_form_after_editor', [ $this, 'php_editor_markup' ], 10, 1 );
55 }
56
57 add_action( 'admin_body_class', [ $this, 'admin_body_class' ] );
58 add_action( 'edit_form_top', [ $this, 'editFormTop' ] );
59 add_action( 'post_submitbox_misc_actions', [ $this, 'post_submitbox_misc_actions' ] );
60 add_action( 'edit_form_after_title', [ $this, 'keep_html_entities' ] );
61
62 add_filter( 'pre_post_content', [ $this, 'stop_post_filters' ] );
63 add_filter( 'content_save_pre', [ $this, 'init_post_filters' ], 9999 );
64 }
65
66 /**
67 * Configures a metabox.
68 *
69 * @since 1.0.0
70 *
71 * @param Wbcr_Factory422_StyleList $styles A set of style to include.
72 *
73 * @param Wbcr_Factory422_ScriptList $scripts A set of scripts to include.
74 *
75 * @return void
76 */
77 public function configure( $scripts, $styles ) {
78 //method must be overriden in the derived classed.
79 $styles->add( WINP_PLUGIN_URL . '/admin/assets/dist/css/ccm.min.css' );
80 $styles->add( WINP_PLUGIN_URL . '/admin/assets/css/code-editor-style.css' );
81
82 $code_editor_theme = $this->plugin->getPopulateOption( 'code_editor_theme' );
83
84 if ( ! empty( $code_editor_theme ) && $code_editor_theme != 'default' ) {
85 $this->styles->add( WINP_PLUGIN_URL . '/admin/assets/css/cmthemes/' . $code_editor_theme . '.css' );
86 }
87
88 $scripts->add( WINP_PLUGIN_URL . '/admin/assets/dist/js/ccm.min.js', [ 'jquery' ], 'winp-snippet-codemirror' );
89 $scripts->add( WINP_PLUGIN_URL . '/admin/assets/js/transition.js', [ 'jquery' ], 'winp-snippet-transition' );
90
91 if ( WINP_Plugin::app()->get_api_object()->is_key() ) {
92 wp_localize_script( 'jquery', 'winp_snippet_sync', [
93 'import' => __( 'Import snippet', 'insert-php' ),
94 'export' => __( 'Export snippet', 'insert-php' ),
95 'import_failed' => __( 'An error occurred during import', 'insert-php' ),
96 'export_failed' => __( 'An error occurred during export', 'insert-php' ),
97 'save' => __( 'Save', 'insert-php' ),
98 'saved' => __( 'Snippet template succefully saved!', 'insert-php' ),
99 'src_loader' => WINP_PLUGIN_URL . '/admin/assets/img/ajax-loader.gif',
100 ] );
101 }
102 }
103
104 /**
105 * Disable post filtering. Snippets code cannot be filtered, otherwise it will cause errors.
106 *
107 * @author Alexander Kovalev <alex.kovalevv@gmail.com>
108 * @since 2.2.3
109 *
110 * @param $value
111 *
112 * @return mixed
113 */
114 public function stop_post_filters( $value ) {
115 global $wbcr__has_kses, $wbcr__has_targeted_link_rel_filters;
116
117 $screen = get_current_screen();
118 if ( empty( $screen ) || $screen->post_type !== WINP_SNIPPETS_POST_TYPE ) {
119 return $value;
120 }
121
122 $snippet_type = WINP_Helper::get_snippet_type();
123
124 if ( $snippet_type !== WINP_SNIPPET_TYPE_TEXT ) {
125 // Prevent content filters from corrupting JSON in post_content.
126 $wbcr__has_kses = ( false !== has_filter( 'content_save_pre', 'wp_filter_post_kses' ) );
127 if ( $wbcr__has_kses ) {
128 kses_remove_filters();
129 }
130 $wbcr__has_targeted_link_rel_filters = ( false !== has_filter( 'content_save_pre', 'wp_targeted_link_rel' ) );
131 if ( $wbcr__has_targeted_link_rel_filters ) {
132 wp_remove_targeted_link_rel_filters();
133 }
134 }
135
136 return $value;
137 }
138
139 /**
140 * Enable post filtering.
141 *
142 * @author Alexander Kovalev <alex.kovalevv@gmail.com>
143 * @since 2.2.3
144 *
145 * @param $value
146 *
147 * @return mixed
148 */
149 public function init_post_filters( $value ) {
150 global $wbcr__has_kses, $wbcr__has_targeted_link_rel_filters;
151
152 $screen = get_current_screen();
153 if ( empty( $screen ) || $screen->post_type !== WINP_SNIPPETS_POST_TYPE ) {
154 return $value;
155 }
156
157 if ( $wbcr__has_kses ) {
158 kses_init_filters();
159 }
160
161 if ( $wbcr__has_targeted_link_rel_filters ) {
162 wp_init_targeted_link_rel_filters();
163 }
164
165 unset( $wbcr__has_kses );
166 unset( $wbcr__has_targeted_link_rel_filters );
167
168 return $value;
169 }
170
171 /**
172 * Add the codemirror editor in the `post` screen
173 *
174 * @author Alexander Kovalev <alex.kovalevv@gmail.com>
175 * @since 2.2.1
176 */
177 public function keep_html_entities( $post ) {
178 $current_screen = get_current_screen();
179
180 if ( empty( $post ) || ( $current_screen->post_type != WINP_SNIPPETS_POST_TYPE ) ) {
181 return false;
182 }
183
184 if ( WINP_Plugin::app()->getOption( 'keep_html_entities' ) && strstr( $post->post_content, '&' ) ) {
185
186 // First the ampresands
187 $post->post_content = str_replace( '&amp', htmlentities( '&amp' ), $post->post_content );
188
189 // Then the rest of the entities
190 $html_flags = defined( 'ENT_HTML5' ) ? ENT_QUOTES | ENT_HTML5 : ENT_QUOTES;
191 $entities = get_html_translation_table( HTML_ENTITIES, $html_flags );
192
193 unset( $entities[ array_search( '&amp;', $entities ) ] );
194
195 $regular_expression = str_replace( ';', '', '/(' . implode( '|', $entities ) . ')/i' );
196
197 preg_match_all( $regular_expression, $post->post_content, $matches );
198
199 if ( isset( $matches[0] ) && count( $matches[0] ) > 0 ) {
200 foreach ( $matches[0] as $_entity ) {
201 $post->post_content = str_replace( $_entity, htmlentities( $_entity ), $post->post_content );
202 }
203 }
204 }
205 }
206
207 /**
208 * Remove media button
209 */
210 public function removeMediaButton() {
211 global $post;
212
213 if ( empty( $post ) || $post->post_type !== WINP_SNIPPETS_POST_TYPE ) {
214 return;
215 }
216 remove_action( 'media_buttons', 'media_buttons' );
217 }
218
219 /**
220 * Add html to admin footer
221 */
222 public function adminFooter() {
223 global $pagenow;
224
225 $screen = get_current_screen();
226
227 if ( ( 'post-new.php' == $pagenow || 'post.php' == $pagenow ) && WINP_SNIPPETS_POST_TYPE == $screen->post_type ) {
228 $snippet_id = get_the_ID();
229 $is_key = WINP_Plugin::app()->get_api_object()->is_key();
230 $premium_text = $is_key ? '' : ' [Premium]';
231 $button_nonce = ' data-nonce="' . wp_create_nonce( "wbcr_inp_save_snippet_{$snippet_id}_as_template" ) . '"';
232
233 ?>
234 <div class="factory-bootstrap-423 factory-fontawesome-000">
235 <div class="modal fade" id="winp-sync-modal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
236 aria-hidden="true" style="display: none">
237 <div class="modal-dialog modal-dialog-centered" role="document">
238 <div class="modal-content">
239 <div class="modal-header">
240 <button type="button" class="close" data-dismiss="modal" aria-label="Close">
241 <span aria-hidden="true">&times;</span>
242 </button>
243 </div>
244 <div class="modal-body" id="winp-sync-content">
245 <p class="winp-icon">
246 <span class="dashicons dashicons-category"></span>
247 </p>
248 <p class="winp-header-modal">
249 <?php _e( 'Save a Snippet as a Template', 'insert-php' ); ?>
250 <?php echo $premium_text; ?>
251 </p>
252 <?php if ( $is_key ) : ?>
253 <p class="winp-title-modal">
254 <?php _e( 'Your snippets will be available for export and reuse on any page or website', 'insert-php' ); ?></p>
255 <?php else : ?>
256 <p class="winp-title-modal">
257 <?php _e( 'A copy of your snippet and its settings are stored on our remote server. You can access it from any website where you’ve activated the plugin’s premium version. If you have our plugin on multiple websites or work in a team, it’s quite handy to use templates. The feature is available in the premium version only.', 'insert-php' ); ?>
258 </p>
259 <?php endif; ?>
260 <?php if ( $is_key ) : ?>
261 <input type="text" id="winp-sync-snippet-name" required
262 placeholder="<?php _e( 'Enter template name', 'insert-php' ); ?>">
263 <button type="button" class="btn btn-secondary" id="winp-sync-save-button"<?php echo $button_nonce; ?>>
264 <span style="width: 40px"><?php _e( 'Save', 'insert-php' ); ?></span>
265 </button>
266 <div class="winp-modal-error">
267 <span class="dashicons dashicons-warning"></span>
268 <span class="warning-text"></span>
269 </div>
270 <?php else : ?>
271 <?php WINP_Helper::get_purchase_button( 'edit-snippet' ) ?>
272 <?php endif; ?>
273 </div>
274 </div>
275 </div>
276 </div>
277 <?php //wp_nonce_field( 'winp-snippet-library', 'winp-snippet-library-nonce' ); ?>
278 </div>
279 <?php
280 }
281 }
282
283 /**
284 * Deregister other CodeMirror styles
285 */
286 public function deregisterDefaultEditorResourses() {
287 global $post;
288
289 if ( empty( $post ) || $post->post_type !== WINP_SNIPPETS_POST_TYPE ) {
290 return;
291 }
292
293 /* Remove other CodeMirror styles */
294 wp_deregister_style( 'codemirror' );
295 }
296
297 public function printCodeEditorScripts() {
298 global $post;
299
300 if ( empty( $post ) || $post->post_type !== WINP_SNIPPETS_POST_TYPE ) {
301 return;
302 }
303
304 $snippet_type = WINP_Helper::get_snippet_type();
305 $code_editor_mode = 'application/x-httpd-php';
306 if ( $snippet_type == WINP_SNIPPET_TYPE_PHP ) {
307 $code_editor_mode = 'text/x-php';
308 } else if ( $snippet_type === WINP_SNIPPET_TYPE_CSS ) {
309 $code_editor_mode = 'text/css';
310 } else if ( $snippet_type === WINP_SNIPPET_TYPE_JS ) {
311 $code_editor_mode = 'application/javascript';
312 } else if ( $snippet_type === WINP_SNIPPET_TYPE_HTML ) {
313 $code_editor_mode = 'text/html';
314 }
315 $code_editor_theme = $this->plugin->getPopulateOption( 'code_editor_theme' );
316 ?>
317 <script>
318 /* Loads CodeMirror on the snippet editor */
319 (function() {
320
321 var atts = [];
322
323 atts['mode'] = '<?php echo $code_editor_mode ?>';
324
325 atts['matchBrackets'] = true;
326 atts['styleActiveLine'] = true;
327 atts['continueComments'] = true;
328 atts['autoCloseTags'] = true;
329 atts['viewportMargin'] = Infinity;
330
331 atts['inputStyle'] = 'contenteditable';
332 atts['direction'] = 'ltr';
333 atts['lint'] = true;
334 atts['gutters'] = ["CodeMirror-lint-markers"];
335
336 atts['matchTags'] = {
337 'bothTags': true
338 };
339
340 atts['extraKeys'] = {
341 'Ctrl-Enter': function(cm) {
342 document.getElementById('post_content').submit();
343 },
344 'Ctrl-Space': 'autocomplete',
345 'Ctrl-/': 'toggleComment',
346 'Cmd-/': 'toggleComment',
347 'Alt-F': 'findPersistent',
348 'Ctrl-F': 'findPersistent',
349 'Cmd-F': 'findPersistent'
350 };
351
352 atts['indentWithTabs'] = <?php $this->printBool( $this->plugin->getPopulateOption( 'code_editor_indent_with_tabs', true ) ) ?>;
353 atts['tabSize'] = <?php echo (int) $this->plugin->getPopulateOption( 'code_editor_tab_size', 4 ) ?>;
354 atts['indentUnit'] = <?php echo (int) $this->plugin->getPopulateOption( 'code_editor_indent_unit', 4 ) ?>;
355 atts['lineNumbers'] = <?php $this->printBool( $this->plugin->getPopulateOption( 'code_editor_line_numbers', true ) ) ?>;
356 atts['lineWrapping'] = <?php $this->printBool( $this->plugin->getPopulateOption( 'code_editor_wrap_lines', true ) ) ?>;
357 atts['autoCloseBrackets'] = <?php $this->printBool( $this->plugin->getPopulateOption( 'code_editor_auto_close_brackets', true ) ) ?>;
358 <?php if ($this->plugin->getPopulateOption( 'code_editor_highlight_selection_matches', true )) { ?>
359 atts['highlightSelectionMatches'] = {
360 showToken: true,
361 style: 'winp-matchhighlight'
362 };
363 <?php } else { ?>
364 atts['highlightSelectionMatches'] = false;
365 <?php } ?>
366
367 <?php if(! empty( $code_editor_theme ) && $code_editor_theme != 'default'): ?>
368 atts['theme'] = '<?php echo esc_attr( $code_editor_theme ) ?>';
369 <?php endif; ?>
370
371 Woody_CodeMirror.fromTextArea(document.getElementById('post_content'), atts);
372 })();
373
374 jQuery(document).ready(function($) {
375 $('.wp-editor-tabs').remove();
376 });
377 </script>
378 <?php
379 }
380
381 /**
382 * Markup PHP snippet editor.
383 *
384 * @param Wp_Post $post Post Object.
385 */
386 function php_editor_markup( $post ) {
387
388 if ( WINP_SNIPPETS_POST_TYPE == $post->post_type ) {
389 wp_nonce_field( basename( __FILE__ ), WINP_SNIPPETS_POST_TYPE );
390
391 $snippet_code = WINP_Helper::get_snippet_code( $post );
392
393 ?>
394 <div class="wp-editor-container winp-editor-container">
395 <textarea id="post_content" name="post_content"
396 class="wp-editor-area winp-php-content"><?php echo esc_html( $snippet_code ); ?></textarea>
397 </div>
398 <?php
399 }
400 }
401
402 /**
403 * Adds one or more classes to the body tag in the dashboard.
404 *
405 * @param string $classes Current body classes.
406 *
407 * @return string Altered body classes.
408 */
409 public function admin_body_class( $classes ) {
410 global $post;
411
412 if ( ! empty( $post ) && $post->post_type == WINP_SNIPPETS_POST_TYPE ) {
413 $snippet_type = WINP_Helper::get_snippet_type();
414
415 $new_classes = "wbcr-inp-snippet-type-" . esc_attr( $snippet_type );
416
417 if ( $snippet_type !== WINP_SNIPPET_TYPE_TEXT ) {
418 $new_classes .= " winp-snippet-enabled";
419 }
420
421 return ' ' . $new_classes . ' ' . $classes;
422 }
423
424 return $classes;
425 }
426
427 /**
428 * Add hidden tag to edit post form
429 * Set post title for snippet post with status auto-draft
430 *
431 * @param $current_post
432 */
433 public function editFormTop( $current_post ) {
434 if ( empty( $current_post ) || $current_post->post_type !== WINP_SNIPPETS_POST_TYPE ) {
435 return;
436 }
437
438 $snippet_type = WINP_Plugin::app()->request->get( 'winp_item', WINP_SNIPPET_TYPE_PHP, 'sanitize_key' );
439 $snippet_type = WINP_Helper::getMetaOption( $current_post->ID, 'snippet_type', $snippet_type );
440
441 echo '<input type="hidden" id="wbcr_inp_snippet_type" name="wbcr_inp_snippet_type" value="' . esc_attr( $snippet_type ) . '">';
442
443 if ( 'auto-draft' == $current_post->post_status && WINP_SNIPPETS_POST_TYPE == $current_post->post_type && WINP_Helper::getMetaOption( $current_post->ID, 'snippet_draft', false ) ) {
444 global $post;
445
446 $post->post_title = get_post( $current_post->ID )->post_title;
447 }
448 }
449
450 /**
451 * Add button "Save as template" on post edit page
452 *
453 * @param WP_Post $post
454 */
455 public function post_submitbox_misc_actions( $post ) {
456 if ( empty( $post ) || ( $post->post_type != WINP_SNIPPETS_POST_TYPE ) ) {
457 return;
458 }
459
460 if ( WINP_Helper::getMetaOption( $post->ID, 'snippet_draft', false ) ) {
461 return;
462 }
463
464 $disabled = '';
465 if ( $post->ID && WINP_Plugin::app()->get_api_object()->is_key() ) {
466 $disabled = WINP_Plugin::app()->get_api_object()->is_changed( $post->ID ) == true ? '' : ' disabled';
467 }
468 ?>
469 <div class="winp-sync-buttons">
470 <a class="wbcr-inp-import-snippet-button button<?php echo $disabled; ?>" id="winp-snippet-sync"
471 href="javascript:void(0)">
472 <span class="dashicons dashicons-cloud" title="<?php _e( 'Export snippet', 'insert-php' ); ?>"></span>
473 <?php _e( 'Save as template', 'insert-php' ); ?>
474 </a>
475 </div>
476 <?php
477 }
478
479 /**
480 * @param bool $bool_val
481 */
482 protected function printBool( $bool_val ) {
483 echo $bool_val ? 'true' : 'false';
484 }
485
486 /**
487 * Configures a form that will be inside the metabox.
488 *
489 * @since 1.0.0
490 *
491 * @param Wbcr_FactoryForms420_Form $form A form object to configure.
492 *
493 * @return void
494 * @see Wbcr_FactoryMetaboxes409_FormMetabox
495 */
496 public function form( $form ) {
497 $snippet_type = WINP_Helper::get_snippet_type();
498
499 if ( $snippet_type === WINP_SNIPPET_TYPE_PHP ) {
500 $option_name = 'Run everywhere';
501 $data = [
502 [ 'evrywhere', __( $option_name, 'insert-php' ) ],
503 [ 'shortcode', __( 'Where there is a shortcode', 'insert-php' ) ],
504 ];
505
506 $events = [
507 'evrywhere' => [
508 'hide' => '.factory-control-snippet_custom_name',
509 ],
510 'shortcode' => [
511 'show' => '.factory-control-snippet_custom_name',
512 ],
513 ];
514 } else {
515 if ( $snippet_type === WINP_SNIPPET_TYPE_TEXT ) {
516 $hint = __( 'If you want to place some content into your snippet from the shortcode just wrap it inside [wbcr_text_snippet id="xxx"]content[/wbcr_text_snippet]. To use this content inside the snippet use {{SNIPPET_CONTENT}} variable.', 'insert-php' );
517 } else {
518 $_type = $snippet_type === WINP_SNIPPET_TYPE_UNIVERSAL ? '' : '_' . $snippet_type;
519 $hint = sprintf( __( 'If you want to place some content into your snippet from the shortcode just wrap it inside [wbcr%s_snippet id="xxx"]content[/wbcr%s_snippet]. To use this content inside the snippet use $content variable.', 'insert-php' ), $_type, $_type );
520 }
521
522 $option_name = 'Automatic insertion';
523 $data = [
524 [ 'auto', __( $option_name, 'insert-php' ) ],
525 [ 'shortcode', __( 'Where there is a shortcode', 'insert-php' ), $hint ],
526 ];
527
528 $events = [
529 'auto' => [
530 'show' => '.factory-control-snippet_location',
531 'hide' => '.factory-control-snippet_custom_name',
532 ],
533 'shortcode' => [
534 'hide' => '.factory-control-snippet_location,.factory-control-snippet_p_number',
535 'show' => '.factory-control-snippet_custom_name',
536 ],
537 ];
538 }
539
540 $items[] = [
541 'type' => 'dropdown',
542 'way' => 'buttons',
543 'name' => 'snippet_scope',
544 'data' => $data,
545 'title' => __( 'Where to execute the code?', 'insert-php' ),
546 'hint' => sprintf( esc_html__( 'If you select the "%s" option, after activating the widget, the php code will be launched on all pages of your site. Another option works only where you have set a shortcode snippet (widgets, post).', 'insert-php' ), __( $option_name, 'insert-php' ) ),
547 'default' => 'shortcode',
548 'events' => $events,
549 ];
550
551 $is_pro = WINP_Plugin::app()->get_api_object()->is_key();
552 $items[] = [
553 'type' => 'textbox',
554 'name' => 'snippet_custom_name',
555 'title' => __( 'Custom shortcode name', 'insert-php' ),
556 'hint' => __( 'By default, all snippet shortcodes look like this: [wbcr_snippet id=”121”]. Such shortcodes are hard to remember. In addition, when you move a snippet to another website its ID can be changed. So the best solution for the snippets use regularly is to define a custom shortcode name. The custom shortcode may look like this: [soccer_match_date]', 'insert-php' ),
557 'default' => '',
558 // Добавляем класс
559 'cssClass' => ! $is_pro ? [ 'winp-field-premium-element winp-field-w250' ] : [ 'winp-field-w250' ],
560 // Добавляем атрибут disable
561 'htmlAttrs' => ! $is_pro ? [ 'disabled' => 'disabled' ] : [],
562 ];
563
564 if ( $snippet_type !== WINP_SNIPPET_TYPE_PHP ) {
565 $data = [
566 [
567 'title' => __( 'Everywhere', 'insert-php' ),
568 'type' => 'group',
569 'items' => [
570 [
571 WINP_SNIPPET_AUTO_HEADER,
572 __( 'Head', 'insert-php' ),
573 __( 'Snippet will be placed in the source code before </head>.', 'insert-php' ),
574 ],
575 [
576 WINP_SNIPPET_AUTO_FOOTER,
577 __( 'Footer', 'insert-php' ),
578 __( 'Snippet will be placed in the source code before </body>.', 'insert-php' ),
579 ],
580 ],
581 ],
582 [
583 'title' => __( 'Posts, Pages, Custom post types', 'insert-php' ),
584 'type' => 'group',
585 'items' => [
586 [
587 WINP_SNIPPET_AUTO_BEFORE_POST,
588 __( 'Insert Before Post', 'insert-php' ),
589 __( 'Snippet will be placed before the title of the post/page.', 'insert-php' ),
590 ],
591 [
592 WINP_SNIPPET_AUTO_BEFORE_CONTENT,
593 __( 'Insert Before Content', 'insert-php' ),
594 __( 'Snippet will be placed before the content of the post/page.', 'insert-php' ),
595 ],
596 [
597 WINP_SNIPPET_AUTO_BEFORE_PARAGRAPH,
598 __( 'Insert Before Paragraph', 'insert-php' ),
599 __( 'Snippet will be placed before the paragraph, which number you can specify in the Location number field.', 'insert-php' ),
600 ],
601 [
602 WINP_SNIPPET_AUTO_AFTER_PARAGRAPH,
603 __( 'Insert After Paragraph', 'insert-php' ),
604 __( 'Snippet will be placed after the paragraph, which number you can specify in the Location number field.', 'insert-php' ),
605 ],
606 [
607 WINP_SNIPPET_AUTO_AFTER_CONTENT,
608 __( 'Insert After Content', 'insert-php' ),
609 __( 'Snippet will be placed after the content of the post/page.', 'insert-php' ),
610 ],
611 [
612 WINP_SNIPPET_AUTO_AFTER_POST,
613 __( 'Insert After Post', 'insert-php' ),
614 __( 'Snippet will be placed in the very end of the post/page.', 'insert-php' ),
615 ],
616 ],
617 ],
618 [
619 'title' => __( 'Categories, Archives, Tags, Taxonomies', 'insert-php' ),
620 'type' => 'group',
621 'items' => [
622 [
623 WINP_SNIPPET_AUTO_BEFORE_EXCERPT,
624 __( 'Insert Before Excerpt', 'insert-php' ),
625 __( 'Snippet will be placed before the excerpt of the post/page.', 'insert-php' ),
626 ],
627 [
628 WINP_SNIPPET_AUTO_AFTER_EXCERPT,
629 __( 'Insert After Excerpt', 'insert-php' ),
630 __( 'Snippet will be placed after the excerpt of the post/page.', 'insert-php' ),
631 ],
632 [
633 WINP_SNIPPET_AUTO_BETWEEN_POSTS,
634 __( 'Between Posts', 'insert-php' ),
635 __( 'Snippet will be placed between each post.', 'insert-php' ),
636 ],
637 [
638 WINP_SNIPPET_AUTO_BEFORE_POSTS,
639 __( 'Before post', 'insert-php' ),
640 __( 'Snippet will be placed before the post, which number you can specify in the Location number field.', 'insert-php' ),
641 ],
642 [
643 WINP_SNIPPET_AUTO_AFTER_POSTS,
644 __( 'After post', 'insert-php' ),
645 __( 'Snippet will be placed after the post, which number you can specify in the Location number field.', 'insert-php' ),
646 ],
647 ],
648 ],
649 ];
650
651 if ( $snippet_type === WINP_SNIPPET_TYPE_TEXT ) {
652 unset( $data[0] );
653 $data = array_values( $data );
654 }
655
656 $items[] = [
657 'type' => 'dropdown',
658 'name' => 'snippet_location',
659 'data' => $data,
660 'title' => __( 'Insertion location', 'insert-php' ),
661 'hint' => __( 'Select the location for you snippet.', 'insert-php' ),
662 'default' => WINP_SNIPPET_AUTO_HEADER,
663 'events' => [
664 WINP_SNIPPET_AUTO_HEADER => [
665 'hide' => '.factory-control-snippet_p_number',
666 ],
667 WINP_SNIPPET_AUTO_FOOTER => [
668 'hide' => '.factory-control-snippet_p_number',
669 ],
670 WINP_SNIPPET_AUTO_BEFORE_POST => [
671 'hide' => '.factory-control-snippet_p_number',
672 ],
673 WINP_SNIPPET_AUTO_BEFORE_CONTENT => [
674 'hide' => '.factory-control-snippet_p_number',
675 ],
676 WINP_SNIPPET_AUTO_AFTER_CONTENT => [
677 'hide' => '.factory-control-snippet_p_number',
678 ],
679 WINP_SNIPPET_AUTO_AFTER_POST => [
680 'hide' => '.factory-control-snippet_p_number',
681 ],
682 WINP_SNIPPET_AUTO_BEFORE_EXCERPT => [
683 'hide' => '.factory-control-snippet_p_number',
684 ],
685 WINP_SNIPPET_AUTO_AFTER_EXCERPT => [
686 'hide' => '.factory-control-snippet_p_number',
687 ],
688 WINP_SNIPPET_AUTO_BETWEEN_POSTS => [
689 'hide' => '.factory-control-snippet_p_number',
690 ],
691 WINP_SNIPPET_AUTO_BEFORE_PARAGRAPH => [
692 'show' => '.factory-control-snippet_p_number',
693 ],
694 WINP_SNIPPET_AUTO_AFTER_PARAGRAPH => [
695 'show' => '.factory-control-snippet_p_number',
696 ],
697 WINP_SNIPPET_AUTO_BEFORE_POSTS => [
698 'show' => '.factory-control-snippet_p_number',
699 ],
700 WINP_SNIPPET_AUTO_AFTER_POSTS => [
701 'show' => '.factory-control-snippet_p_number',
702 ],
703 ],
704 ];
705
706 $items[] = [
707 'type' => 'textbox',
708 'name' => 'snippet_p_number',
709 'title' => __( 'Location number', 'insert-php' ),
710 'hint' => __( 'Paragraph / Post number', 'insert-php' ),
711 'default' => 0,
712 ];
713 }
714
715 if ( $snippet_type === WINP_SNIPPET_TYPE_CSS || $snippet_type === WINP_SNIPPET_TYPE_JS ) {
716 $items[] = [
717 'type' => 'dropdown',
718 'way' => 'buttons',
719 'name' => 'snippet_linking',
720 'data' => [
721 [ 'external', __( 'External File', 'insert-php' ) ],
722 [ 'inline', __( 'Inline Code', 'insert-php' ) ],
723 ],
724 'title' => __( 'Linking type', 'insert-php' ),
725 'hint' => __( 'Select how the snippet will be linked to the page.', 'insert-php' ),
726 'default' => 'external',
727 ];
728 }
729
730 $items[] = [
731 'type' => 'textarea',
732 'name' => 'snippet_description',
733 'title' => __( 'Description', 'insert-php' ),
734 'hint' => __( 'You can write a short note so that you can always remember why this code or your colleague was able to apply this code in his works.', 'insert-php' ),
735 'tinymce' => [
736 'height' => 150,
737 'plugins' => '',
738 ],
739 'default' => '',
740 ];
741
742 if ( $snippet_type !== WINP_SNIPPET_TYPE_TEXT ) {
743 $shorcode_name = $snippet_type === WINP_SNIPPET_TYPE_UNIVERSAL ? 'wbcr_snippet' : 'wbcr_' . $snippet_type . '_snippet';
744 $items[] = [
745 'type' => 'textbox',
746 'name' => 'snippet_tags',
747 'title' => __( 'Available attributes', 'insert-php' ),
748 'hint' => sprintf( esc_html__( "Available attributes for shortcode via comma. Only numbers, letters and underscore characters are allowed. Attribute id is always available. With this option you can set additional attributes for the shortcode. Example: start_date attribute to [%s id='xxx' start_date='2018/01/15'] shortcode. Now we can get attribute value in the snippet with the \$start_date variable. It's convenient if you want to print out different results depending on this attributes.", "insert-php" ), $shorcode_name ),
749 'placeholder' => 'title, pass_attr1, pass_attr2'
750 //'default' => ''
751 ];
752 }
753
754 $form->add( $items );
755 }
756
757 /**
758 * Validate the snippet code before saving to database
759 *
760 * @param $snippet_code
761 * @param $snippet_type
762 *
763 * @return bool true if code produces errors
764 */
765 private function validateCode( $snippet_code, $snippet_type ) {
766 global $post;
767
768 $snippet_code = stripslashes( $snippet_code );
769
770 if ( empty( $snippet_code ) ) {
771 return true;
772 }
773
774 ob_start( [ $this, 'codeErrorCallback' ] );
775
776 $result = $snippet_type == WINP_SNIPPET_TYPE_UNIVERSAL ? eval( "?> " . $snippet_code . " <?php " ) : eval( $snippet_code );
777
778 // elimination of errors 500 in eval() functions, with the directive display_errors = off;
779 header( 'HTTP/1.0 200 OK' );
780
781 ob_end_clean();
782
783 do_action( 'wbcr_inp_after_execute_snippet', $post->ID, $snippet_code, $result );
784
785 return false !== $result;
786 }
787
788 /**
789 * This friendly notice will be shown to the user in case of php errors.
790 *
791 * @param $out
792 *
793 * @return string
794 */
795 private function codeErrorCallback( $out ) {
796 $error = error_get_last();
797
798 if ( is_null( $error ) ) {
799 return $out;
800 }
801
802 $m = '<h3>' . __( "Don't Panic", 'code-snippets' ) . '</h3>';
803 $m .= '<p>' . sprintf( __( 'The code snippet you are trying to save produced a fatal error on line %d:', 'code_snippets' ), $error['line'] ) . '</p>';
804 $m .= '<strong>' . $error['message'] . '</strong>';
805 $m .= '<p>' . __( 'The previous version of the snippet is unchanged, and the rest of this site should be functioning normally as before.', 'code-snippets' ) . '</p>';
806 $m .= '<p>' . __( 'Please use the back button in your browser to return to the previous page and try to fix the code error.', 'code-snippets' );
807 $m .= ' ' . __( 'If you prefer, you can close this page and discard the changes you just made. No changes will be made to this site.', 'code-snippets' ) . '</p>';
808
809 return $m;
810 }
811
812 /**
813 * Filter the code by removing close php tag from beginning and adding open php tag to beginning (if not)
814 *
815 * @param $code
816 * @param $snippet_type
817 *
818 * @return mixed|string
819 */
820 private function filterCode( $code, $snippet_type ) {
821 if ( empty( $code ) ) {
822 return $code;
823 }
824
825 if ( $snippet_type == WINP_SNIPPET_TYPE_CSS || $snippet_type == WINP_SNIPPET_TYPE_JS ) {
826 $code = strip_tags( $code );
827 } else if ( $snippet_type == WINP_SNIPPET_TYPE_HTML ) {
828 $code = preg_replace( '/<\\?.*(\\?>|$)/Us', '', $code );
829 } else if ( $snippet_type != WINP_SNIPPET_TYPE_PHP ) {
830 /* Remove ?> from beginning of snippet */
831 $code = preg_replace( '|^[\s]*\?>|', '', $code );
832
833 /* Если количество закрывающи�
834 тегов не равно количеству открывающи�
835 , то добавим лишний */
836 $start_count = substr_count( $code, '<?' );
837 $end_count = substr_count( $code, '?>' );
838
839 if ( $start_count !== $end_count ) {
840 if ( $start_count > $end_count ) {
841 $code = $code . '?>';
842 } else {
843 $code = '<?php ' . $code;
844 }
845 }
846 }
847
848 return $code;
849 }
850
851 /**
852 * On saving form
853 *
854 * @param $postId
855 *
856 * @todo Доработать с учетом изменения имени поля для ввода кода
857 *
858 */
859 public function onSavingForm( $post_id ) {
860 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
861 return;
862 }
863
864 $location = WINP_Plugin::app()->request->post( WINP_Plugin::app()->getPrefix() . 'snippet_location', WINP_SNIPPET_AUTO_HEADER, true );
865 WINP_Helper::updateMetaOption( $post_id, 'snippet_location', $location );
866
867 $type = WINP_Plugin::app()->request->post( WINP_Plugin::app()->getPrefix() . 'snippet_type', WINP_SNIPPET_TYPE_PHP, true );
868 WINP_Helper::updateMetaOption( $post_id, 'snippet_type', $type );
869
870 $linking = WINP_Plugin::app()->request->post( WINP_Plugin::app()->getPrefix() . 'snippet_linking', '', true );
871 WINP_Helper::updateMetaOption( $post_id, 'snippet_linking', $linking );
872
873 // Save Conditional execution logic for the snippet
874 $filters = WINP_Plugin::app()->request->post( WINP_Plugin::app()->getPrefix() . 'snippet_filters', '' );
875 $filters = ! empty( $filters ) ? json_decode( stripslashes( $filters ) ) : '';
876 WINP_Helper::updateMetaOption( $post_id, 'snippet_filters', $filters );
877
878 $changed_filters = WINP_Plugin::app()->request->post( WINP_Plugin::app()->getPrefix() . 'changed_filters', 0 );
879 $changed_filters = intval( $changed_filters );
880 WINP_Helper::updateMetaOption( $post_id, 'changed_filters', $changed_filters );
881
882 do_action( 'wbcr/inp/base_option/on_saving_form', $post_id );
883 }
884
885 /**
886 * After saving form
887 *
888 * @param int $post_id
889 */
890 public function afterSavingForm( $post_id ) {
891 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
892 return;
893 }
894
895 $is_default_activate = WINP_Plugin::app()->getPopulateOption( 'activate_by_default', true );
896 $snippet_scope = WINP_Plugin::app()->request->post( WINP_Plugin::app()->getPrefix() . 'snippet_scope', null, true );
897 $snippet_type = WINP_Helper::get_snippet_type( $post_id );
898 $post_content = get_post_field( 'post_content', $post_id );
899
900 if ( $snippet_type != WINP_SNIPPET_TYPE_TEXT ) {
901 $snippet_content = ! empty( $post_content ) ? WINP_Plugin::app()->getExecuteObject()->prepareCode( $post_content, $post_id ) : '';
902 } else {
903 $snippet_content = $post_content;
904 }
905
906 WINP_Helper::updateMetaOption( $post_id, 'snippet_activate', false );
907
908 $validate = true;
909
910 if ( $snippet_scope == 'evrywhere' || $snippet_scope == 'auto' ) {
911 if ( $snippet_type != WINP_SNIPPET_TYPE_TEXT && $snippet_type != WINP_SNIPPET_TYPE_CSS && $snippet_type != WINP_SNIPPET_TYPE_JS && $snippet_type != WINP_SNIPPET_TYPE_HTML ) {
912 $validate = $this->validateCode( $snippet_content, $snippet_type );
913 } else {
914 $validate = true;
915 }
916 }
917
918 if ( $validate && $is_default_activate && WINP_Plugin::app()->currentUserCan() ) {
919 WINP_Helper::updateMetaOption( $post_id, 'snippet_activate', true );
920 } else {
921 if ( ! defined( 'WP_SANDBOX_SCRAPING' ) ) {
922 define( 'WP_SANDBOX_SCRAPING', true );
923 }
924 /* Display message if a parse error occurred */
925 wp_redirect( add_query_arg( [
926 'action' => 'edit',
927 'post' => $post_id,
928 'wbcr_inp_save_snippet_result' => 'code-error',
929 ], admin_url( 'post.php' ) ) );
930
931 exit;
932 }
933 }
934 }
935