parser = $parser; $this->renderer = $renderer; $this->assets = $assets; $this->settings = $settings; } /** * Register shortcode. * * @return void */ public function register() { add_shortcode( 'ukulele_chords', array( $this, 'render' ) ); add_filter( 'the_content', array( $this, 'filter_the_content' ), 9 ); } /** * Prime frontend assets before scripts and styles are printed. * * @return void */ public function prime_frontend_assets() { if ( is_admin() ) { return; } global $wp_query; if ( ! $wp_query instanceof \WP_Query || empty( $wp_query->posts ) ) { return; } foreach ( $wp_query->posts as $post ) { if ( $post instanceof \WP_Post ) { $this->prime_post_assets( $post ); } } } /** * Render shortcode output. * * @param array $atts Shortcode attributes. * @param string|null $content Content. * @return string */ public function render( $atts, $content = null ) { $content = is_string( $content ) ? trim( $content ) : ''; if ( '' === $content ) { return ''; } $attributes = shortcode_atts( array( 'controls' => $this->settings->get( 'show_controls' ) ? 'true' : 'false', 'diagrams' => $this->settings->get( 'enable_diagrams' ) ? 'true' : 'false', 'transpose' => '0', 'print_button' => $this->settings->get( 'enable_print_button' ) ? 'true' : 'false', 'print_diagrams' => $this->settings->get( 'print_show_diagrams' ) ? 'true' : 'false', 'tuning' => $this->settings->get( 'default_tuning' ), 'enharmonic_preference' => $this->settings->get( 'enharmonic_preference' ), ), $atts, 'ukulele_chords' ); $attributes = apply_filters( 'da_plectrum_shortcode_attributes', $attributes, $atts, $content ); return $this->render_song( $content, $attributes ); } /** * Automatically process supported post content when enabled. * * @param string $content The current post content. * @return string */ public function filter_the_content( $content ) { if ( ! in_the_loop() || ! is_main_query() || is_admin() ) { return $content; } if ( ! $this->settings->get( 'automatic_processing' ) ) { return $content; } $post = get_post(); if ( ! $post instanceof \WP_Post ) { return $content; } $enabled_post_types = $this->settings->get( 'enabled_post_types' ); if ( ! is_array( $enabled_post_types ) || ! in_array( $post->post_type, $enabled_post_types, true ) ) { return $content; } if ( has_shortcode( $content, 'ukulele_chords' ) || ! $this->contains_chord_markup( $content ) ) { return $content; } return $this->render_song( $content, array( 'controls' => $this->settings->get( 'show_controls' ) ? 'true' : 'false', 'diagrams' => $this->settings->get( 'enable_diagrams' ) ? 'true' : 'false', 'transpose' => '0', 'print_button' => $this->settings->get( 'enable_print_button' ) ? 'true' : 'false', 'print_diagrams' => $this->settings->get( 'print_show_diagrams' ) ? 'true' : 'false', 'tuning' => $this->settings->get( 'default_tuning' ), 'enharmonic_preference' => $this->settings->get( 'enharmonic_preference' ), ) ); } /** * Prime front-end assets for a specific queried post. * * @param \WP_Post $post Post to inspect. * @return void */ private function prime_post_assets( \WP_Post $post ) { $content = (string) $post->post_content; if ( has_shortcode( $content, 'ukulele_chords' ) ) { $this->assets->mark_frontend_required(); foreach ( $this->get_shortcode_tunings( $content ) as $tuning ) { $this->assets->mark_tuning_required( $tuning ); } return; } if ( ! $this->settings->get( 'automatic_processing' ) ) { return; } $enabled_post_types = $this->settings->get( 'enabled_post_types' ); if ( ! is_array( $enabled_post_types ) || ! in_array( $post->post_type, $enabled_post_types, true ) ) { return; } if ( ! $this->contains_chord_markup( $content ) ) { return; } $this->assets->mark_frontend_required(); $this->assets->mark_tuning_required( (string) $this->settings->get( 'default_tuning' ) ); } /** * Render parsed song content using shared context. * * @param string $content Chord-marked content. * @param array $attributes Render attributes. * @return string */ private function render_song( $content, $attributes ) { ++self::$instance_count; $instance_id = 'da-plectrum-' . self::$instance_count; $parsed = $this->parser->parse( $content ); $library = da_plectrum_get_chord_library( $attributes['tuning'] ); $post_id = get_the_ID(); $post_title = $post_id ? get_the_title( $post_id ) : ''; $author_id = $post_id ? (int) get_post_field( 'post_author', $post_id ) : 0; $this->assets->mark_frontend_required(); $this->assets->mark_tuning_required( $attributes['tuning'] ); return $this->renderer->render( $parsed, array( 'instance_id' => $instance_id, 'attributes' => $attributes, 'library' => $library, 'settings' => array( 'footer_notice' => $this->settings->get( 'print_footer_notice' ), 'default_diagram_width' => (int) $this->settings->get( 'default_diagram_width' ), 'default_song_scale' => (float) $this->settings->get( 'default_song_scale' ), 'chord_prompt_font_size' => (int) $this->settings->get( 'chord_prompt_font_size' ), 'block_spacing' => (int) $this->settings->get( 'block_spacing' ), 'section_break_spacing' => (int) $this->settings->get( 'section_break_spacing' ), ), 'post' => array( 'id' => $post_id, 'title' => $post_title, 'author_id' => $author_id, 'author' => $author_id ? get_the_author_meta( 'display_name', $author_id ) : '', 'site_name' => get_bloginfo( 'name' ), 'year' => gmdate( 'Y' ), ), ) ); } /** * Detect likely chord markup before automatic processing. * * @param string $content Content to inspect. * @return bool */ private function contains_chord_markup( $content ) { return 1 === preg_match( '/\[[A-G](?:#|b)?(?:m|min|maj|sus|add|dim|aug|\+)?[^\]]*\]/', $content ); } /** * Extract tuning values from shortcode markup. * * @param string $content Raw post content. * @return array */ private function get_shortcode_tunings( $content ) { $tunings = array(); $pattern = get_shortcode_regex( array( 'ukulele_chords' ) ); if ( ! preg_match_all( "/$pattern/", $content, $matches, PREG_SET_ORDER ) ) { return array( 'gCEA' ); } foreach ( $matches as $match ) { $attributes = shortcode_parse_atts( $match[3] ?? '' ); $tuning = isset( $attributes['tuning'] ) && is_string( $attributes['tuning'] ) && '' !== $attributes['tuning'] ? $attributes['tuning'] : 'gCEA'; $tunings[] = $tuning; } return array_values( array_unique( $tunings ) ); } }