From 861a5f271a4aa3cc631857443fc782bcf9335e08 Mon Sep 17 00:00:00 2001 From: Sazedul Haque Date: Mon, 13 Jul 2026 16:34:26 +0600 Subject: [PATCH] Example Usage comment updated for all PHP components --- components/Accordion.php | 42 ++++-- components/Alert.php | 39 +++++- components/AttachmentCard.php | 28 +++- components/Avatar.php | 44 +++++-- components/Badge.php | 40 +++++- components/Button.php | 80 +++++++++++- components/ConfirmationModal.php | 51 +++++++- components/CourseFilter.php | 17 ++- components/DateFilter.php | 49 ++++++- components/DropdownFilter.php | 54 +++++++- components/EmptyState.php | 32 ++++- components/FileUploader.php | 50 ++++--- components/InputField.php | 217 +++++++++++++++++++++++++++---- components/Modal.php | 59 +++++++-- components/Nav.php | 83 +++++++----- components/Pagination.php | 53 ++++++-- components/Popover.php | 94 ++++++++++--- components/PreviewTrigger.php | 13 +- components/Progress.php | 65 ++++++++- components/SearchFilter.php | 50 +++++-- components/Sorting.php | 36 ++++- components/StarRating.php | 42 +++++- components/StarRatingInput.php | 34 ++++- components/StatusSelect.php | 51 ++++++-- components/SvgIcon.php | 46 ++++++- components/Table.php | 125 +++++++++++------- components/Tabs.php | 75 +++++++---- components/Tooltip.php | 72 +++++++++- components/WPEditor.php | 86 ++++++++---- 29 files changed, 1443 insertions(+), 284 deletions(-) diff --git a/components/Accordion.php b/components/Accordion.php index 36708cc0ae..3c1ca48ac6 100644 --- a/components/Accordion.php +++ b/components/Accordion.php @@ -27,7 +27,7 @@ * ->add_item( 'About Course', '

Description...

' ) * ->render(); * - * // Multiple items + * // Multiple items, first open by default * Accordion::make() * ->add_item( 'About Course', '

Description...

' ) * ->add_item( 'Requirements', '

Prerequisites...

' ) @@ -35,11 +35,38 @@ * ->default_open( array( 0 ) ) * ->render(); * - * // With custom icon and template + * // Multiple items open by default (indices 0 and 2) * Accordion::make() - * ->add_item( 'Details', '', 'path/to/template.php', 'custom-icon' ) + * ->add_item( 'Overview', '

Course overview...

' ) + * ->add_item( 'Curriculum', '

Topics covered...

' ) + * ->add_item( 'FAQ', '

Common questions...

' ) + * ->default_open( array( 0, 2 ) ) + * ->render(); + * + * // Only one item open at a time (allow_multiple = false) + * Accordion::make() + * ->add_item( 'Section 1', '

Content 1...

' ) + * ->add_item( 'Section 2', '

Content 2...

' ) * ->allow_multiple( false ) * ->render(); + * + * // With custom icon per item + * Accordion::make() + * ->add_item( 'Resources', '', '', Icon::RESOURCES ) + * ->add_item( 'Downloads', '', '', Icon::DOWNLOAD_2 ) + * ->render(); + * + * // With a PHP template file as content + * Accordion::make() + * ->add_item( 'Details', '', get_template_directory() . '/partials/details.php' ) + * ->render(); + * + * // Extra HTML attributes on the wrapper + * Accordion::make() + * ->add_item( 'Notes', '

Some notes...

' ) + * ->attr( 'id', 'course-accordion' ) + * ->attr( 'class', 'my-custom-class' ) + * ->render(); * ``` * * @since 4.0.0 @@ -189,7 +216,7 @@ public function get(): string { 'multiple' => $this->multiple, 'defaultOpen' => $this->default_open, ); - $alpine_json = wp_json_encode( $alpine_config ); + $alpine_json = wp_json_encode( $alpine_config ); // Merge custom classes. $wrapper_classes = 'tutor-accordion'; @@ -206,9 +233,9 @@ public function get(): string { // Build items HTML. $items_html = ''; foreach ( $this->items as $index => $item ) { - $title = isset( $item['title'] ) ? $item['title'] : ''; - $icon = isset( $item['icon'] ) ? $item['icon'] : ''; - $panel_id = 'tutor-acc-panel-' . $index; + $title = isset( $item['title'] ) ? $item['title'] : ''; + $icon = isset( $item['icon'] ) ? $item['icon'] : ''; + $panel_id = 'tutor-acc-panel-' . $index; $trigger_id = 'tutor-acc-trigger-' . $index; $icon_html = $this->render_icon( $icon ); @@ -262,5 +289,4 @@ class="tutor-accordion-content" $items_html ); } - } diff --git a/components/Alert.php b/components/Alert.php index 6b864babf6..d03ba8ca82 100644 --- a/components/Alert.php +++ b/components/Alert.php @@ -20,11 +20,46 @@ * * Example usage: * ``` + * // Default (neutral) alert * Alert::make() - * ->text( 'This is an alert' ) + * ->text( 'Your changes have been saved.' ) + * ->render(); + * + * // Success alert with icon + * Alert::make() + * ->text( 'Course published successfully.' ) * ->variant( Alert::SUCCESS ) * ->icon( Icon::PRIME_CHECK_CIRCLE ) - * ->action( '' ) + * ->render(); + * + * // Info alert with action button + * Alert::make() + * ->text( 'You have an incomplete quiz. Resume where you left off.' ) + * ->variant( Alert::INFO ) + * ->icon( Icon::INFO ) + * ->action( '' ) + * ->render(); + * + * // Warning alert + * Alert::make() + * ->text( 'Your subscription expires in 3 days.' ) + * ->variant( Alert::WARNING ) + * ->icon( Icon::WARNING ) + * ->render(); + * + * // Error alert with custom icon size + * Alert::make() + * ->text( 'Payment failed. Please try again.' ) + * ->variant( Alert::ERROR ) + * ->icon( Icon::CLOSE_CIRCLE, 24, 24 ) + * ->render(); + * + * // Alert with extra HTML attributes + * Alert::make() + * ->text( 'Draft saved.' ) + * ->variant( Alert::SUCCESS ) + * ->attr( 'id', 'draft-alert' ) + * ->attr( 'x-show', 'showAlert' ) * ->render(); * ``` * diff --git a/components/AttachmentCard.php b/components/AttachmentCard.php index 53aeb7ef66..a978991994 100644 --- a/components/AttachmentCard.php +++ b/components/AttachmentCard.php @@ -18,13 +18,39 @@ * Class AttachmentCard * * Example Usage: + * ```php + * // Basic downloadable attachment * AttachmentCard::make() * ->file_name( 'lesson-plan.pdf' ) - * ->file_size( '1.2 MB' ) + * ->file_size( '1258291' ) // bytes — size_format() is applied internally * ->is_downloadable( true ) * ->action_attr( '@click', 'downloadFile()' ) * ->render(); * + * // Removable attachment (delete icon) + * AttachmentCard::make() + * ->file_name( 'assignment.docx' ) + * ->file_size( '524288' ) + * ->is_downloadable( false ) + * ->action_attr( '@click', 'removeFile(index)' ) + * ->render(); + * + * // With Alpine.js dynamic bindings on title and meta + * AttachmentCard::make() + * ->title_attr( 'x-text', 'file.name' ) + * ->meta_attr( 'x-text', 'formatBytes(file.size)' ) + * ->action_attr( '@click.stop', 'removeFile(index)' ) + * ->render(); + * + * // With extra attributes on the wrapper + * AttachmentCard::make() + * ->file_name( 'course-notes.pdf' ) + * ->file_size( '2097152' ) + * ->is_downloadable( true ) + * ->attr( 'data-id', '42' ) + * ->render(); + * ``` + * * @since 4.0.0 */ class AttachmentCard extends BaseComponent { diff --git a/components/Avatar.php b/components/Avatar.php index 345621d01d..66aac27efc 100644 --- a/components/Avatar.php +++ b/components/Avatar.php @@ -24,25 +24,49 @@ * Example usage: * * ```php - * Avatar with user object/ID + * // Avatar from a WP user ID (auto-resolves photo or initials) * Avatar::make() - * ->user($user_id) - * ->size(Size::SIZE_56) + * ->user( $user_id ) + * ->size( Size::SIZE_56 ) * ->render(); * - * Avatar with image source + * // Avatar from a WP_User object * Avatar::make() - * ->src('https://example.com/avatar.jpg') - * ->size(Size::SIZE_20) + * ->user( $user ) + * ->size( Size::SIZE_40 ) * ->bordered() * ->render(); * - * Avatar with initials + * // Avatar with explicit image URL * Avatar::make() - * ->initials('SK') - * ->size(Size::SIZE_32) - * ->rounded(false) + * ->src( 'https://example.com/avatar.jpg' ) + * ->alt( 'John Doe' ) + * ->size( Size::SIZE_32 ) * ->render(); + * + * // Avatar with initials fallback only + * Avatar::make() + * ->initials( 'JD' ) + * ->size( Size::SIZE_48 ) + * ->render(); + * + * // Avatar with square shape (no border-radius) + * Avatar::make() + * ->user( $user_id ) + * ->size( Size::SIZE_64 ) + * ->shape( 'square' ) + * ->render(); + * + * // Avatar with border and custom attributes + * Avatar::make() + * ->src( 'https://example.com/pic.jpg' ) + * ->size( Size::SIZE_20 ) + * ->bordered() + * ->attr( 'data-user-id', $user_id ) + * ->render(); + * + * // Retrieve HTML string without echoing + * $html = Avatar::make()->user( $user_id )->size( Size::SIZE_24 )->get(); * ``` * * @since 4.0.0 diff --git a/components/Badge.php b/components/Badge.php index a554e0cf6a..07d3b6bf52 100644 --- a/components/Badge.php +++ b/components/Badge.php @@ -20,16 +20,54 @@ * * Example usage: * ``` + * // Primary badge * Badge::make() - * ->label( 'Primary' ) + * ->label( 'New' ) * ->variant( Badge::PRIMARY ) + * ->render(); + * + * // Badge with SVG icon markup + * Badge::make() + * ->label( 'Certified' ) + * ->variant( Badge::SUCCESS ) * ->icon( '...' ) * ->render(); * + * // Badge with icon name (SvgIcon slug) + * Badge::make() + * ->label( 'Warning' ) + * ->variant( Badge::WARNING ) + * ->icon( Icon::WARNING, 14, 14 ) + * ->render(); + * + * // Badge with icon as URL (img tag is generated) + * Badge::make() + * ->label( 'Verified' ) + * ->variant( Badge::SUCCESS_SOLID ) + * ->icon( 'https://example.com/check.png', 16, 16 ) + * ->render(); + * + * // Rounded (pill) badge * Badge::make() * ->label( 'Points: 20' ) + * ->variant( Badge::HIGHLIGHT ) * ->rounded() * ->render(); + * + * // Error / disabled badge without icon + * Badge::make() + * ->label( 'Inactive' ) + * ->variant( Badge::DISABLED ) + * ->render(); + * + * // Badge with no variant (default style) and extra attrs + * Badge::make() + * ->label( 'Draft' ) + * ->attr( 'data-status', 'draft' ) + * ->render(); + * + * // Retrieve HTML string without echoing + * $html = Badge::make()->label( 'Info' )->variant( Badge::INFO )->get(); * ``` * * @since 4.0.0 diff --git a/components/Button.php b/components/Button.php index 761fb4943f..4dbc310f26 100644 --- a/components/Button.php +++ b/components/Button.php @@ -15,7 +15,6 @@ use Tutor\Components\Constants\Size; use Tutor\Components\Constants\Variant; -use Tutor\Components\Constants\Color; defined( 'ABSPATH' ) || exit; @@ -24,13 +23,87 @@ * * Example usage: * ``` + * // Primary button (default) * Button::make() * ->label( 'Enroll Now' ) + * ->render(); + * + * // Button with size and variant + * Button::make() + * ->label( 'Save Changes' ) * ->size( Size::LARGE ) * ->variant( Variant::PRIMARY ) - * ->icon( 'tutor-icon-play' ) - * ->attr( 'data-id', 101 ) * ->render(); + * + * // Button with left icon + * Button::make() + * ->label( 'Add Course' ) + * ->icon( Icon::PLUS ) + * ->size( Size::MEDIUM ) + * ->variant( Variant::PRIMARY ) + * ->render(); + * + * // Button with right icon and custom icon size/color + * Button::make() + * ->label( 'Download' ) + * ->icon( Icon::DOWNLOAD_2, 'right', 18, Color::BRAND ) + * ->variant( Variant::OUTLINE ) + * ->render(); + * + * // Icon-only button (no visible label, uses aria-label) + * Button::make() + * ->label( 'Delete' ) + * ->icon( Icon::DELETE_2 ) + * ->icon_only() + * ->variant( Variant::GHOST ) + * ->size( Size::SMALL ) + * ->render(); + * + * // Disabled button + * Button::make() + * ->label( 'Submit' ) + * ->variant( Variant::PRIMARY ) + * ->disabled() + * ->render(); + * + * // Block (full-width) button + * Button::make() + * ->label( 'Continue' ) + * ->variant( Variant::PRIMARY ) + * ->block() + * ->render(); + * + * // Link-styled button rendered as tag + * Button::make() + * ->label( 'View Course' ) + * ->variant( Variant::LINK ) + * ->tag( 'a' ) + * ->attr( 'href', get_permalink( $course_id ) ) + * ->render(); + * + * // Destructive button + * Button::make() + * ->label( 'Delete Course' ) + * ->variant( Variant::DESTRUCTIVE ) + * ->size( Size::SMALL ) + * ->render(); + * + * // Secondary/outline button with data attribute + * Button::make() + * ->label( 'Cancel' ) + * ->variant( Variant::SECONDARY ) + * ->attr( 'data-id', $course_id ) + * ->render(); + * + * // Button with RTL-flippable directional icon + * Button::make() + * ->label( 'Next' ) + * ->icon( Icon::CHEVRON_RIGHT, 'right' ) + * ->flip_rtl() + * ->render(); + * + * // Retrieve HTML string without echoing + * $html = Button::make()->label( 'Get Started' )->variant( Variant::PRIMARY )->get(); * ``` * * @since 4.0.0 @@ -403,5 +476,4 @@ public function get(): string { return $this->component_string; } - } diff --git a/components/ConfirmationModal.php b/components/ConfirmationModal.php index 37d0025a85..d477917992 100644 --- a/components/ConfirmationModal.php +++ b/components/ConfirmationModal.php @@ -20,8 +20,7 @@ * Confirmation Modal Component Class. * * ``` - * // Example usage: - * + * // Basic delete confirmation * ConfirmationModal::make() * ->id( 'delete-course-modal' ) * ->title( 'Delete This Course?' ) @@ -30,14 +29,58 @@ * ->mutation_state( 'deleteMutation' ) * ->render(); * - * // With custom icon + * // With custom icon (icon name from Icon class) * ConfirmationModal::make() * ->id( 'delete-announcement-modal' ) * ->title( 'Delete This Announcement?' ) * ->message( 'This action cannot be undone.' ) - * ->icon( Icon::DELETE_2, 80 ) + * ->icon( Icon::DELETE_2, 80, 80 ) * ->confirm_handler( 'handleDeleteAnnouncement(payload?.announcementId)' ) * ->render(); + * + * // With icon as URL (img will be generated) + * ConfirmationModal::make() + * ->id( 'remove-student-modal' ) + * ->title( 'Remove Student?' ) + * ->message( 'The student will lose access to this course.' ) + * ->icon( 'https://example.com/icons/warning.svg', 100, 100 ) + * ->render(); + * + * // With custom button text + * ConfirmationModal::make() + * ->id( 'publish-course-modal' ) + * ->title( 'Publish Course?' ) + * ->message( 'The course will be visible to all students.' ) + * ->cancel_text( 'Not Yet' ) + * ->confirm_text( 'Publish Now' ) + * ->confirm_handler( 'publishCourse()' ) + * ->render(); + * + * // With custom modal width + * ConfirmationModal::make() + * ->id( 'wide-confirm-modal' ) + * ->title( 'Reset All Progress?' ) + * ->message( 'This will permanently reset all student progress records.' ) + * ->width( '520px' ) + * ->confirm_handler( 'resetProgress()' ) + * ->render(); + * + * // With fully custom confirm / cancel buttons + * ConfirmationModal::make() + * ->id( 'custom-btn-modal' ) + * ->title( 'Archive Course?' ) + * ->message( 'The course will be hidden from the catalog.' ) + * ->confirm_button( '' ) + * ->cancel_button( '' ) + * ->render(); + * + * // With inline HTML in the message (allowed tags) + * ConfirmationModal::make() + * ->id( 'delete-review-modal' ) + * ->title( 'Delete Review?' ) + * ->message( 'You are about to delete the review by .' ) + * ->confirm_handler( 'deleteReview(payload?.reviewId)' ) + * ->render(); * ``` * * @since 4.0.0 diff --git a/components/CourseFilter.php b/components/CourseFilter.php index 60af6fc4fc..975d2a74aa 100644 --- a/components/CourseFilter.php +++ b/components/CourseFilter.php @@ -23,11 +23,24 @@ * Class CourseFilter * * Example Usage: - * ``` + * ```php + * // Minimal — auto-fetches courses for the current user + * CourseFilter::make() + * ->render(); + * + * // With explicit courses list and total count * CourseFilter::make() * ->courses( $courses ) * ->count( $total_announcements ) * ->render(); + * + * // Pre-populate options from a custom courses array + * CourseFilter::make() + * ->courses( CourseModel::get_courses_by_instructor() ) + * ->render(); + * + * // Retrieve HTML without echoing + * $html = CourseFilter::make()->courses( $courses )->get(); * ``` * * @since 4.0.0 @@ -93,7 +106,7 @@ public static function get_course_filter_options( $courses = null ) { ); if ( null === $courses ) { - $courses = current_user_can( 'administrator' ) ? CourseModel::get_courses() : CourseModel::get_courses_by_instructor(); + $courses = current_user_can( 'manage_options' ) ? CourseModel::get_courses() : CourseModel::get_courses_by_instructor(); } if ( ! empty( $courses ) ) { diff --git a/components/DateFilter.php b/components/DateFilter.php index 1c948b6a86..143ea8dfdd 100644 --- a/components/DateFilter.php +++ b/components/DateFilter.php @@ -23,17 +23,58 @@ * Example usage: * * ```php + * // Single-date picker (bottom-start) + * DateFilter::make() + * ->type( DateFilter::TYPE_SINGLE ) + * ->render(); + * + * // Date-range picker (bottom-start, default) * DateFilter::make() * ->type( DateFilter::TYPE_RANGE ) - * ->placement( DateFilter::PLACEMENT_BOTTOM_START ) * ->render(); - * ``` * - * ```php + * // Date-range picker positioned at bottom-end * DateFilter::make() - * ->type( DateFilter::TYPE_SINGLE ) + * ->type( DateFilter::TYPE_RANGE ) * ->placement( DateFilter::PLACEMENT_BOTTOM_END ) * ->render(); + * + * // With a custom button label + * DateFilter::make() + * ->type( DateFilter::TYPE_RANGE ) + * ->label( 'Filter by date' ) + * ->render(); + * + * // Hide the initial label (show only icon until a range is selected) + * DateFilter::make() + * ->type( DateFilter::TYPE_RANGE ) + * ->hide_initial_label() + * ->render(); + * + * // Suppress label text entirely (icon-only button) + * DateFilter::make() + * ->type( DateFilter::TYPE_RANGE ) + * ->show_label( false ) + * ->render(); + * + * // Custom trigger button size and icon size + * DateFilter::make() + * ->type( DateFilter::TYPE_RANGE ) + * ->trigger_size( Size::X_SMALL ) + * ->icon_size( 14 ) + * ->render(); + * + * // Clear related query params when the filter changes (e.g. reset pagination) + * DateFilter::make() + * ->type( DateFilter::TYPE_RANGE ) + * ->clear_params( array( 'current_page' ) ) + * ->render(); + * + * // Extra attributes on the wrapper + * DateFilter::make() + * ->type( DateFilter::TYPE_SINGLE ) + * ->attr( 'id', 'my-date-filter' ) + * ->render(); * ``` * * @since 4.0.0 diff --git a/components/DropdownFilter.php b/components/DropdownFilter.php index 73e552dff7..a564deedb6 100644 --- a/components/DropdownFilter.php +++ b/components/DropdownFilter.php @@ -24,26 +24,70 @@ * Class DropdownFilter * * Example Usage: - * ``` - * // Basic dropdown with custom options + * ```php + * // Basic dropdown bound to URL query param (link-based navigation) + * DropdownFilter::make() + * ->options( $options ) + * ->query_param( 'status' ) + * ->render(); + * + * // With custom variant, size and search box * DropdownFilter::make() * ->options( $options ) * ->query_param( 'status' ) * ->variant( Variant::PRIMARY ) * ->size( Size::SMALL ) * ->search( true ) + * ->placeholder( __( 'Search status...', 'tutor' ) ) * ->render(); * - * // Course filter (convenience method) + * // JS callback on change (Alpine.js method name) instead of link navigation * DropdownFilter::make() - * ->options( $courses ) + * ->options( $options ) + * ->on_change( 'changeStatus' ) + * ->bind_active_value( 'currentStatus' ) + * ->render(); + * + * // Course filter convenience use-case + * DropdownFilter::make() + * ->options( CourseFilter::get_course_filter_options() ) * ->count( $total_items ) - * ->query_param( 'course_id' ) + * ->query_param( 'course-id' ) * ->variant( Variant::PRIMARY_SOFT ) * ->size( Size::X_SMALL ) * ->popover_size( Size::MEDIUM ) * ->position( Positions::BOTTOM_END ) * ->placeholder( __( 'Search Course', 'tutor' ) ) + * ->search( true ) + * ->render(); + * + * // Cumulative filtering — preserve existing query params via base_url + * DropdownFilter::make() + * ->options( $options ) + * ->query_param( 'category' ) + * ->base_url( remove_query_arg( 'current_page' ) ) + * ->render(); + * + * // Outline variant with custom button CSS + * DropdownFilter::make() + * ->options( $options ) + * ->variant( Variant::OUTLINE ) + * ->button_class( 'tutor-btn tutor-btn-outline tutor-btn-small my-custom-btn' ) + * ->render(); + * + * // Popover positioned bottom-end with large width + * DropdownFilter::make() + * ->options( $options ) + * ->query_param( 'type' ) + * ->position( Positions::BOTTOM_END ) + * ->popover_size( Size::LARGE ) + * ->render(); + * + * // Custom icon size for the chevron + * DropdownFilter::make() + * ->options( $options ) + * ->variant( Variant::PRIMARY ) + * ->icon_size( 14 ) * ->render(); * ``` * diff --git a/components/EmptyState.php b/components/EmptyState.php index 69251263f7..5925e81bdc 100644 --- a/components/EmptyState.php +++ b/components/EmptyState.php @@ -19,12 +19,40 @@ * Class EmptyState * * Example Usage: - * ``` + * ```php + * // Basic empty state (default icon and subtitle) + * EmptyState::make() + * ->title( 'No Courses Found' ) + * ->render(); + * + * // With title and subtitle * EmptyState::make() * ->title( 'No Data' ) * ->subtitle( 'Please check back later.' ) - * ->icon_path( 'path/to/icon.png' ) * ->render(); + * + * // With an image URL as icon + * EmptyState::make() + * ->title( 'No Announcements' ) + * ->subtitle( 'You have not posted any announcements yet.' ) + * ->icon_path( tutor()->url . 'assets/images/empty-announcements.svg' ) + * ->render(); + * + * // With raw SVG/HTML markup as icon + * EmptyState::make() + * ->title( 'No Results' ) + * ->icon( '...' ) + * ->render(); + * + * // With extra CSS class on the wrapper + * EmptyState::make() + * ->title( 'Nothing Here Yet' ) + * ->subtitle( 'Start by creating your first course.' ) + * ->attr( 'class', 'tutor-mt-10' ) + * ->render(); + * + * // Retrieve HTML without echoing + * $html = EmptyState::make()->title( 'No Reviews' )->get(); * ``` * * @since 4.0.0 diff --git a/components/FileUploader.php b/components/FileUploader.php index 7c998ca12d..fcaceddedf 100644 --- a/components/FileUploader.php +++ b/components/FileUploader.php @@ -22,32 +22,43 @@ /** * Class FileUploader * - * Example Usage (Native Multiple): + * Example Usage: + * ```php + * // Native single-file upload + * FileUploader::make() + * ->name( 'resume' ) + * ->accept( '.pdf,.doc' ) + * ->render(); + * + * // Native multiple-file upload with size/count limits * FileUploader::make() * ->name( 'course_attachments' ) * ->uploader_title( __( 'Upload Assignments', 'tutor' ) ) - * ->uploader_subtitle( __( 'Support PDF, DOCX (Max 20MB)', 'tutor' ) ) + * ->uploader_subtitle( __( 'Supports PDF, DOCX — max 20 MB each', 'tutor' ) ) * ->accept( '.pdf,.docx' ) * ->multiple( true ) * ->max_files( 3 ) * ->max_size( 20 * 1024 * 1024 ) * ->render(); * - * Example Usage (Native Single): + * // Image uploader (native file input, image preview variant) * FileUploader::make() - * ->name( 'resume' ) - * ->accept( '.pdf,.doc' ) + * ->variant( FileUploader::IMAGE_UPLOADER ) + * ->name( 'cover_photo' ) + * ->accept( '.jpg,.jpeg,.png,.webp' ) * ->render(); * - * Example Usage (WP Media Image): + * // WP Media Library — single image * FileUploader::make() * ->variant( FileUploader::IMAGE_UPLOADER ) * ->use_wp_media( true ) * ->wp_media_library_type( 'image' ) + * ->wp_media_title( __( 'Select Profile Photo', 'tutor' ) ) + * ->wp_media_button_text( __( 'Use This Photo', 'tutor' ) ) * ->name( 'profile_photo' ) * ->render(); * - * Example Usage (WP Media Multiple Documents): + * // WP Media Library — multiple documents * FileUploader::make() * ->use_wp_media( true ) * ->multiple( true ) @@ -55,21 +66,30 @@ * ->name( 'shared_files' ) * ->render(); * - * Example Usage (Native Image): + * // Custom icon, title, subtitle and button text * FileUploader::make() - * ->variant( FileUploader::IMAGE_UPLOADER ) - * ->name( 'cover_photo' ) - * ->render(); - * - * Example Usage (Custom UI): - * FileUploader::make() - * ->name( 'custom_upload' ) + * ->name( 'resources' ) * ->uploader_icon( Icon::RESOURCES ) + * ->uploader_icon_size( 32 ) * ->uploader_title( __( 'Resource Center', 'tutor' ) ) * ->uploader_subtitle( __( 'Add any relevant documents here', 'tutor' ) ) * ->uploader_button_text( __( 'Choose Resources', 'tutor' ) ) * ->render(); * + * // Required upload with an ID and Alpine.js callbacks + * FileUploader::make() + * ->name( 'assignment_file' ) + * ->id( 'assignment-upload' ) + * ->required( true ) + * ->accept( '.pdf' ) + * ->attr( 'onFileSelect', 'handleFileSelect' ) + * ->attr( 'onError', 'handleUploadError' ) + * ->render(); + * + * // Retrieve HTML without echoing + * $html = FileUploader::make()->name( 'attachment' )->get(); + * ``` + * * @since 4.0.0 */ class FileUploader extends BaseComponent { diff --git a/components/InputField.php b/components/InputField.php index 89391dbccf..5dd44ecbd0 100644 --- a/components/InputField.php +++ b/components/InputField.php @@ -24,8 +24,16 @@ * InputField Component Class. * * Example usage: - * ``` - * // Text input with clear button + * ```php + * // Plain text input with label + * InputField::make() + * ->type( 'text' ) + * ->name( 'full_name' ) + * ->label( 'Full Name' ) + * ->placeholder( 'Enter your full name' ) + * ->render(); + * + * // Required text input with clear button and help text * InputField::make() * ->type( 'text' ) * ->name( 'full_name' ) @@ -33,8 +41,16 @@ * ->placeholder( 'Enter your full name' ) * ->required() * ->clearable() - * ->help_text( 'This is a helper text.' ) - * ->attr( 'x-bind', "register('full_name', { required: 'Name is required', minLength: { value: 2, message: 'Name must be at least 2 characters' } })") + * ->help_text( 'This name will appear on your certificate.' ) + * ->render(); + * + * // Text input with Alpine.js form validation binding + * InputField::make() + * ->type( 'text' ) + * ->name( 'username' ) + * ->label( 'Username' ) + * ->required() + * ->attr( 'x-bind', "register('username', { required: 'Username is required', minLength: { value: 3, message: 'Min 3 characters' } })" ) * ->render(); * * // Text input with left icon @@ -42,7 +58,40 @@ * ->type( 'text' ) * ->name( 'email' ) * ->label( 'Email' ) - * ->left_icon( '...' ) + * ->left_icon( SvgIcon::make()->name( Icon::MAIL )->size( 18 )->get() ) + * ->render(); + * + * // Text input with right icon + * InputField::make() + * ->type( 'text' ) + * ->name( 'website' ) + * ->label( 'Website' ) + * ->right_icon( SvgIcon::make()->name( Icon::LINK )->size( 18 )->get() ) + * ->render(); + * + * // Email input + * InputField::make() + * ->type( 'email' ) + * ->name( 'email_address' ) + * ->label( 'Email Address' ) + * ->placeholder( 'you@example.com' ) + * ->render(); + * + * // Number input + * InputField::make() + * ->type( 'number' ) + * ->name( 'seats' ) + * ->label( 'Seats Available' ) + * ->value( '30' ) + * ->render(); + * + * // Password input with strength meter + * InputField::make() + * ->type( 'password' ) + * ->name( 'new_password' ) + * ->label( 'New Password' ) + * ->show_strength( true ) + * ->min_strength( 3 ) * ->render(); * * // Textarea @@ -50,17 +99,41 @@ * ->type( 'textarea' ) * ->name( 'bio' ) * ->label( 'Bio' ) + * ->placeholder( 'Tell us about yourself...' ) * ->render(); * * // Checkbox * InputField::make() * ->type( 'checkbox' ) * ->name( 'agree' ) - * ->label( 'I agree to terms' ) - * ->size( 'md' ) + * ->label( 'I agree to the terms and conditions' ) + * ->size( Size::MD ) + * ->render(); + * + * // Checkbox with HTML label (e.g., link inside label) + * InputField::make() + * ->type( 'checkbox' ) + * ->name( 'agree' ) + * ->label_html( 'I agree to the Terms' ) + * ->render(); + * + * // Intermediate (indeterminate) checkbox + * InputField::make() + * ->type( 'checkbox' ) + * ->name( 'select_all' ) + * ->label( 'Select All' ) + * ->intermediate( true ) * ->render(); * - * // Radio + * // Pre-checked checkbox + * InputField::make() + * ->type( 'checkbox' ) + * ->name( 'subscribe' ) + * ->label( 'Subscribe to newsletter' ) + * ->checked( true ) + * ->render(); + * + * // Radio button * InputField::make() * ->type( 'radio' ) * ->name( 'gender' ) @@ -68,15 +141,15 @@ * ->value( 'male' ) * ->render(); * - * // Switch + * // Toggle switch * InputField::make() * ->type( 'switch' ) * ->name( 'notifications' ) - * ->label( 'Enable notifications?' ) - * ->size( 'md' ) + * ->label( 'Enable email notifications' ) + * ->size( Size::MD ) * ->render(); * - * // InputField with error + * // Input with error state * InputField::make() * ->type( 'text' ) * ->name( 'username' ) @@ -84,22 +157,114 @@ * ->error( 'This field is required.' ) * ->render(); * - * // Select + * // Disabled input + * InputField::make() + * ->type( 'text' ) + * ->name( 'readonly_field' ) + * ->label( 'Read Only' ) + * ->value( 'Cannot change me' ) + * ->disabled() + * ->render(); + * + * // Loading state (e.g., while async options load) + * InputField::make() + * ->type( 'select' ) + * ->name( 'category' ) + * ->label( 'Category' ) + * ->loading( true ) + * ->loading_message( __( 'Loading categories...', 'tutor' ) ) + * ->render(); + * + * // Single select with flat options list + * InputField::make() + * ->type( 'select' ) + * ->name( 'country' ) + * ->label( 'Country' ) + * ->placeholder( 'Select a country' ) + * ->options( array( + * array( 'label' => 'United States', 'value' => 'us' ), + * array( 'label' => 'United Kingdom', 'value' => 'uk' ), + * array( 'label' => 'Canada', 'value' => 'ca' ), + * ) ) + * ->render(); + * + * // Select with icons and descriptions per option * InputField::make() - * ->type( 'select' ) - * ->name( 'interests' ) - * ->label( 'Interests' ) - * ->placeholder( 'Select your interests') - * ->required( 'Please select an interest') - * ->clearable() - * ->options( $interests ) - * ->multiple() - * ->searchable() - * ->size( 'md' ) - * ->max_selections( 2 ) - * ->help_text( 'This is a helper next.' ) - * ->render(); + * ->type( 'select' ) + * ->name( 'level' ) + * ->label( 'Course Level' ) + * ->options( array( + * array( 'label' => 'Beginner', 'value' => 'beginner', 'icon' => Icon::PLAY_LINE, 'description' => 'No prior knowledge needed' ), + * array( 'label' => 'Intermediate', 'value' => 'intermediate', 'icon' => Icon::BOOK, 'description' => 'Some experience required' ), + * array( 'label' => 'Advanced', 'value' => 'advanced', 'icon' => Icon::GRADUATION, 'description' => 'For experienced learners' ), + * ) ) + * ->render(); + * + * // Multi-select with search, clearable and max selections + * InputField::make() + * ->type( 'select' ) + * ->name( 'interests' ) + * ->label( 'Interests' ) + * ->placeholder( 'Select your interests' ) + * ->required( 'Please select an interest' ) + * ->clearable() + * ->options( $interests ) + * ->multiple() + * ->searchable() + * ->size( Size::MD ) + * ->max_selections( 2 ) + * ->help_text( 'You can pick up to 2 interests.' ) + * ->render(); * + * // Grouped select options + * InputField::make() + * ->type( 'select' ) + * ->name( 'topic' ) + * ->label( 'Topic' ) + * ->groups( array( + * array( + * 'label' => 'Development', + * 'options' => array( + * array( 'label' => 'PHP', 'value' => 'php' ), + * array( 'label' => 'JavaScript', 'value' => 'js' ), + * ), + * ), + * array( + * 'label' => 'Design', + * 'options' => array( + * array( 'label' => 'Figma', 'value' => 'figma' ), + * array( 'label' => 'Illustrator','value' => 'ai' ), + * ), + * ), + * ) ) + * ->render(); + * + * // Select with onChange callback and collapsable on selection + * InputField::make() + * ->type( 'select' ) + * ->name( 'sort_by' ) + * ->label( 'Sort By' ) + * ->options( $sort_options ) + * ->on_change( 'function(value){ handleSortChange(value); }' ) + * ->collapsable( true ) + * ->render(); + * + * // Time picker (12-hour, 15-minute interval) + * InputField::make() + * ->type( 'time' ) + * ->name( 'start_time' ) + * ->label( 'Start Time' ) + * ->selection_time_mode( 12 ) + * ->interval( 15 ) + * ->render(); + * + * // Small-size input + * InputField::make() + * ->type( 'text' ) + * ->name( 'search_term' ) + * ->placeholder( 'Search...' ) + * ->size( Size::SM ) + * ->render(); * ``` * * @since 4.0.0 diff --git a/components/Modal.php b/components/Modal.php index b2b400ed0e..4fe29337ff 100644 --- a/components/Modal.php +++ b/components/Modal.php @@ -18,38 +18,75 @@ * Modal Component Class. * * ``` - * // Example usage: + * // Basic modal with title and body text + * Modal::make() + * ->id( 'confirm-modal' ) + * ->title( 'Confirm Submission' ) + * ->body( '

Are you sure you want to submit this form?

' ) + * ->render(); * + * // Modal with title, subtitle and footer buttons * Modal::make() * ->id( 'confirm-modal' ) * ->title( 'Confirm Submission' ) - * ->subtitle( 'Are you sure you want to submit?' ) - * ->body( 'This action cannot be undone.' ) - * ->footer_buttons( '' ) + * ->subtitle( 'This action cannot be undone.' ) + * ->body( 'All data will be saved permanently.' ) + * ->footer_buttons( + * Button::make()->label( 'Cancel' )->variant( Variant::SECONDARY )->attr( '@click', "TutorCore.modal.closeModal('confirm-modal')" )->get() . + * Button::make()->label( 'Submit' )->variant( Variant::PRIMARY )->get() + * ) * ->footer_alignment( 'right' ) * ->render(); * - * // With template path + * // Modal loaded from a PHP template file * Modal::make() * ->id( 'course-modal' ) * ->title( 'Course Details' ) - * ->template( 'path/to/template.php' ) + * ->template( get_template_directory() . '/partials/course-modal.php', array( 'course_id' => $course_id ) ) * ->render(); * - * // Headless modal (no close button) + * // Non-closeable (headless) modal * Modal::make() * ->id( 'headless-modal' ) * ->closeable( false ) - * ->body( '

Success!

' ) + * ->body( '

Processing payment, please wait...

' ) * ->render(); * - * // Open by default (state is 'closed' by default) + * // Modal open by default (state = 'open') * Modal::make() * ->id( 'welcome-modal' ) - * ->title( 'Welcome' ) - * ->body( 'Please confirm to continue.' ) + * ->title( 'Welcome!' ) + * ->body( 'Please review the onboarding checklist to get started.' ) * ->state( 'open' ) * ->render(); + * + * // Modal with custom width + * Modal::make() + * ->id( 'wide-modal' ) + * ->title( 'Course Builder' ) + * ->body( '
...
' ) + * ->width( '800px' ) + * ->render(); + * + * // Modal with title icon + * Modal::make() + * ->id( 'alert-modal' ) + * ->title( 'Attention Required' ) + * ->title_icon( Icon::WARNING ) + * ->body( 'Your session is about to expire.' ) + * ->render(); + * + * // Footer buttons aligned left + * Modal::make() + * ->id( 'info-modal' ) + * ->title( 'How it works' ) + * ->body( '

Learn more about this feature.

' ) + * ->footer_buttons( Button::make()->label( 'Got it' )->variant( Variant::PRIMARY )->get() ) + * ->footer_alignment( 'left' ) + * ->render(); + * + * // Retrieve HTML without echoing + * $html = Modal::make()->id( 'my-modal' )->title( 'My Modal' )->body( 'Content' )->get(); * ``` * * @since 4.0.0 diff --git a/components/Nav.php b/components/Nav.php index 862532f2e7..47c5a76afa 100644 --- a/components/Nav.php +++ b/components/Nav.php @@ -24,44 +24,59 @@ * Responsible for rendering the nav component. * * - * //Example Usage : + * Example Usage: * - * ``` + * ```php + * // Simple link-only nav (primary, medium) + * $items = array( + * array( 'type' => 'link', 'label' => 'Dashboard', 'icon' => Icon::DASHBOARD, 'url' => '/dashboard', 'active' => true ), + * array( 'type' => 'link', 'label' => 'My Courses', 'icon' => Icon::BOOK, 'url' => '/my-courses' ), + * array( 'type' => 'link', 'label' => 'Wishlist', 'icon' => Icon::WISHLIST, 'url' => '/wishlist' ), + * ); + * + * Nav::make() + * ->items( $items ) + * ->render(); + * + * // Nav with a dropdown item * $items = array( - * array( - * 'type' => 'link', // 'link' or 'dropdown' - * 'label' => 'Wishlist', - * 'icon' => Icon::WISHLIST, - * 'url' => '#', - * 'active' => false, - * ), - * array( - * 'type' => 'dropdown', - * 'active' => true, - * 'options' => array( - * array( - * 'label' => 'Active', - * 'count => 4, - * 'icon' => Icon::PLAY_LINE, - * 'url' => '#', - * 'active' => false, - * ), - * array( - * 'label' => 'Enrolled', - * 'count => 4, - * 'icon' => Icon::ENROLLED, - * 'url' => '#', - * 'active' => true, - * ), - * ), - * ), + * array( + * 'type' => 'dropdown', + * 'active' => true, + * 'options' => array( + * array( 'label' => 'Active', 'count' => 4, 'icon' => Icon::PLAY_LINE, 'url' => '?status=active', 'active' => true ), + * array( 'label' => 'Enrolled', 'count' => 2, 'icon' => Icon::ENROLLED, 'url' => '?status=enrolled' ), + * array( 'label' => 'Wishlist', 'count' => 1, 'icon' => Icon::WISHLIST, 'url' => '?status=wishlist' ), + * ), + * ), + * array( 'type' => 'link', 'label' => 'Reviews', 'url' => '/reviews' ), * ); * - * echo Nav::make() - * ->items( array( $dropdown ) ) - * ->size( Size::SMALL ) - * ->variant( Variant::SECONDARY ) - * ->render(); + * Nav::make() + * ->items( $items ) + * ->size( Size::SMALL ) + * ->variant( Variant::SECONDARY ) + * ->render(); + * + * // Nav with count displayed on link items + * $items = array( + * array( 'type' => 'link', 'label' => 'Students', 'count' => 42, 'url' => '/students', 'active' => true ), + * array( 'type' => 'link', 'label' => 'Reviews', 'count' => 8, 'url' => '/reviews' ), + * ); + * + * Nav::make() + * ->items( $items ) + * ->size( Size::LARGE ) + * ->render(); + * + * // Extra attributes on the wrapper + * Nav::make() + * ->items( $items ) + * ->attr( 'id', 'student-nav' ) + * ->render(); + * + * // Retrieve HTML without echoing + * $html = Nav::make()->items( $items )->get(); * ``` * * @since 4.0.0 diff --git a/components/Pagination.php b/components/Pagination.php index 27f183a800..bb7aac1e12 100644 --- a/components/Pagination.php +++ b/components/Pagination.php @@ -19,16 +19,51 @@ * * Responsible for rendering pagination component. * - * // Example Usage : + * Example Usage: * - * ``` - * Pagination::make() - * ->current( 2 ) - * ->total( 200 ) - * ->limit( tutor_utils()->get_option( 'pagination_per_page' ) ) - * ->prev( SvgIcon::make()->name( Icon::CHEVRON_LEFT_2 )->get() ) - * ->next( SvgIcon::make()->name( Icon::CHEVRON_RIGHT_2 )->get() ) - * ->render(); + * ```php + * // Minimal — current page from URL, default prev/next icons + * Pagination::make() + * ->current( (int) Input::get( 'current_page', 1 ) ) + * ->total( $total_items ) + * ->limit( 10 ) + * ->render(); + * + * // With custom prev/next icon markup + * Pagination::make() + * ->current( 2 ) + * ->total( 200 ) + * ->limit( tutor_utils()->get_option( 'pagination_per_page' ) ) + * ->prev( SvgIcon::make()->name( Icon::CHEVRON_LEFT_2 )->flip_rtl()->get() ) + * ->next( SvgIcon::make()->name( Icon::CHEVRON_RIGHT_2 )->flip_rtl()->get() ) + * ->render(); + * + * // Custom URL format (e.g., pretty-permalink pagination) + * Pagination::make() + * ->current( get_query_var( 'paged', 1 ) ) + * ->total( $total_items ) + * ->limit( 20 ) + * ->format( '/page/%#%/' ) + * ->render(); + * + * // Show all page links (no ellipsis collapsing) + * Pagination::make() + * ->current( 1 ) + * ->total( 50 ) + * ->limit( 5 ) + * ->show_all( true ) + * ->render(); + * + * // Extra CSS class on the nav wrapper + * Pagination::make() + * ->current( 1 ) + * ->total( 100 ) + * ->limit( 10 ) + * ->attr( 'class', 'tutor-mt-6' ) + * ->render(); + * + * // Retrieve HTML without echoing + * $html = Pagination::make()->current( 1 )->total( 50 )->limit( 10 )->get(); * ``` * * @since 4.0.0 diff --git a/components/Popover.php b/components/Popover.php index ee084a439c..0fdd15e9b6 100644 --- a/components/Popover.php +++ b/components/Popover.php @@ -21,22 +21,86 @@ * Responsible for rendering popover component on button * at different placement positions with footer component and menu items. * - * Example Usage: Basic Popover - * ``` + * Example Usage: + * ```php + * // Basic popover with title and body (bottom-start by default) + * Popover::make() + * ->title( 'Information' ) + * ->body( '

This is a popover component.

' ) + * ->trigger( + * Button::make() + * ->label( 'Show Info' ) + * ->attr( 'x-ref', 'trigger' ) + * ->attr( '@click', 'toggle()' ) + * ->variant( Variant::PRIMARY ) + * ->get() + * ) + * ->render(); + * + * // Popover with close button in header + * Popover::make() + * ->title( 'Details' ) + * ->body( '

Here are the full details.

' ) + * ->closeable( true ) + * ->trigger( + * Button::make()->label( 'Details' )->attr( 'x-ref', 'trigger' )->attr( '@click', 'toggle()' )->get() + * ) + * ->render(); + * + * // Popover positioned top-end + * Popover::make() + * ->title( 'Help' ) + * ->body( '

Read the documentation for more help.

' ) + * ->placement( Positions::TOP_END ) + * ->trigger( + * Button::make()->label( '?' )->attr( 'x-ref', 'trigger' )->attr( '@click', 'toggle()' )->get() + * ) + * ->render(); + * + * // Popover with footer buttons * Popover::make() - * ->title( 'Basic' ) - * ->body( '

This is a popover component

' ) - * ->closeable( true ) - * ->trigger( - * Button::make() - * ->label( 'Show Popover' ) - * ->attr( 'x-ref', 'trigger' ) - * ->attr( '@click', 'toggle()' ) - * ->size( 'medium' ) - * ->variant( 'primary' ) - * ->get() - * ) - * ->render(); + * ->title( 'Confirm' ) + * ->body( '

Are you sure you want to proceed?

' ) + * ->footer( array( + * Button::make()->label( 'Cancel' )->variant( Variant::SECONDARY )->attr( '@click', 'hide()' )->get(), + * Button::make()->label( 'Confirm' )->variant( Variant::PRIMARY )->get(), + * ) ) + * ->footer_alignment( Positions::RIGHT ) + * ->trigger( + * Button::make()->label( 'Open' )->attr( 'x-ref', 'trigger' )->attr( '@click', 'toggle()' )->get() + * ) + * ->render(); + * + * // Popover as a context menu (menu items) + * Popover::make() + * ->menu_item( array( 'tag' => 'button', 'content' => 'Edit', 'icon' => SvgIcon::make()->name( Icon::EDIT )->size( 16 )->get(), 'attr' => array( '@click' => 'editItem()' ) ) ) + * ->menu_item( array( 'tag' => 'button', 'content' => 'Delete', 'icon' => SvgIcon::make()->name( Icon::DELETE_2 )->size( 16 )->get(), 'attr' => array( '@click' => 'deleteItem()', 'class' => 'tutor-text-critical' ) ) ) + * ->menu_min_width( '140px' ) + * ->trigger( + * Button::make()->icon( Icon::DOT_MENU_H )->icon_only()->variant( Variant::GHOST )->attr( 'x-ref', 'trigger' )->attr( '@click', 'toggle()' )->get() + * ) + * ->render(); + * + * // Menu item with right-aligned icon + * Popover::make() + * ->menu_item( array( 'tag' => 'a', 'content' => 'View Profile', 'icon' => SvgIcon::make()->name( Icon::ARROW_RIGHT )->size( 16 )->get(), 'icon_alignment' => Positions::RIGHT, 'attr' => array( 'href' => '#' ) ) ) + * ->trigger( + * Button::make()->label( 'Actions' )->attr( 'x-ref', 'trigger' )->attr( '@click', 'toggle()' )->get() + * ) + * ->render(); + * + * // Non-dismissible popover (click outside does NOT close it) + * Popover::make() + * ->title( 'Important' ) + * ->body( '

You must complete this step before continuing.

' ) + * ->dismissible( false ) + * ->trigger( + * Button::make()->label( 'Open' )->attr( 'x-ref', 'trigger' )->attr( '@click', 'toggle()' )->get() + * ) + * ->render(); + * + * // Retrieve HTML without echoing + * $html = Popover::make()->title( 'Tip' )->body( '

Hover for help.

' )->trigger( $btn )->get(); * ``` * * @since 4.0.0 diff --git a/components/PreviewTrigger.php b/components/PreviewTrigger.php index 6a072c608e..ceef6ea6b5 100644 --- a/components/PreviewTrigger.php +++ b/components/PreviewTrigger.php @@ -18,10 +18,19 @@ * Class PreviewTrigger * * Example Usage: - * ``` + * ```php + * // Render a preview trigger for a course * PreviewTrigger::make() - * ->id( 123 ) + * ->id( $course_id ) * ->render(); + * + * // Render a preview trigger for a lesson + * PreviewTrigger::make() + * ->id( $lesson_id ) + * ->render(); + * + * // Retrieve HTML without echoing + * $html = PreviewTrigger::make()->id( $course_id )->get(); * ``` * * @since 1.0.0 diff --git a/components/Progress.php b/components/Progress.php index 0c433703f0..80824366f7 100644 --- a/components/Progress.php +++ b/components/Progress.php @@ -22,20 +22,77 @@ * Progress Component Class. * * Example usage: - * ``` - * // Progress bar + * ```php + * // Basic animated progress bar (0–100) * Progress::make() * ->type( 'bar' ) * ->value( 75 ) - * ->animated() * ->render(); * - * // Progress circle + * // Progress bar without animation + * Progress::make() + * ->type( 'bar' ) + * ->value( 50 ) + * ->animated( false ) + * ->render(); + * + * // Progress bar with a specific size + * Progress::make() + * ->type( 'bar' ) + * ->value( 30 ) + * ->size( Size::MEDIUM ) + * ->render(); + * + * // Progress bar with brand variant color + * Progress::make() + * ->type( 'bar' ) + * ->value( 60 ) + * ->variant( Variant::BRAND ) + * ->render(); + * + * // Progress circle (percentage arc) * Progress::make() * ->type( 'circle' ) * ->value( 75 ) * ->render(); * + * // Progress circle — complete state (shows checkmark) + * Progress::make() + * ->type( 'circle' ) + * ->complete() + * ->render(); + * + * // Progress circle — locked state + * Progress::make() + * ->type( 'circle' ) + * ->locked() + * ->render(); + * + * // Progress circle without label + * Progress::make() + * ->type( 'circle' ) + * ->value( 40 ) + * ->show_label( false ) + * ->render(); + * + * // Progress circle with custom label text + * Progress::make() + * ->type( 'circle' ) + * ->value( 90 ) + * ->label( '9/10 done' ) + * ->render(); + * + * // Progress circle with custom colors and animation duration + * Progress::make() + * ->type( 'circle' ) + * ->value( 55 ) + * ->stroke_color( '#e0e0e0' ) + * ->progress_stroke_color( '#4CAF50' ) + * ->duration( 1500 ) + * ->render(); + * + * // Retrieve HTML without echoing + * $html = Progress::make()->type( 'bar' )->value( 80 )->get(); * ``` * * @since 4.0.0 diff --git a/components/SearchFilter.php b/components/SearchFilter.php index 8edcd099eb..b8c660a2f4 100644 --- a/components/SearchFilter.php +++ b/components/SearchFilter.php @@ -24,16 +24,50 @@ * Class SearchFilter * * Example Usage: - * ``` + * ```php + * // Minimal search form (uses current URL, param name = 'search') + * SearchFilter::make() + * ->render(); + * + * // With custom placeholder and input name + * SearchFilter::make() + * ->placeholder( 'Search students...' ) + * ->input_name( 'student_search' ) + * ->render(); + * + * // With explicit action URL and hidden inputs to preserve context * SearchFilter::make() - * ->form_id( 'my-search-form' ) - * ->placeholder( 'Search items...' ) - * ->hidden_inputs( array( 'type' => 'course' ) ) - * ->action( 'https://example.com/search' ) + * ->action( admin_url( 'admin.php?page=tutor-students' ) ) * ->input_name( 'search' ) - * ->method( 'GET' ) - * ->size( 'small' ) + * ->hidden_inputs( array( 'type' => 'enrolled', 'course_id' => $course_id ) ) + * ->render(); + * + * // Small-size search field + * SearchFilter::make() + * ->placeholder( 'Search...' ) + * ->size( Size::SMALL ) * ->render(); + * + * // Large-size search field + * SearchFilter::make() + * ->placeholder( 'Search courses...' ) + * ->size( Size::LARGE ) + * ->render(); + * + * // Custom form ID (useful when multiple search forms exist on the same page) + * SearchFilter::make() + * ->form_id( 'announcement-search-form' ) + * ->placeholder( 'Search announcements...' ) + * ->render(); + * + * // POST method (e.g., for AJAX-backed searches) + * SearchFilter::make() + * ->input_name( 'q' ) + * ->method( 'POST' ) + * ->render(); + * + * // Retrieve HTML without echoing + * $html = SearchFilter::make()->placeholder( 'Find a course...' )->get(); * ``` * * @since 4.0.0 @@ -222,7 +256,7 @@ public function get(): string { ob_start(); ?> -
render_attributes(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>> + render_attributes(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>> hidden_inputs as $name => $value ) : ?> diff --git a/components/Sorting.php b/components/Sorting.php index 6fc6aebd3f..01ccddcab9 100644 --- a/components/Sorting.php +++ b/components/Sorting.php @@ -26,14 +26,44 @@ * Class Sorting * * Example Usage: - * ``` + * ```php + * // Minimal — URL query param driven, default labels + * Sorting::make() + * ->render(); + * + * // Pre-set the active order from URL param + * Sorting::make() + * ->order( Input::get( 'order', 'DESC' ) ) + * ->render(); + * + * // Custom ascending/descending labels + * Sorting::make() + * ->order( 'DESC' ) + * ->label_asc( __( 'Oldest', 'tutor' ) ) + * ->label_desc( __( 'Newest', 'tutor' ) ) + * ->render(); + * + * // JavaScript callback on change (Alpine.js method) * Sorting::make() * ->order( 'DESC' ) - * ->label_asc( 'Oldest' ) - * ->label_desc( 'Newest' ) * ->on_change( 'changeOrder' ) * ->bind_active_order( 'currentOrder' ) * ->render(); + * + * // Cumulative filtering — preserve existing query params via base_url + * Sorting::make() + * ->order( Input::get( 'order', 'DESC' ) ) + * ->base_url( remove_query_arg( 'current_page' ) ) + * ->render(); + * + * // Custom button size + * Sorting::make() + * ->order( 'ASC' ) + * ->size( Size::SMALL ) + * ->render(); + * + * // Retrieve HTML without echoing + * $html = Sorting::make()->order( 'DESC' )->get(); * ``` * * @since 4.0.0 diff --git a/components/StarRating.php b/components/StarRating.php index 12ce38333b..7e8e93d883 100644 --- a/components/StarRating.php +++ b/components/StarRating.php @@ -20,11 +20,47 @@ * Class StarRating * * Example Usage: - * ``` + * ```php + * // Display stars only (no numbers) * StarRating::make() - * ->rating(4.5) - * ->show_average(true) + * ->rating( 4.5 ) * ->render(); + * + * // Stars with average numeric rating shown + * StarRating::make() + * ->rating( 4.5 ) + * ->show_average( true ) + * ->render(); + * + * // Stars with review count + * StarRating::make() + * ->rating( 3.8 ) + * ->count( 120 ) + * ->render(); + * + * // Stars with average and review count + * StarRating::make() + * ->rating( 4.2 ) + * ->show_average( true ) + * ->count( 58 ) + * ->render(); + * + * // Larger icon size + * StarRating::make() + * ->rating( 5.0 ) + * ->icon_size( 24 ) + * ->show_average( true ) + * ->render(); + * + * // Zero rating (no stars filled) + * StarRating::make() + * ->rating( 0 ) + * ->show_average( true ) + * ->count( 0 ) + * ->render(); + * + * // Retrieve HTML without echoing + * $html = StarRating::make()->rating( 4.5 )->show_average( true )->count( 30 )->get(); * ``` * * @since 4.0.0 diff --git a/components/StarRatingInput.php b/components/StarRatingInput.php index 04533e405a..bc3696a791 100644 --- a/components/StarRatingInput.php +++ b/components/StarRatingInput.php @@ -21,11 +21,39 @@ * Class StarRatingInput * * Example Usage: - * ``` + * ```php + * // Basic star input (no initial rating) + * StarRatingInput::make() + * ->field_name( 'rating' ) + * ->render(); + * + * // With a pre-selected rating + * StarRatingInput::make() + * ->field_name( 'rating' ) + * ->current_rating( 4.0 ) + * ->render(); + * + * // With Alpine.js onChange callback * StarRatingInput::make() - * ->field_name('rating') - * ->current_rating(4.5) + * ->field_name( 'rating' ) + * ->current_rating( 3.0 ) + * ->on_change( 'handleRatingChange' ) * ->render(); + * + * // With Alpine.js form register binding (for validation) + * StarRatingInput::make() + * ->field_name( 'rating' ) + * ->register( "register('rating', { required: 'Please rate this course' })" ) + * ->render(); + * + * // Emoji view (renders emoji buttons instead of/alongside stars) + * StarRatingInput::make() + * ->field_name( 'course_rating' ) + * ->view( 'emoji' ) + * ->render(); + * + * // Retrieve HTML without echoing + * $html = StarRatingInput::make()->field_name( 'rating' )->current_rating( 5.0 )->get(); * ``` * * @since 4.0.0 diff --git a/components/StatusSelect.php b/components/StatusSelect.php index 2b1b6a7fab..e91edc1859 100644 --- a/components/StatusSelect.php +++ b/components/StatusSelect.php @@ -21,16 +21,51 @@ * StatusSelect Component Class. * * Example usage: - * ``` + * ```php + * // Basic status select for a course + * StatusSelect::make() + * ->options( array( + * 'publish' => array( 'label' => 'Published', 'variant' => 'success', 'icon' => Icon::CHECK_MARK ), + * 'pending' => array( 'label' => 'Pending', 'variant' => 'warning', 'icon' => Icon::CLOCK ), + * 'draft' => array( 'label' => 'Draft', 'variant' => 'default', 'icon' => Icon::EDIT ), + * ) ) + * ->selected( 'publish' ) + * ->action( 'tutor_change_course_status' ) + * ->data( array( 'id' => $course_id ) ) + * ->render(); + * + * // Order / enrollment status select * StatusSelect::make() - * ->options([ - * 'publish' => ['label' => 'Published', 'variant' => 'success', 'icon' => Icon::CHECK_MARK], - * 'pending' => ['label' => 'Pending', 'variant' => 'warning', 'icon' => Icon::CLOCK], - * ]) - * ->selected('publish') - * ->action('tutor_change_course_status') - * ->data(['id' => 123]) + * ->options( array( + * 'completed' => array( 'label' => 'Completed', 'variant' => 'success', 'icon' => Icon::CHECK_CIRCLE ), + * 'cancelled' => array( 'label' => 'Cancelled', 'variant' => 'error', 'icon' => Icon::CLOSE_CIRCLE ), + * 'processing' => array( 'label' => 'Processing','variant' => 'warning', 'icon' => Icon::CLOCK ), + * ) ) + * ->selected( 'processing' ) + * ->action( 'tutor_update_order_status' ) + * ->data( array( 'order_id' => $order_id ) ) * ->render(); + * + * // Without an AJAX action (display only, no auto-update) + * StatusSelect::make() + * ->options( array( + * 'active' => array( 'label' => 'Active', 'variant' => 'success' ), + * 'inactive' => array( 'label' => 'Inactive', 'variant' => 'disabled' ), + * ) ) + * ->selected( 'active' ) + * ->render(); + * + * // With extra data attributes and HTML attrs on the wrapper + * StatusSelect::make() + * ->options( $status_options ) + * ->selected( $current_status ) + * ->action( 'tutor_change_status' ) + * ->data( array( 'id' => $item_id, 'nonce' => wp_create_nonce( 'tutor_nonce' ) ) ) + * ->attr( 'class', 'my-status-select' ) + * ->render(); + * + * // Retrieve HTML without echoing + * $html = StatusSelect::make()->options( $options )->selected( 'publish' )->get(); * ``` */ class StatusSelect extends BaseComponent { diff --git a/components/SvgIcon.php b/components/SvgIcon.php index 3bcd8f187a..d411b9fed0 100644 --- a/components/SvgIcon.php +++ b/components/SvgIcon.php @@ -18,23 +18,63 @@ * SvgIcon Component Class. * * Example usage: - * ``` + * ```php + * // Render icon at default size (16×16) + * SvgIcon::make() + * ->name( Icon::CHECK ) + * ->render(); + * + * // Render with explicit size * SvgIcon::make() * ->name( Icon::CHECK ) * ->size( 24 ) * ->render(); * + * // Render with independent width and height * SvgIcon::make() * ->name( Icon::DELETE ) - * ->size( 16 ) - * ->attr( 'class', 'tutor-icon-secondary' ) + * ->width( 20 ) + * ->height( 24 ) * ->render(); * + * // Render with a design-system color token * SvgIcon::make() * ->name( Icon::DELETE ) * ->size( 16 ) * ->color( Color::SECONDARY ) * ->render(); + * + * // Render with a custom CSS class + * SvgIcon::make() + * ->name( Icon::STAR_FILL ) + * ->size( 20 ) + * ->attr( 'class', 'tutor-icon-warning' ) + * ->render(); + * + * // Render directional icon that flips in RTL layouts + * SvgIcon::make() + * ->name( Icon::CHEVRON_RIGHT ) + * ->size( 16 ) + * ->flip_rtl() + * ->render(); + * + * // Ignore kids-mode icon override (always use default icon) + * SvgIcon::make() + * ->name( Icon::PLAY_LINE ) + * ->size( 24 ) + * ->ignore_kids() + * ->render(); + * + * // Retrieve HTML string without echoing + * $html = SvgIcon::make()->name( Icon::DELETE )->size( 16 )->color( Color::CRITICAL )->get(); + * + * // Multiple attrs + * SvgIcon::make() + * ->name( Icon::SPINNER ) + * ->size( 14 ) + * ->attr( 'class', 'tutor-animate-spin' ) + * ->attr( 'aria-label', 'Loading' ) + * ->render(); * ``` * * Note: The color() property only works with the version 4 design system tokens. diff --git a/components/Table.php b/components/Table.php index 07867a79c2..7b72303d9a 100644 --- a/components/Table.php +++ b/components/Table.php @@ -18,59 +18,88 @@ * Responsible for rendering table component with variable number * of rows and columns. * - * ``` - * // Component Data Structure + * ```php + * // Minimal table with headings and rows + * $headings = array( + * array( 'content' => __( 'Student', 'tutor' ) ), + * array( 'content' => __( 'Progress', 'tutor' ) ), + * array( 'content' => __( 'Score', 'tutor' ) ), + * ); + * + * $contents = array( + * array( + * 'columns' => array( + * array( 'content' => 'Jane Doe' ), + * array( 'content' => '80%' ), + * array( 'content' => '92/100' ), + * ), + * ), + * array( + * 'columns' => array( + * array( 'content' => 'John Smith' ), + * array( 'content' => '55%' ), + * array( 'content' => '61/100' ), + * ), + * ), + * ); + * * Table::make() - * ->headings( - * [ - * [ - * 'content' => '', - * ] - * ] - * ) - * ->contents( - * [ - * [ - * 'columns' => [ - * [ - * 'content' => '', - * ] - * ], - * ] - * ] - * ) - * ->attributes('') - * ->render(); - * ``` + * ->headings( $headings ) + * ->contents( $contents ) + * ->render(); * + * // Table with rich HTML inside cells and column borders + * $headings = array( + * array( 'content' => __( 'Quiz Info', 'tutor' ) ), + * array( 'content' => __( 'Marks', 'tutor' ) ), + * ); * - * ``` - * // Example Usage: - * $heading = array( - * array( - * 'content' => __( 'Quiz Info', 'tutor' ), - * ), - * array( - * 'content' => __( 'Marks', 'tutor' ), - * ), - * ); + * $contents = array( + * array( + * 'columns' => array( + * array( + * 'content' => + * '
' . + * SvgIcon::make()->name( Icon::QUESTION_CIRCLE )->size( 16 )->get() . + * esc_html__( 'Total Questions', 'tutor' ) . + * '
', + * ), + * array( 'content' => 20 ), + * ), + * ), + * array( + * 'columns' => array( + * array( + * 'content' => + * '
' . + * SvgIcon::make()->name( Icon::STAR_FILL )->size( 16 )->get() . + * esc_html__( 'Pass Mark', 'tutor' ) . + * '
', + * ), + * array( 'content' => 14 ), + * ), + * ), + * ); * - * $content = array( - * array( - * 'columns' => array( - * array( - * 'content' => '
' . SvgIcon::make()->name( Icon::QUESTION_CIRCLE )->render() . __( 'Questions', 'tutor' ) . '
', - * ), - * array( 'content' => 20 ), - * ), - * ), - * ); + * Table::make() + * ->headings( $headings ) + * ->contents( $contents ) + * ->attrs( array( 'class' => 'tutor-table-column-borders tutor-mb-6' ) ) + * ->render(); + * + * // Table with a custom class on a specific heading column + * $headings = array( + * array( 'content' => 'Name', 'class' => 'tutor-text-left' ), + * array( 'content' => 'Actions', 'class' => 'tutor-text-right' ), + * ); + * + * Table::make() + * ->headings( $headings ) + * ->contents( $contents ) + * ->render(); * - * echo Table::make() - * ->headings( $heading ) - * ->contents( $content ) - * ->attributes( 'tutor-table-wrapper tutor-table-column-borders tutor-mb-6' ) - * ->render(); + * // Retrieve HTML without echoing + * $html = Table::make()->headings( $headings )->contents( $contents )->get(); * ``` * * @since 4.0.0 diff --git a/components/Tabs.php b/components/Tabs.php index 2faa2872f8..f8cf116107 100644 --- a/components/Tabs.php +++ b/components/Tabs.php @@ -26,33 +26,64 @@ * Example usage: * * ```php - * $tabs_data = [ - * [ - * 'id' => 'lesson', - * 'label' => 'Lessons', - * 'icon' => 'book', - * 'content' => '

Lesson content goes here.

', - * ], - * [ - * 'id' => 'assignments', - * 'label' => 'Assignments', - * 'icon' => 'file', - * 'content' => '

Assignment content goes here.

', - * ], - * [ - * 'id' => 'quizzes', - * 'label' => 'Quizzes', - * 'icon' => 'check', - * 'content' => '

Quiz content goes here.

', - * ], - * ]; + * // Horizontal tabs (default orientation) + * $tabs_data = array( + * array( 'id' => 'overview', 'label' => 'Overview', 'content' => '

Course overview.

' ), + * array( 'id' => 'lessons', 'label' => 'Lessons', 'content' => '

Lesson list here.

' ), + * array( 'id' => 'quizzes', 'label' => 'Quizzes', 'content' => '

Quiz list here.

' ), + * ); + * + * Tabs::make() + * ->tabs( $tabs_data ) + * ->default_tab( 'overview' ) + * ->render(); + * + * // Vertical orientation + * Tabs::make() + * ->tabs( $tabs_data ) + * ->default_tab( 'lessons' ) + * ->orientation( Tabs::TYPE_VERTICAL ) + * ->render(); + * + * // With icons in tab buttons + * $tabs_data = array( + * array( 'id' => 'lesson', 'label' => 'Lessons', 'icon' => Icon::BOOK, 'content' => '

Lesson content.

' ), + * array( 'id' => 'assignments', 'label' => 'Assignments', 'icon' => Icon::FILE, 'content' => '

Assignment content.

' ), + * array( 'id' => 'quizzes', 'label' => 'Quizzes', 'icon' => Icon::CHECK, 'content' => '

Quiz content.

' ), + * ); * * Tabs::make() * ->tabs( $tabs_data ) * ->default_tab( 'lesson' ) - * ->orientation( 'horizontal' ) - * ->url_params( [ 'enabled' => true ] ) * ->render(); + * + * // Sync active tab to a custom URL query param (?section=...) + * Tabs::make() + * ->tabs( $tabs_data ) + * ->default_tab( 'overview' ) + * ->url_params( array( 'enabled' => true, 'paramName' => 'section' ) ) + * ->render(); + * + * // Disable URL sync entirely + * Tabs::make() + * ->tabs( $tabs_data ) + * ->default_tab( 'overview' ) + * ->url_params( array( 'enabled' => false ) ) + * ->render(); + * + * // With a disabled tab + * $tabs_data = array( + * array( 'id' => 'active', 'label' => 'Active', 'content' => '

...

' ), + * array( 'id' => 'disabled', 'label' => 'Locked', 'content' => '', 'disabled' => true ), + * ); + * + * Tabs::make() + * ->tabs( $tabs_data ) + * ->default_tab( 'active' ) + * ->render(); + * + * // Retrieve HTML without echoing + * $html = Tabs::make()->tabs( $tabs_data )->default_tab( 'overview' )->get(); * ``` * * @since 4.0.0 diff --git a/components/Tooltip.php b/components/Tooltip.php index 6921dc77a1..0885679b0d 100644 --- a/components/Tooltip.php +++ b/components/Tooltip.php @@ -21,13 +21,75 @@ * Tooltip Component Class. * * Example usage: - * ``` + * ```php + * // Basic tooltip on hover (top placement, default) + * Tooltip::make() + * ->content( 'This is a helpful tip.' ) + * ->trigger_element( '' ) + * ->render(); + * + * // Tooltip with specific placement and size + * Tooltip::make() + * ->content( 'Detailed information here.' ) + * ->placement( Tooltip::PLACEMENT_BOTTOM ) + * ->size( Size::LARGE ) + * ->trigger_element( '' . SvgIcon::make()->name( Icon::INFO )->size( 16 )->get() . '' ) + * ->render(); + * + * // Tooltip triggered on focus (keyboard accessible) + * Tooltip::make() + * ->content( 'This field requires a valid email.' ) + * ->trigger_on( Tooltip::FOCUS ) + * ->placement( Tooltip::PLACEMENT_TOP ) + * ->trigger_element( '' ) + * ->render(); + * + * // Tooltip triggered on click + * Tooltip::make() + * ->content( 'Copied to clipboard!' ) + * ->trigger_on( Tooltip::CLICK ) + * ->placement( Tooltip::PLACEMENT_END ) + * ->trigger_element( '' ) + * ->render(); + * + * // Tooltip with arrow alignment (centered) * Tooltip::make() - * ->content( 'Helpful information' ) - * ->placement( 'top' ) - * ->size( Size::SMALL ) - * ->trigger_element( '' ) + * ->content( 'Centered arrow tip.' ) + * ->arrow( Tooltip::ARROW_CENTER ) + * ->placement( Tooltip::PLACEMENT_TOP ) + * ->trigger_element( 'Hover' ) * ->render(); + * + * // Tooltip with custom offset distance + * Tooltip::make() + * ->content( 'Offset from trigger by 16px.' ) + * ->offset( 16 ) + * ->trigger_element( '' ) + * ->render(); + * + * // Tooltip with show/hide delay + * Tooltip::make() + * ->content( 'Appears after 300ms, hides after 200ms.' ) + * ->delay( 300, 200 ) + * ->trigger_element( 'Hover me' ) + * ->render(); + * + * // Tooltip with rich HTML content + * Tooltip::make() + * ->content( 'Tip: Use keyboard shortcuts to save time.', array( 'strong' => array(), 'em' => array() ) ) + * ->placement( Tooltip::PLACEMENT_BOTTOM ) + * ->trigger_element( '' . SvgIcon::make()->name( Icon::QUESTION_CIRCLE )->size( 16 )->get() . '' ) + * ->render(); + * + * // Tooltip placed at start (left in LTR) + * Tooltip::make() + * ->content( 'Left-side tooltip.' ) + * ->placement( Tooltip::PLACEMENT_START ) + * ->trigger_element( '' ) + * ->render(); + * + * // Retrieve HTML without echoing + * $html = Tooltip::make()->content( 'Save your work' )->trigger_element( $btn_html )->get(); * ``` * * @since 4.0.0 diff --git a/components/WPEditor.php b/components/WPEditor.php index e5b20f225d..e55ccfd346 100644 --- a/components/WPEditor.php +++ b/components/WPEditor.php @@ -21,41 +21,83 @@ * WPEditor Component Class. * * Example usage: - * ``` - * // Basic editor + * ```php + * // Basic editor with label * WPEditor::make() * ->name( 'description' ) - * ->label( 'Description' ) - * ->content( 'Default content' ) + * ->label( 'Course Description' ) + * ->content( 'Default content here.' ) + * ->render(); + * + * // Required editor with placeholder + * WPEditor::make() + * ->name( 'answer' ) + * ->label( 'Your Answer' ) + * ->placeholder( 'Write your answer here...' ) + * ->required( true ) * ->render(); * - * // Editor with validation + * // Editor with Alpine.js form validation binding * WPEditor::make() * ->name( 'answer' ) * ->label( 'Your Answer' ) - * ->placeholder( 'Write your answer here' ) * ->attr( 'x-bind', "register('answer', { required: 'Answer is required' })" ) * ->render(); * - * // Editor with custom configuration + * // Editor pre-filled with saved content * WPEditor::make() * ->name( 'bio' ) - * ->content( $user_bio ) - * ->editor_config( - * array( - * 'teeny' => false, - * 'media_buttons' => false, - * 'quicktags' => false, - * 'editor_height' => 150, - * 'tinymce' => array( - * 'toolbar1' => 'bold,italic,underline,link,unlink,removeformat,image,bullist,codesample', - * 'toolbar2' => '', - * 'toolbar3' => '', - * 'plugins' => 'link,image,lists,codesample', - * ), - * ) - * ); + * ->label( 'Instructor Bio' ) + * ->content( get_user_meta( $user_id, 'description', true ) ) + * ->render(); + * + * // Editor with help text and error state + * WPEditor::make() + * ->name( 'overview' ) + * ->label( 'Course Overview' ) + * ->help_text( 'Describe what students will learn.' ) + * ->error( 'This field is required.' ) + * ->render(); + * + * // Custom TinyMCE toolbar (no media buttons, custom toolbar) + * WPEditor::make() + * ->name( 'announcement' ) + * ->label( 'Announcement' ) + * ->editor_config( array( + * 'teeny' => false, + * 'media_buttons' => false, + * 'quicktags' => false, + * 'editor_height' => 200, + * 'tinymce' => array( + * 'toolbar1' => 'bold,italic,underline,link,unlink,bullist,numlist,removeformat', + * 'toolbar2' => '', + * 'toolbar3' => '', + * ), + * ) ) + * ->render(); + * + * // Teeny editor (minimal toolbar) + * WPEditor::make() + * ->name( 'short_bio' ) + * ->label( 'Short Bio' ) + * ->editor_config( array( 'teeny' => true, 'media_buttons' => false ) ) * ->render(); + * + * // Custom wrapper attribute (e.g., Alpine.js show binding) + * WPEditor::make() + * ->name( 'notes' ) + * ->label( 'Notes' ) + * ->wrapper_attr( 'x-show', 'showNotes' ) + * ->render(); + * + * // With explicit editor ID + * WPEditor::make() + * ->name( 'content' ) + * ->id( 'my-custom-editor-id' ) + * ->render(); + * + * // Retrieve HTML without echoing + * $html = WPEditor::make()->name( 'description' )->content( $saved_content )->get(); * ``` * * @since 4.0.0