array( 'course-grid', array( 'per_page' => array( 'perPage', 'int' ), 'columns' => array( 'columns', 'int' ), 'orderby' => array( 'orderBy', 'key' ), 'show' => array( 'show', 'key' ), 'show_progress' => array( 'showProgress', 'bool' ), 'show_excerpt' => array( 'showExcerpt', 'bool' ), 'category' => array( 'categoryTerm', 'int' ), 'subcategories' => array( 'includeSubcategories', 'bool' ), 'filters' => array( 'showFilters', 'bool' ), 'sort' => array( 'showSort', 'bool' ), 'badges' => array( 'showBadges', 'bool' ), 'rating' => array( 'showRating', 'bool' ), 'wishlist' => array( 'showWishlist', 'bool' ), 'levels' => array( 'showLevels', 'bool' ), ), ), 'rooster_lms_course_outline' => array( 'course-outline', array( 'course' => array( 'coursePost', 'int' ), 'show_progress' => array( 'showProgress', 'bool' ), ), ), 'rooster_lms_enrol_button' => array( 'enrol-button', array( 'course' => array( 'coursePost', 'int' ), 'enrol_label' => array( 'enrolLabel', 'text' ), 'start_label' => array( 'startLabel', 'text' ), 'continue_label' => array( 'continueLabel', 'text' ), ), ), 'rooster_lms_mark_complete' => array( 'mark-complete', array( 'lesson' => array( 'lessonPost', 'int' ), 'label' => array( 'label', 'text' ), ), ), 'rooster_lms_progress' => array( 'progress-bar', array( 'course' => array( 'coursePost', 'int' ), 'show_label' => array( 'showLabel', 'bool' ), ), ), 'rooster_lms_my_courses' => array( 'my-courses', array( 'per_page' => array( 'perPage', 'int' ), 'show_tabs' => array( 'showTabs', 'bool' ), 'default_tab' => array( 'defaultTab', 'key' ), ), ), 'rooster_lms_org_progress' => array( 'org-progress', array( 'per_page' => array( 'perPage', 'int' ), 'org' => array( 'orgId', 'int' ), ), ), 'rooster_lms_categories' => array( 'category-grid', array( 'taxonomy' => array( 'taxonomy', 'key' ), 'parent' => array( 'parentTerm', 'int' ), 'depth' => array( 'depth', 'int' ), 'columns' => array( 'columns', 'int' ), 'show_count' => array( 'showCount', 'bool' ), 'show_image' => array( 'showImage', 'bool' ), 'show_description' => array( 'showDescription', 'bool' ), 'hide_empty' => array( 'hideEmpty', 'bool' ), 'single_course_link' => array( 'singleCourseLink', 'bool' ), 'show_lesson_count' => array( 'showLessonCount', 'bool' ), 'parent_from_url' => array( 'parentFromUrl', 'bool' ), ), ), 'rooster_lms_category_list' => array( 'category-list', array( 'taxonomy' => array( 'taxonomy', 'key' ), 'parent' => array( 'parentTerm', 'int' ), 'depth' => array( 'depth', 'int' ), 'show_count' => array( 'showCount', 'bool' ), 'hide_empty' => array( 'hideEmpty', 'bool' ), ), ), 'rooster_lms_breadcrumbs' => array( 'breadcrumbs', array( 'show_home' => array( 'showHome', 'bool' ), 'show_archive' => array( 'showArchive', 'bool' ), 'show_current' => array( 'showCurrent', 'bool' ), 'post' => array( 'postId', 'int' ), 'taxonomy' => array( 'taxonomy', 'key' ), 'term' => array( 'termId', 'int' ), ), ), 'rooster_lms_org_portal' => array( 'org-portal', array( 'tab' => array( 'tab', 'key' ), 'org' => array( 'orgId', 'int' ), 'apparent_root' => array( 'apparentRoot', 'text' ), ), ), 'rooster_lms_org_dashboard' => array( 'org-dashboard', array( 'org' => array( 'orgId', 'int' ) ) ), 'rooster_lms_org_members' => array( 'org-members', array( 'org' => array( 'orgId', 'int' ) ) ), 'rooster_lms_org_matrix' => array( 'org-matrix', array( 'org' => array( 'orgId', 'int' ) ) ), 'rooster_lms_org_job_roles' => array( 'org-job-roles', array( 'org' => array( 'orgId', 'int' ) ) ), 'rooster_lms_org_locations' => array( 'org-locations', array( 'org' => array( 'orgId', 'int' ) ) ), 'rooster_lms_org_branding' => array( 'org-branding', array( 'org' => array( 'orgId', 'int' ) ) ), 'rooster_lms_org_registration_fields' => array( 'org-registration-fields', array( 'org' => array( 'orgId', 'int' ) ) ), 'rooster_lms_org_enroller' => array( 'org-enroller', array( 'org' => array( 'orgId', 'int' ) ) ), 'rooster_lms_org_catalogue' => array( 'org-catalogue', array( 'org' => array( 'orgId', 'int' ) ) ), 'rooster_lms_org_quiz_results' => array( 'org-quiz-results', array( 'org' => array( 'orgId', 'int' ) ) ), 'rooster_lms_quiz' => array( 'quiz', array( 'quiz' => array( 'quizPost', 'int' ), 'course' => array( 'coursePost', 'int' ), ), ), 'rooster_lms_h5p' => array( 'h5p', array( 'content' => array( 'contentId', 'int' ), 'counts_for_completion' => array( 'countsForCompletion', 'bool' ), 'lesson' => array( 'lessonPost', 'int' ), ), ), 'rooster_lms_my_certificates' => array( 'my-certificates', array() ), 'rooster_lms_certificate_verify' => array( 'certificate-verify', array() ), 'rooster_lms_grading_queue' => array( 'grading-queue', array( 'org' => array( 'orgId', 'int' ) ) ), 'rooster_lms_org_assessments' => array( 'org-assessments', array( 'org' => array( 'orgId', 'int' ) ) ), 'rooster_lms_feedback' => array( 'feedback', array( 'course' => array( 'coursePost', 'int' ), 'section' => array( 'section', 'section' ), 'display' => array( 'display', 'key' ), ), ), 'rooster_lms_account' => array( 'account', array( 'section' => array( 'defaultSection', 'key' ) ) ), 'rooster_lms_account_menu' => array( 'account-menu', array( 'show_name' => array( 'showButtonText', 'bool' ), 'login_label' => array( 'loginLabel', 'text' ), ), ), 'rooster_lms_live_session' => array( 'live-session', array( 'id' => array( 'sessionId', 'int' ), 'show' => array( 'show', 'key' ), 'course' => array( 'coursePost', 'int' ), 'experience' => array( 'experience', 'key' ), ), ), 'rooster_lms_live_sessions' => array( 'live-sessions', array( 'scope' => array( 'scope', 'key' ), 'course' => array( 'coursePost', 'int' ), 'org' => array( 'orgId', 'int' ), 'count' => array( 'count', 'int' ), 'layout' => array( 'layout', 'key' ), 'mode' => array( 'mode', 'key' ), 'category' => array( 'categoryTerm', 'int' ), 'editions' => array( 'editions', 'bool' ), ), ), 'rooster_lms_live_lesson' => array( 'live-lesson', array( 'lesson' => array( 'lessonPost', 'int' ), 'materials' => array( 'showMaterials', 'bool' ), ), ), 'rooster_lms_live_roster' => array( 'live-roster', array( 'org' => array( 'orgId', 'int' ) ) ), ); public const LIVE_NEXT = 'rooster_lms_live_next'; public const PORTAL = 'rooster_lms_org_portal'; private static bool $registered = false; public function register(): void { if ( self::$registered ) { return; } self::$registered = true; add_action( 'init', array( $this, 'add_shortcodes' ) ); } public function add_shortcodes(): void { foreach ( array_keys( self::MAP ) as $tag ) { add_shortcode( $tag, array( $this, 'render' ) ); } add_shortcode( self::LIVE_NEXT, array( self::class, 'live_next' ) ); } public static function live_next( $atts = array() ): string { $atts = is_array( $atts ) ? array_intersect_key( $atts, array_flip( array( 'course', 'experience' ) ) ) : array(); $atts['show'] = 'next'; return ( new self() )->render( $atts, '', 'rooster_lms_live_session' ); } public function render( $atts, $content = '', $tag = '' ): string { unset( $content ); $tag = (string) $tag; if ( ! isset( self::MAP[ $tag ] ) ) { return ''; } $attributes = self::block_attributes( $tag, is_array( $atts ) ? $atts : array() ); $name = self::MAP[ $tag ][0]; if ( BlockRegistry::is_registered( $name ) ) { return render_block( array( 'blockName' => 'rooster-lms/' . $name, 'attrs' => $attributes, 'innerHTML' => '', 'innerContent' => array(), 'innerBlocks' => array(), ) ); } $class = BlockRegistry::BLOCKS[ $name ] ?? ''; return '' === $class ? '' : (string) $class::render( $attributes ); } public static function portal( $atts = array() ): string { return ( new self() )->render( is_array( $atts ) ? $atts : array(), '', self::PORTAL ); } public static function block_attributes( string $tag, array $atts ): array { $spec = self::MAP[ $tag ][1]; $defaults = array_fill_keys( array_keys( $spec ), null ); $atts = shortcode_atts( $defaults, $atts, $tag ); $out = array(); foreach ( $spec as $key => $target ) { if ( null === $atts[ $key ] || ! is_scalar( $atts[ $key ] ) ) { continue; } $value = (string) $atts[ $key ]; switch ( $target[1] ) { case 'int': $out[ $target[0] ] = max( 0, (int) $value ); break; case 'bool': $out[ $target[0] ] = (bool) filter_var( $value, FILTER_VALIDATE_BOOLEAN ); break; case 'section': $out[ $target[0] ] = max( -1, (int) $value ); break; case 'key': $out[ $target[0] ] = sanitize_key( $value ); break; default: $out[ $target[0] ] = sanitize_text_field( $value ); } } return $out; } }