$atts Block or shortcode attributes. */ public function render( array $atts ): string { if ( ! is_user_logged_in() ) { $loginPageId = Val::int( $atts['loginPageId'] ?? $atts['login_page_id'] ?? 0 ); return sprintf( '
%s %s.
', esc_html__( 'Please', 'unsupervised-schedular' ), esc_url( $this->loginUrl( $loginPageId ) ), esc_html__( 'log in to book a lesson', 'unsupervised-schedular' ) ); } if ( RegistrationStatus::isAwaitingApproval( get_current_user_id() ) ) { return '' . esc_html__( 'Your account is awaiting studio approval. You will be able to book once a studio admin approves it.', 'unsupervised-schedular' ) . '
'; } if ( ! current_user_can( RoleManager::CAP_BOOK_LESSON ) ) { return '' . esc_html__( 'This page is for students only.', 'unsupervised-schedular' ) . '
'; } wp_enqueue_style( 'us-scheduler' ); wp_enqueue_script( 'us-scheduler' ); $lessonTypeId = absint( Val::int( $atts['lessonTypeId'] ?? $atts['lesson_type'] ?? 0 ) ); $showTypeFilter = self::toBool( $atts['showTypeFilter'] ?? $atts['show_filter'] ?? true ); $mode = self::mode( $atts['displayMode'] ?? $atts['show'] ?? self::MODE_BOTH ); $showBooking = self::MODE_UPCOMING !== $mode; $showUpcoming = self::MODE_BOOKING !== $mode; // Who this account may book for. A single-student account gets one entry // (themselves) and no selector at all; a guardian's list leads with their // children, so the default choice is never the parent. $students = $this->guardians->bookableStudents( get_current_user_id() ); ob_start(); include USC_PLUGIN_DIR . 'templates/frontend/booking-page.php'; return (string) ob_get_clean(); } /** * Normalises the display-mode attribute; anything unrecognised embeds the * whole page, so a typo never silently hides half of it. */ private static function mode( mixed $value ): string { $mode = strtolower( trim( Val::string( $value ) ) ); return in_array( $mode, [ self::MODE_BOOKING, self::MODE_UPCOMING ], true ) ? $mode : self::MODE_BOTH; } /** * Reads a boolean attribute. Block attributes arrive as real booleans, * shortcode attributes as strings — where the words people actually write * for "off" ("no", "false", "off") are all truthy to PHP, so they are * matched explicitly rather than cast. */ private static function toBool( mixed $value ): bool { if ( is_string( $value ) ) { return ! in_array( strtolower( trim( $value ) ), [ '', '0', 'no', 'false', 'off' ], true ); } return Val::bool( $value ); } /** * URL the logged-out prompt sends visitors to: the chosen login page when * one is configured (and still exists), otherwise the WordPress login * screen with a redirect back to the current page. */ public function loginUrl( int $loginPageId ): string { if ( $loginPageId > 0 ) { $url = get_permalink( $loginPageId ); if ( is_string( $url ) ) { return $url; } } $permalink = get_permalink(); return wp_login_url( false === $permalink ? '' : $permalink ); } }