$atts Shortcode attributes. * @return string HTML output. */ public function render( array $atts = [] ): string { $atts = shortcode_atts( [ 'view' => 'month', 'category' => '', 'user' => '', 'users' => '', 'show_categories' => 'true', 'initial_month' => '', ], $atts, 'webcalendar' ); // Enqueue frontend assets wp_enqueue_script( 'webcal-frontend' ); wp_enqueue_style( 'webcal-frontend' ); $initial_month = preg_match( '/^\d{4}-\d{2}$/', $atts['initial_month'] ) ? $atts['initial_month'] : ''; // Pass attributes to JS wp_localize_script( 'webcal-frontend', 'webcalData', [ 'view' => $atts['view'], 'category' => $atts['category'], 'user' => $atts['user'], 'users' => sanitize_text_field( $atts['users'] ), 'showCategories' => $atts['show_categories'] !== 'false', 'initialMonth' => $initial_month, 'nonce' => wp_create_nonce( 'wp_rest' ), 'apiUrl' => get_rest_url( null, 'webcal/v1' ), ] ); // Every substituted value is esc_attr()'d; wp_kses() is a defensive // boundary on the returned markup so the shortcode contract is // verifiably safe even if a future edit forgets an inner escape (WPORG-13.2). return wp_kses( sprintf( '
', esc_attr( $atts['view'] ), esc_attr( $atts['category'] ), esc_attr( $initial_month ), esc_attr( sanitize_text_field( $atts['users'] ) ), esc_attr( $atts['show_categories'] !== 'false' ? 'true' : 'false' ) ), [ 'div' => [ 'class' => [], 'data-view' => [], 'data-category' => [], 'data-initial-month' => [], 'data-users' => [], 'data-show-categories' => [], ], ] ); } }