PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 4.0.3
Tutor LMS – eLearning and online course solution v4.0.3
4.0.3 4.0.2 4.0.1 4.0.0 3.9.15 3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / components / WPEditor.php
tutor / components Last commit date
Constants 3 weeks ago Accordion.php 1 week ago Alert.php 1 week ago AttachmentCard.php 1 week ago Avatar.php 1 week ago Badge.php 1 week ago BaseComponent.php 3 weeks ago Button.php 1 week ago ConfirmationModal.php 1 week ago CourseFilter.php 1 week ago DateFilter.php 1 week ago DropdownFilter.php 1 week ago EmptyState.php 1 week ago FileUploader.php 1 week ago InputField.php 1 week ago Modal.php 1 week ago Nav.php 1 week ago Pagination.php 1 week ago Popover.php 1 week ago PreviewTrigger.php 1 week ago Progress.php 1 week ago SearchFilter.php 1 week ago Sorting.php 1 week ago StarRating.php 1 week ago StarRatingInput.php 1 week ago StatusSelect.php 1 week ago SvgIcon.php 1 week ago Table.php 1 week ago Tabs.php 1 week ago Tooltip.php 1 week ago WPEditor.php 1 week ago
WPEditor.php
485 lines
1 <?php
2 /**
3 * Tutor Component: WPEditor
4 *
5 * Provides a fluent builder for rendering WordPress editor (TinyMCE/QuickTags)
6 * with tutorForm integration for validation and state management.
7 *
8 * @package Tutor\Components
9 * @author Themeum
10 * @link https://themeum.com
11 * @since 4.0.0
12 */
13
14 namespace Tutor\Components;
15
16 use Tutor\Helpers\UrlHelper;
17
18 defined( 'ABSPATH' ) || exit;
19
20 /**
21 * WPEditor Component Class.
22 *
23 * Example usage:
24 * ```php
25 * // Basic editor with label
26 * WPEditor::make()
27 * ->name( 'description' )
28 * ->label( 'Course Description' )
29 * ->content( 'Default content here.' )
30 * ->render();
31 *
32 * // Required editor with placeholder
33 * WPEditor::make()
34 * ->name( 'answer' )
35 * ->label( 'Your Answer' )
36 * ->placeholder( 'Write your answer here...' )
37 * ->required( true )
38 * ->render();
39 *
40 * // Editor with Alpine.js form validation binding
41 * WPEditor::make()
42 * ->name( 'answer' )
43 * ->label( 'Your Answer' )
44 * ->attr( 'x-bind', "register('answer', { required: 'Answer is required' })" )
45 * ->render();
46 *
47 * // Editor pre-filled with saved content
48 * WPEditor::make()
49 * ->name( 'bio' )
50 * ->label( 'Instructor Bio' )
51 * ->content( get_user_meta( $user_id, 'description', true ) )
52 * ->render();
53 *
54 * // Editor with help text and error state
55 * WPEditor::make()
56 * ->name( 'overview' )
57 * ->label( 'Course Overview' )
58 * ->help_text( 'Describe what students will learn.' )
59 * ->error( 'This field is required.' )
60 * ->render();
61 *
62 * // Custom TinyMCE toolbar (no media buttons, custom toolbar)
63 * WPEditor::make()
64 * ->name( 'announcement' )
65 * ->label( 'Announcement' )
66 * ->editor_config( array(
67 * 'teeny' => false,
68 * 'media_buttons' => false,
69 * 'quicktags' => false,
70 * 'editor_height' => 200,
71 * 'tinymce' => array(
72 * 'toolbar1' => 'bold,italic,underline,link,unlink,bullist,numlist,removeformat',
73 * 'toolbar2' => '',
74 * 'toolbar3' => '',
75 * ),
76 * ) )
77 * ->render();
78 *
79 * // Teeny editor (minimal toolbar)
80 * WPEditor::make()
81 * ->name( 'short_bio' )
82 * ->label( 'Short Bio' )
83 * ->editor_config( array( 'teeny' => true, 'media_buttons' => false ) )
84 * ->render();
85 *
86 * // Custom wrapper attribute (e.g., Alpine.js show binding)
87 * WPEditor::make()
88 * ->name( 'notes' )
89 * ->label( 'Notes' )
90 * ->wrapper_attr( 'x-show', 'showNotes' )
91 * ->render();
92 *
93 * // With explicit editor ID
94 * WPEditor::make()
95 * ->name( 'content' )
96 * ->id( 'my-custom-editor-id' )
97 * ->render();
98 *
99 * // Retrieve HTML without echoing
100 * $html = WPEditor::make()->name( 'description' )->content( $saved_content )->get();
101 * ```
102 *
103 * @since 4.0.0
104 */
105 class WPEditor extends BaseComponent {
106
107 /**
108 * Editor name attribute (also used as editor ID if ID is not set).
109 *
110 * @since 4.0.0
111 *
112 * @var string
113 */
114 protected $name = '';
115
116 /**
117 * Editor ID attribute.
118 *
119 * @since 4.0.0
120 *
121 * @var string
122 */
123 protected $id = '';
124
125 /**
126 * Editor content.
127 *
128 * @since 4.0.0
129 *
130 * @var string
131 */
132 protected $content = '';
133
134 /**
135 * Editor label text.
136 *
137 * @since 4.0.0
138 *
139 * @var string
140 */
141 protected $label = '';
142
143 /**
144 * Editor placeholder text.
145 *
146 * @since 4.0.0
147 *
148 * @var string
149 */
150 protected $placeholder = '';
151
152 /**
153 * Help text below editor.
154 *
155 * @since 4.0.0
156 *
157 * @var string
158 */
159 protected $help_text = '';
160
161 /**
162 * Error message text.
163 *
164 * @since 4.0.0
165 *
166 * @var string
167 */
168 protected $error = '';
169
170 /**
171 * Whether editor is required.
172 *
173 * @since 4.0.0
174 *
175 * @var bool
176 */
177 protected $required = false;
178
179 /**
180 * WordPress editor configuration.
181 *
182 * @since 4.0.0
183 *
184 * @var array
185 */
186 protected $editor_config = array();
187
188 /**
189 * Set editor name.
190 *
191 * @since 4.0.0
192 *
193 * @param string $name Editor name.
194 *
195 * @return $this
196 */
197 public function name( $name ) {
198 $this->name = sanitize_key( $name );
199 return $this;
200 }
201
202 /**
203 * Set editor ID.
204 *
205 * @since 4.0.0
206 *
207 * @param string $id Editor ID.
208 *
209 * @return $this
210 */
211 public function id( $id ) {
212 $this->id = sanitize_key( $id );
213 return $this;
214 }
215
216 /**
217 * Set editor content.
218 *
219 * @since 4.0.0
220 *
221 * @param string $content Editor content.
222 *
223 * @return $this
224 */
225 public function content( $content ) {
226 $this->content = $content;
227 return $this;
228 }
229
230 /**
231 * Set editor label.
232 *
233 * @since 4.0.0
234 *
235 * @param string $label Label text.
236 *
237 * @return $this
238 */
239 public function label( $label ) {
240 $this->label = $label;
241 return $this;
242 }
243
244 /**
245 * Set editor placeholder.
246 *
247 * @since 4.0.0
248 *
249 * @param string $placeholder Placeholder text.
250 *
251 * @return $this
252 */
253 public function placeholder( $placeholder ) {
254 $this->placeholder = $placeholder;
255 return $this;
256 }
257
258 /**
259 * Set help text.
260 *
261 * @since 4.0.0
262 *
263 * @param string $text Help text.
264 *
265 * @return $this
266 */
267 public function help_text( $text ) {
268 $this->help_text = $text;
269 return $this;
270 }
271
272 /**
273 * Set error message.
274 *
275 * @since 4.0.0
276 *
277 * @param string $error Error message.
278 *
279 * @return $this
280 */
281 public function error( $error ) {
282 $this->error = $error;
283 return $this;
284 }
285
286 /**
287 * Set required state.
288 *
289 * @since 4.0.0
290 *
291 * @param bool $required Whether editor is required.
292 *
293 * @return $this
294 */
295 public function required( $required = true ) {
296 $this->required = $required;
297 return $this;
298 }
299
300 /**
301 * Set WordPress editor configuration.
302 *
303 * @since 4.0.0
304 *
305 * @param array $config Editor configuration.
306 *
307 * @return $this
308 */
309 public function editor_config( $config ) {
310 $this->editor_config = $config;
311 return $this;
312 }
313
314 /**
315 * Get default editor configuration.
316 *
317 * @since 4.0.0
318 *
319 * @return array
320 */
321 protected function get_default_config() {
322 return array(
323 'media_buttons' => false,
324 'teeny' => true,
325 'quicktags' => true,
326 'editor_height' => 150,
327 'textarea_name' => $this->name,
328 'tinymce' => array(
329 'skin' => 'light',
330 'skin_url' => UrlHelper::asset( 'lib/tinymce/light' ),
331 'content_css' => $this->get_content_css(),
332 ),
333 );
334 }
335
336 /**
337 * Get TinyMCE content styles used inside the editor iframe.
338 *
339 * Mirrors the stylesheet list used by the React WPEditor component so both
340 * entry points render editor content consistently.
341 *
342 * @since 4.0.0
343 *
344 * @return string
345 */
346 protected function get_content_css() {
347 return implode(
348 ',',
349 array(
350 includes_url( 'css/dashicons.min.css' ),
351 includes_url( 'js/tinymce/skins/wordpress/wp-content.css' ),
352 UrlHelper::asset( 'lib/tinymce/light/content.min.css' ),
353 )
354 );
355 }
356
357 /**
358 * Attributes for the wrapper element.
359 *
360 * @since 4.0.0
361 *
362 * @var array
363 */
364 protected $wrapper_attr = array();
365
366 /**
367 * Set wrapper attribute.
368 *
369 * @since 4.0.0
370 *
371 * @param string $key Attribute key.
372 * @param string $value Attribute value.
373 *
374 * @return $this
375 */
376 public function wrapper_attr( $key, $value ) {
377 $this->wrapper_attr[ $key ] = $value;
378 return $this;
379 }
380
381 /**
382 * Get the editor component as HTML string.
383 *
384 * @since 4.0.0
385 *
386 * @return string Component HTML.
387 */
388 public function get(): string {
389 if ( empty( $this->name ) ) {
390 return '';
391 }
392
393 ob_start();
394
395 $editor_id = ! empty( $this->id ) ? $this->id : $this->name;
396 $default_config = $this->get_default_config();
397 $config = array_merge( $default_config, $this->editor_config );
398
399 if ( isset( $default_config['tinymce'] ) || isset( $this->editor_config['tinymce'] ) ) {
400 $config['tinymce'] = array_merge(
401 $default_config['tinymce'] ?? array(),
402 $this->editor_config['tinymce'] ?? array()
403 );
404 }
405 $wrapper_class = 'tutor-wp-editor-wrapper tutor-input-field';
406
407 if ( isset( $this->attributes['class'] ) ) {
408 $wrapper_class .= ' ' . $this->attributes['class'];
409 }
410 if ( isset( $this->wrapper_attr['class'] ) ) {
411 $wrapper_class .= ' ' . $this->wrapper_attr['class'];
412 }
413
414 if ( ! empty( $this->error ) ) {
415 $wrapper_class .= ' tutor-wp-editor-error tutor-input-field-error';
416 }
417
418 $wrapper_attrs = $this->wrapper_attr;
419
420 $wrapper_attrs['class'] = $wrapper_class;
421
422 ?>
423 <div
424 <?php
425 foreach ( $wrapper_attrs as $key => $value ) {
426 printf( '%s="%s"', esc_attr( $key ), esc_attr( $value ) );
427 }
428 ?>
429 x-data="tutorWPEditor({
430 name: '<?php echo esc_js( $this->name ); ?>',
431 editorId: '<?php echo esc_js( $editor_id ); ?>',
432 placeholder: '<?php echo esc_js( $this->placeholder ); ?>'
433 })"
434 >
435 <?php if ( ! empty( $this->label ) ) : ?>
436 <label
437 for="<?php echo esc_attr( $editor_id ); ?>"
438 class="tutor-label <?php echo $this->required ? 'tutor-label-required' : ''; ?>"
439 >
440 <?php echo esc_html( $this->label ); ?>
441 </label>
442 <?php endif; ?>
443
444 <div class="tutor-wp-editor-container">
445 <!-- Hidden input for form value binding -->
446 <input
447 type="hidden"
448 name="<?php echo esc_attr( $this->name ); ?>"
449 <?php $this->render_attributes(); ?>
450 />
451
452 <?php
453 // Render WordPress editor.
454 wp_editor( $this->content, $editor_id, $config );
455 ?>
456 </div>
457
458 <!-- Error Text (Alpine + PHP) -->
459 <div
460 class="tutor-error-text"
461 x-cloak
462 x-show="errors?.['<?php echo esc_js( $this->name ); ?>']"
463 x-text="errors?.['<?php echo esc_js( $this->name ); ?>']?.message"
464 role="alert"
465 aria-live="polite"
466 >
467 <?php echo esc_html( $this->error ); ?>
468 </div>
469
470 <!-- Help Text -->
471 <?php if ( ! empty( $this->help_text ) ) : ?>
472 <div
473 class="tutor-help-text"
474 x-show="!errors?.['<?php echo esc_js( $this->name ); ?>']?.message"
475 >
476 <?php echo esc_html( $this->help_text ); ?>
477 </div>
478 <?php endif; ?>
479 </div>
480 <?php
481
482 return ob_get_clean();
483 }
484 }
485