get_bloginfo( 'name' ), 'url' => home_url( '/' ), ]; if ( is_front_page() ) { return $trail; } if ( is_singular( 'post' ) ) { $categories = get_the_category(); if ( ! empty( $categories ) ) { $cat = $categories[0]; if ( $cat->parent ) { $ancestors = array_reverse( get_ancestors( $cat->term_id, 'category' ) ); foreach ( $ancestors as $ancestor_id ) { $ancestor = get_term( $ancestor_id, 'category' ); $trail[] = [ 'name' => $ancestor->name, 'url' => get_term_link( $ancestor ), ]; } } $trail[] = [ 'name' => $cat->name, 'url' => get_term_link( $cat ), ]; } $trail[] = [ 'name' => get_the_title(), 'url' => get_permalink(), ]; } elseif ( is_singular( 'page' ) ) { global $post; $ancestors = get_post_ancestors( $post ); $ancestors = array_reverse( $ancestors ); foreach ( $ancestors as $ancestor_id ) { $trail[] = [ 'name' => get_the_title( $ancestor_id ), 'url' => get_permalink( $ancestor_id ), ]; } $trail[] = [ 'name' => get_the_title(), 'url' => get_permalink(), ]; } elseif ( is_singular() ) { $post_type = get_post_type(); $post_type_object = get_post_type_object( $post_type ); if ( $post_type_object && $post_type_object->has_archive ) { $trail[] = [ 'name' => $post_type_object->labels->name, 'url' => get_post_type_archive_link( $post_type ), ]; } $trail[] = [ 'name' => get_the_title(), 'url' => get_permalink(), ]; } elseif ( is_category() || is_tag() || is_tax() ) { $term = get_queried_object(); if ( $term && $term->parent ) { $ancestors = array_reverse( get_ancestors( $term->term_id, $term->taxonomy ) ); foreach ( $ancestors as $ancestor_id ) { $ancestor = get_term( $ancestor_id, $term->taxonomy ); $trail[] = [ 'name' => $ancestor->name, 'url' => get_term_link( $ancestor ), ]; } } $trail[] = [ 'name' => $term ? $term->name : '', 'url' => $term ? get_term_link( $term ) : '', ]; } elseif ( is_author() ) { $trail[] = [ 'name' => get_the_author_meta( 'display_name', get_queried_object_id() ), 'url' => get_author_posts_url( get_queried_object_id() ), ]; } elseif ( is_search() ) { $trail[] = [ /* translators: %s: search query */ 'name' => sprintf( __( 'Search results for "%s"', 'shadowsync-seo' ), get_search_query() ), 'url' => '', ]; } elseif ( is_404() ) { $trail[] = [ 'name' => __( 'Page not found', 'shadowsync-seo' ), 'url' => '', ]; } return $trail; } // ── OUTPUT JSON-LD SCHEMA ─────────────────────────────── public function output_breadcrumb_schema() { if ( is_front_page() ) { return; } $trail = $this->get_trail(); if ( count( $trail ) < 2 ) { return; } $items = []; foreach ( $trail as $index => $crumb ) { $item = [ '@type' => 'ListItem', 'position' => $index + 1, 'name' => $crumb['name'], ]; if ( ! empty( $crumb['url'] ) ) { $item['item'] = $crumb['url']; } $items[] = $item; } $schema = [ '@context' => 'https://schema.org', '@type' => 'BreadcrumbList', 'itemListElement' => $items, ]; echo '' . "\n"; } // ── RENDER VISIBLE HTML BREADCRUMBS ───────────────────── public function render_breadcrumb_html( $atts = [] ) { $atts = shortcode_atts( [ 'separator' => '›', ], $atts ); $trail = $this->get_trail(); if ( count( $trail ) < 2 ) { return ''; } $html = ''; return $html; } // ── GUTENBERG BLOCK ────────────────────────────────────── public function register_block() { if ( ! function_exists( 'register_block_type' ) ) { return; } // Without an editor script the block exists only on the server and // never appears in the block inserter. wp_register_script( 'shadowsync-seo-breadcrumbs-block', SHADOWSYNC_SEO_URL . 'assets/breadcrumbs-block.js', [ 'wp-blocks', 'wp-element', 'wp-server-side-render', 'wp-i18n', 'wp-block-editor' ], SHADOWSYNC_SEO_VERSION, true ); register_block_type( 'shadowsync-seo/breadcrumbs', [ 'editor_script' => 'shadowsync-seo-breadcrumbs-block', 'render_callback' => [ $this, 'render_breadcrumb_html' ], ] ); } }