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' ],
] );
}
}