Completed
Push — develop ( 14767b...cffcc3 )
by Marco
01:20
created

Black_Studio_TinyMCE_Admin::enqueue_style()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 4
nop 0
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 * Black Studio TinyMCE Widget - Admin features
4
 *
5
 * @package Black_Studio_TinyMCE_Widget
6
 */
7
8
// Exit if accessed directly.
9
if ( ! defined( 'ABSPATH' ) ) {
10
	exit;
11
}
12
13
if ( ! class_exists( 'Black_Studio_TinyMCE_Admin' ) ) {
14
15
	/**
16
	 * Class that provides admin functionalities
17
	 *
18
	 * @package Black_Studio_TinyMCE_Widget
19
	 * @since 2.0.0
20
	 */
21
	final class Black_Studio_TinyMCE_Admin {
22
23
		/**
24
		 * The single instance of the class
25
		 *
26
		 * @var object
27
		 * @since 2.0.0
28
		 */
29
		protected static $_instance = null;
30
31
		/**
32
		 * Array containing the plugin links
33
		 *
34
		 * @var array
35
		 * @since 2.0.0
36
		 */
37
		protected $links;
38
39
		/**
40
		 * Return the single class instance
41
		 *
42
		 * @return object
43
		 * @since 2.0.0
44
		 */
45
		public static function instance() {
46
			if ( is_null( self::$_instance ) ) {
47
				self::$_instance = new self();
48
			}
49
			return self::$_instance;
50
		}
51
52
		/**
53
		 * Class constructor
54
		 *
55
		 * @uses add_action()
56
		 * @uses add_filter()
57
		 * @uses get_option()
58
		 * @uses get_bloginfo()
59
		 *
60
		 * @global object $wp_embed
61
		 * @since 2.0.0
62
		 */
63
		protected function __construct() {
64
			// Register action and filter hooks.
65
			add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
66
			add_action( 'admin_init', array( $this, 'admin_init' ), 20 );
67
			add_action( 'init', array( $this, 'register_dummy_post_type' ) );
68
		}
69
70
		/**
71
		 * Prevent the class from being cloned
72
		 *
73
		 * @return void
74
		 * @since 2.0.0
75
		 */
76
		protected function __clone() {
77
			_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin&#8217; uh?' ), '2.0' );
78
		}
79
80
		/**
81
		 * Load language files
82
		 *
83
		 * @uses load_plugin_textdomain()
84
		 *
85
		 * @return void
86
		 * @since 2.0.0
87
		 */
88
		public function load_textdomain() {
89
			load_plugin_textdomain( 'black-studio-tinymce-widget', false, dirname( dirname( plugin_basename( __FILE__ ) ) ) . '/languages/' );
90
		}
91
92
		/**
93
		 * Checks if the plugin admin code should be loaded
94
		 *
95
		 * @uses apply_filters()
96
		 *
97
		 * @global string $pagenow
98
		 * @return boolean
99
		 * @since 2.0.0
100
		 */
101
		public function enabled() {
102
			global $pagenow;
103
			$enabled_pages = apply_filters( 'black_studio_tinymce_enable_pages', array( 'widgets.php', 'customize.php', 'admin-ajax.php' ) );
104
			return apply_filters( 'black_studio_tinymce_enable', in_array( $pagenow, $enabled_pages, true ) );
105
		}
106
107
		/**
108
		 * Add actions and filters (only in widgets admin page)
109
		 *
110
		 * @uses add_action()
111
		 * @uses add_filter()
112
		 * @uses do_action()
113
		 *
114
		 * @return void
115
		 * @since 2.0.0
116
		 */
117
		public function admin_init() {
118
			$this->init_links();
119
			add_action( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 2 );
120
			if ( $this->enabled() ) {
121
				add_action( 'admin_head', array( $this, 'enqueue_media' ) );
122
				add_action( 'admin_print_scripts', array( $this, 'admin_print_scripts' ) );
123
				add_action( 'admin_print_styles', array( $this, 'admin_print_styles' ) );
124
				add_action( 'admin_print_footer_scripts', array( $this, 'admin_print_footer_scripts' ) );
125
				add_action( 'black_studio_tinymce_before_editor', array( $this, 'display_links' ) );
126
				add_action( 'black_studio_tinymce_editor', array( $this, 'editor' ), 10, 4 );
127
				add_action( 'black_studio_tinymce_after_editor', array( $this, 'fix_the_editor_content_filter' ) );
128
				add_action( 'wp_tiny_mce_init', array( $this, 'wp_tiny_mce_init' ) );
129
				add_filter( 'wp_editor_settings', array( $this, 'editor_settings' ), 5, 2 );
130
				add_filter( 'tiny_mce_before_init', array( $this, 'tinymce_fix_rtl' ), 10 );
131
				add_filter( 'tiny_mce_before_init', array( $this, 'tinymce_fullscreen' ), 10, 2 );
132
				add_filter( 'quicktags_settings', array( $this, 'quicktags_fullscreen' ), 10, 2 );
133
				if ( ! user_can_richedit() ) {
134
					add_action( 'admin_notices', array( $this, 'visual_editor_disabled_notice' ) );
135
				}
136
				add_action( 'wp_ajax_bstw_visual_editor_disabled_dismiss_notice', array( $this, 'visual_editor_disabled_dismiss_notice' ) );
137
				do_action( 'black_studio_tinymce_load' );
138
			}
139
		}
140
141
		/**
142
		 * Instantiate tinyMCE editor
143
		 *
144
		 * @uses add_thickbox()
145
		 * @uses wp_enqueue_media()
146
		 *
147
		 * @return void
148
		 * @since 2.0.0
149
		 */
150
		public function enqueue_media() {
151
			// Add support for thickbox media dialog.
152
			add_thickbox();
153
			// New media modal dialog (WP 3.5+).
154
			if ( function_exists( 'wp_enqueue_media' ) ) {
155
				wp_enqueue_media();
156
			}
157
		}
158
159
		/**
160
		 * Enqueue styles
161
		 *
162
		 * @uses wp_enqueue_style()
163
		 *
164
		 * @return void
165
		 * @since 2.0.0
166
		 */
167
		public function admin_print_styles() {
168
			wp_enqueue_style( 'wp-jquery-ui-dialog' );
169
			wp_enqueue_style( 'editor-buttons' );
170
			$this->enqueue_style();
171
		}
172
173
		/**
174
		 * Helper function to enqueue style
175
		 *
176
		 * @uses apply_filters()
177
		 * @uses wp_enqueue_style()
178
		 * @uses plugins_url()
179
		 * @uses SCRIPT_DEBUG
180
		 *
181
		 * @return void
182
		 * @since 2.0.0
183
		 */
184
		public function enqueue_style() {
185
			$style  = apply_filters( 'black_studio_tinymce_widget_style', 'black-studio-tinymce-widget' );
186
			$path   = apply_filters( 'black_studio_tinymce_widget_style_path', 'css/' );
187
			$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '.css' : '.min.css';
188
			wp_enqueue_style(
189
				$style,
190
				plugins_url( $path . $style . $suffix, dirname( __FILE__ ) ),
191
				array(),
192
				bstw()->get_version()
193
			);
194
		}
195
196
		/**
197
		 * Enqueue header scripts
198
		 *
199
		 * @uses wp_enqueue_script()
200
		 * @uses do_action()
201
		 *
202
		 * @return void
203
		 * @since 2.0.0
204
		 */
205
		public function admin_print_scripts() {
206
			wp_enqueue_script( 'media-upload' );
207
			wp_enqueue_script( 'wplink' );
208
			wp_enqueue_script( 'wpdialogs-popup' );
209
			$this->enqueue_script();
210
			$this->localize_script();
211
			do_action( 'wp_enqueue_editor', array( 'tinymce' => true ) );
212
		}
213
214
		/**
215
		 * Helper function to enqueue script
216
		 *
217
		 * @uses apply_filters()
218
		 * @uses wp_enqueue_script()
219
		 * @uses plugins_url()
220
		 * @uses SCRIPT_DEBUG
221
		 *
222
		 * @return void
223
		 * @since 2.0.0
224
		 */
225
		public function enqueue_script() {
226
			$script = apply_filters( 'black_studio_tinymce_widget_script', 'black-studio-tinymce-widget' );
227
			$path   = apply_filters( 'black_studio_tinymce_widget_script_path', 'js/' );
228
			$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '.js' : '.min.js';
229
			wp_enqueue_script(
230
				$script,
231
				plugins_url( $path . $script . $suffix, dirname( __FILE__ ) ),
232
				array( 'jquery', 'editor', 'quicktags' ),
233
				bstw()->get_version(),
234
				true
235
			);
236
		}
237
238
		/**
239
		 * Helper function to enqueue localized script
240
		 *
241
		 * @uses apply_filters()
242
		 * @uses wp_localize_script()
243
		 *
244
		 * @return void
245
		 * @since 2.0.0
246
		 */
247
		public function localize_script() {
248
			$container_selectors = apply_filters( 'black_studio_tinymce_container_selectors', array( 'div.widget', 'div.widget-inside' ) );
249
			$activate_events     = apply_filters( 'black_studio_tinymce_activate_events', array() );
250
			$deactivate_events   = apply_filters( 'black_studio_tinymce_deactivate_events', array() );
251
			$data                = array(
252
				'dummy_post_id'       => $this->get_dummy_post_id(),
253
				'container_selectors' => implode( ', ', $container_selectors ),
254
				'activate_events'     => $activate_events,
255
				'deactivate_events'   => $deactivate_events,
256
				/* translators: error message shown when a duplicated widget ID is detected */
257
				'error_duplicate_id'  => __( 'ERROR: Duplicate widget ID detected. To avoid content loss, please create a new widget with the same content and then delete this one.', 'black-studio-tinymce-widget' ),
258
			);
259
			wp_localize_script( apply_filters( 'black_studio_tinymce_widget_script', 'black-studio-tinymce-widget' ), 'bstw_data', $data );
260
		}
261
262
		/**
263
		 * Enqueue footer scripts
264
		 *
265
		 * @return void
266
		 * @since 2.0.0
267
		 */
268
		public function admin_print_footer_scripts() {
269
			$this->editor( '', 'black-studio-tinymce-widget', 'black-studio-tinymce-widget' );
270
		}
271
272
		/**
273
		 * Output the visual editor
274
		 *
275
		 * @uses wp_editor()
276
		 *
277
		 * @param string $text      Text inside the editor.
278
		 * @param string $editor_id Editor instance ID.
279
		 * @param string $name      Editor instance name.
280
		 * @param string $type      Editor instance type.
281
		 * @return void
282
		 * @since 2.0.0
283
		 */
284
		public function editor( $text, $editor_id, $name = '', $type = 'visual' ) {
285
			wp_editor( $text, $editor_id, array(
286
				'textarea_name'  => $name,
287
				'default_editor' => 'visual' === $type ? 'tmce' : 'html',
288
			) );
289
		}
290
291
		/**
292
		 * Remove editor content filters for multiple editor instances
293
		 * Workaround for WordPress Core bug #28403 https://core.trac.wordpress.org/ticket/28403
294
		 *
295
		 * @uses remove_filter
296
		 *
297
		 * @return void
298
		 * @since 2.1.7
299
		 */
300
		public function fix_the_editor_content_filter() {
301
			remove_filter( 'the_editor_content', 'wp_htmledit_pre' );
302
			remove_filter( 'the_editor_content', 'wp_richedit_pre' );
303
		}
304
305
		/**
306
		 * Setup editor instance for event handling
307
		 *
308
		 * @uses SCRIPT_DEBUG
309
		 *
310
		 * @return void
311
		 * @since 2.2.1
312
		 */
313
		public function wp_tiny_mce_init() {
314
			$script = 'black-studio-tinymce-widget-setup';
315
			$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '.js' : '.min.js';
316
			echo "\t\t" . '<script type="text/javascript" src="' . plugins_url( 'js/' . $script . $suffix, dirname( __FILE__ ) ) . '"></script>' . "\n"; // xss ok.
317
		}
318
319
		/**
320
		 * Set editor settings
321
		 *
322
		 * @param mixed[] $settings Array of settings.
323
		 * @param string  $editor_id Editor instance ID.
324
		 * @return mixed[]
325
		 * @since 2.0.0
326
		 */
327
		public function editor_settings( $settings, $editor_id ) {
328
			if ( strstr( $editor_id, 'black-studio-tinymce' ) ) {
329
				$settings['tinymce']       = array(
330
					'wp_skip_init'       => 'widget-black-studio-tinymce-__i__-text' === $editor_id,
331
					'add_unload_trigger' => false,
332
					'wp_autoresize_on'   => false,
333
				);
334
				$settings['editor_height'] = 350;
335
				$settings['dfw']           = true;
336
				$settings['editor_class']  = 'black-studio-tinymce';
337
			}
338
			return $settings;
339
		}
340
341
		/**
342
		 * Initialize plugin links
343
		 *
344
		 * @return void
345
		 * @since 2.0.0
346
		 */
347
		public function init_links() {
348
			$this->links = array(
349
				/* translators: text used for plugin home link */
350
				'https://wordpress.org/plugins/black-studio-tinymce-widget/' => __( 'Home', 'black-studio-tinymce-widget' ),
351
				/* translators: text used for support faq link */
352
				'https://wordpress.org/plugins/black-studio-tinymce-widget/faq/' => __( 'FAQ', 'black-studio-tinymce-widget' ),
353
				/* translators: text used for support forum link */
354
				'https://wordpress.org/support/plugin/black-studio-tinymce-widget' => __( 'Support', 'black-studio-tinymce-widget' ),
355
				/* translators: text used for reviews link */
356
				'https://wordpress.org/support/view/plugin-reviews/black-studio-tinymce-widget' => __( 'Rate', 'black-studio-tinymce-widget' ),
357
				/* translators: text used for follow on twitter link */
358
				'https://twitter.com/blackstudioita' => __( 'Follow', 'black-studio-tinymce-widget' ),
359
				/* translators: text used for donation link */
360
				'https://www.blackstudio.it/en/wordpress-plugins/black-studio-tinymce-widget/' => __( 'Donate', 'black-studio-tinymce-widget' ),
361
			);
362
		}
363
364
		/**
365
		 * Display plugin links
366
		 *
367
		 * @return void
368
		 * @since 2.0.0
369
		 */
370
		public function display_links() {
371
			echo "\t<div class='bstw-links'>\n";
372
			echo "\t\t<span class='bstw-links-list'>\n";
373
			$counter = count( $this->links ) - 1;
374
			foreach ( $this->links as $url => $label ) {
375
				$separator = ( $counter-- > 0 ? ' | ' : '' );
376
				echo "\t\t\t<a href='" . esc_url( $url ) . "' target='_blank'>" . esc_html( $label ) . "</a>$separator\n"; // xss ok.
377
			}
378
			echo "\t\t</span>\n";
379
			/* translators: text used for the icon that shows the plugin links */
380
			echo "\t\t<a class='bstw-links-icon icon16 icon-plugins' href='#' title='" . esc_attr( __( 'About Black Studio TinyMCE Widget plugin', 'black-studio-tinymce-widget' ) ) . "'></a>\n";
381
			echo "\t</div>\n";
382
		}
383
384
		/**
385
		 * Show row meta on the plugin screen
386
		 *
387
		 * @uses esc_html()
388
		 * @uses esc_url()
389
		 *
390
		 * @param string[] $links Array of links.
391
		 * @param string   $file  Plugin's filename.
392
		 * @return string[]
393
		 * @since 2.0.0
394
		 */
395
		public function plugin_row_meta( $links, $file ) {
396
			if ( bstw()->get_basename() === $file ) {
397
				foreach ( $this->links as $url => $label ) {
398
					$links[ $label ] = '<a href="' . esc_url( $url ) . '" target="_blank">' . esc_html( $label ) . '</a>';
399
				}
400
			}
401
			return $links;
402
		}
403
404
		/**
405
		 * Fix for rtl languages
406
		 *
407
		 * @param mixed[] $settings Array of settings.
408
		 * @return mixed[]
409
		 * @since 2.1.0
410
		 */
411
		public function tinymce_fix_rtl( $settings ) {
412
			// This fix has to be applied to all editor instances (not just BSTW ones).
413
			if ( is_rtl() && isset( $settings['plugins'] ) && ',directionality' === $settings['plugins'] ) {
414
				unset( $settings['plugins'] );
415
			}
416
			return $settings;
417
		}
418
419
		/**
420
		 * Apply TinyMCE default fullscreen
421
		 *
422
		 * @param mixed[]     $settings  Array of settings.
423
		 * @param string|null $editor_id Editor ID.
424
		 * @return mixed[]
425
		 * @since 2.1.2
426
		 */
427
		public function tinymce_fullscreen( $settings, $editor_id = null ) {
428
			if ( strstr( $editor_id, 'black-studio-tinymce' ) ) {
429
				for ( $i = 1; $i <= 4; $i++ ) {
430
					$toolbar = 'toolbar' . $i;
431
					if ( isset( $settings[ $toolbar ] ) ) {
432
						$settings[ $toolbar ] = str_replace( 'wp_fullscreen', 'wp_fullscreen,fullscreen', $settings[ $toolbar ] );
433
					}
434
				}
435
			}
436
			return $settings;
437
		}
438
439
		/**
440
		 * Disable Quicktags default fullscreen
441
		 *
442
		 * @param mixed[] $settings  Array of settings.
443
		 * @param string  $editor_id Editor ID.
444
		 * @return mixed[]
445
		 * @since 2.1.2
446
		 */
447
		public function quicktags_fullscreen( $settings, $editor_id ) {
448
			if ( strstr( $editor_id, 'black-studio-tinymce' ) ) {
449
				$settings['buttons'] = str_replace( ',fullscreen', '', $settings['buttons'] );
450
			}
451
			return $settings;
452
		}
453
454
		/**
455
		 * Show admin notice when visual editor is disabled in current user's profile settings
456
		 *
457
		 * @uses get_user_meta()
458
		 * @uses get_current_user_id()
459
		 *
460
		 * @return void
461
		 * @since 2.4.0
462
		 */
463
		public function visual_editor_disabled_notice() {
464
			global $pagenow;
465
			$dismissed = false;
466
			if ( function_exists( 'get_user_meta' ) ) {
467
				$dismissed = get_user_meta( get_current_user_id(), '_bstw_visual_editor_disabled_notice_dismissed', true );
468
			}
469
			if ( 'widgets.php' === $pagenow && empty( $dismissed ) ) {
470
				echo '<div class="bstw-visual-editor-disabled-notice notice notice-warning is-dismissible">';
471
				/* translators: warning message shown when when visual editor is disabled in current user's profile settings */
472
				echo '<p>' . esc_html( __( 'Visual Editor is disabled in your Profile settings. You need to enable it in order to use the Visual Editor widget at its full potential.', 'black-studio-tinymce-widget' ) ) . '</p>';
473
				echo '</div>';
474
			}
475
		}
476
477
		/**
478
		 * Store dismission of the "Visual Editor disabled" notice for the current user
479
		 *
480
		 * @uses add_user_meta()
481
		 * @uses get_current_user_id()
482
		 *
483
		 * @return void
484
		 * @since 2.4.0
485
		 */
486
		public function visual_editor_disabled_dismiss_notice() {
487
			if ( function_exists( 'add_user_meta' ) ) {
488
				add_user_meta( get_current_user_id(), '_bstw_visual_editor_disabled_notice_dismissed', true );
489
			}
490
		}
491
492
		/**
493
		 * Register a private custom post type to be used for link embed previews
494
		 *
495
		 * @uses register_post_type()
496
		 *
497
		 * @return void
498
		 * @since 3.0.0
499
		 */
500
		public function register_dummy_post_type() {
501
			$args = array(
502
				'public'             => false,
503
				'publicly_queryable' => false,
504
				'show_ui'            => false,
505
				'query_var'          => false,
506
				'rewrite'            => false,
507
				'capability_type'    => 'post',
508
				'hierarchical'       => false,
509
				'menu_position'      => null,
510
				'show_in_nav_menus'  => false,
511
				'has_archive'        => false,
512
			);
513
			register_post_type( 'bstw_dummy', $args );
514
		}
515
516
		/**
517
		 * Get dummy post ID for link embed previews
518
		 *
519
		 * @uses WP_Query()
520
		 * @uses wp_insert_post()
521
		 * @uses update_option()
522
		 * @uses get_option()
523
		 *
524
		 * @return int
525
		 * @since 3.0.0
526
		 */
527
		public function get_dummy_post_id() {
528
			$query_post = new WP_Query( 'post_type=bstw_dummy' );
529
			if ( $query_post->post_count > 0 ) {
530
				$dummy_post_id = $query_post->post->ID;
531
			} else {
532
				$dummy_post_id = wp_insert_post( array( 'post_type' => 'bstw_dummy' ) );
533
			}
534
			return $dummy_post_id;
535
		}
536
537
	} // END class Black_Studio_TinyMCE_Admin
538
539
} // END class_exists check
540