two breadcrumbs functions

one

<?php
/**
 * Dynamic Breadcrumb Function
 *
 * Outputs a breadcrumb trail for any WordPress page, post, CPT,
 * taxonomy archive, search results, or 404 page.
 *
 * Usage: <?php minglu_breadcrumbs(); ?>
 *
 * @param array $args Optional config overrides.
 */
function minglu_breadcrumbs( array $args = [] ): void {

	$defaults = [
		'separator'   => '<span class="breadcrumb__sep">/</span>',
		'home_label'  => __( 'Home', 'minglu' ),
		'show_on_home' => false, // hide breadcrumbs on the front page
	];
	$args = wp_parse_args( $args, $defaults );

	// Optionally hide on the front page.
	if ( is_front_page() && ! $args['show_on_home'] ) {
		return;
	}

	global $post;
	$sep   = $args['separator'];
	$crumbs = []; // [ 'label' => string, 'url' => string|null ]

	// ── Home ──────────────────────────────────────────────────
	$crumbs[] = [
		'label' => esc_html( $args['home_label'] ),
		'url'   => esc_url( home_url( '/' ) ),
	];

	// ── WooCommerce ───────────────────────────────────────────
	if ( function_exists( 'is_woocommerce' ) && is_woocommerce() ) {

		// Shop page.
		$shop_id = wc_get_page_id( 'shop' );
		if ( $shop_id && $shop_id !== -1 ) {
			$crumbs[] = [
				'label' => esc_html( get_the_title( $shop_id ) ),
				'url'   => esc_url( get_permalink( $shop_id ) ),
			];
		}

		if ( is_product_category() || is_product_tag() ) {
			$term = get_queried_object();
			// Ancestor categories.
			if ( $term->parent ) {
				foreach ( array_reverse( get_ancestors( $term->term_id, 'product_cat' ) ) as $ancestor_id ) {
					$ancestor = get_term( $ancestor_id, 'product_cat' );
					$crumbs[] = [
						'label' => esc_html( $ancestor->name ),
						'url'   => esc_url( get_term_link( $ancestor ) ),
					];
				}
			}
			// Current term — no link (last crumb).
			$crumbs[] = [ 'label' => esc_html( $term->name ), 'url' => null ];

		} elseif ( is_product() ) {
			// Product category trail above the product.
			$categories = get_the_terms( $post->ID, 'product_cat' );
			if ( $categories && ! is_wp_error( $categories ) ) {
				$cat = current( $categories );
				foreach ( array_reverse( get_ancestors( $cat->term_id, 'product_cat' ) ) as $ancestor_id ) {
					$ancestor = get_term( $ancestor_id, 'product_cat' );
					$crumbs[] = [
						'label' => esc_html( $ancestor->name ),
						'url'   => esc_url( get_term_link( $ancestor ) ),
					];
				}
				$crumbs[] = [
					'label' => esc_html( $cat->name ),
					'url'   => esc_url( get_term_link( $cat ) ),
				];
			}
			$crumbs[] = [ 'label' => esc_html( get_the_title() ), 'url' => null ];
		}

	// ── Standard taxonomy archive ─────────────────────────────
	} elseif ( is_tax() || is_category() || is_tag() ) {
		$term = get_queried_object();

		// Walk up ancestor chain.
		if ( ! empty( $term->parent ) ) {
			$taxonomy = $term->taxonomy;
			foreach ( array_reverse( get_ancestors( $term->term_id, $taxonomy ) ) as $ancestor_id ) {
				$ancestor = get_term( $ancestor_id, $taxonomy );
				$crumbs[] = [
					'label' => esc_html( $ancestor->name ),
					'url'   => esc_url( get_term_link( $ancestor ) ),
				];
			}
		}
		$crumbs[] = [ 'label' => esc_html( $term->name ), 'url' => null ];

	// ── Single post / CPT ─────────────────────────────────────
	} elseif ( is_single() ) {
		$post_type = get_post_type();

		if ( 'post' === $post_type ) {
			// Primary category (Yoast) or first assigned category.
			$primary_id = get_post_meta( $post->ID, '_yoast_wpseo_primary_category', true );
			$categories = get_the_category();

			if ( $primary_id ) {
				$cat = get_category( (int) $primary_id );
			} elseif ( ! empty( $categories ) ) {
				$cat = $categories[0];
			}

			if ( ! empty( $cat ) ) {
				foreach ( array_reverse( get_ancestors( $cat->term_id, 'category' ) ) as $ancestor_id ) {
					$ancestor = get_category( $ancestor_id );
					$crumbs[] = [
						'label' => esc_html( $ancestor->name ),
						'url'   => esc_url( get_category_link( $ancestor->term_id ) ),
					];
				}
				$crumbs[] = [
					'label' => esc_html( $cat->name ),
					'url'   => esc_url( get_category_link( $cat->term_id ) ),
				];
			}
		} else {
			// Custom post type — link its archive if one exists.
			$pto = get_post_type_object( $post_type );
			if ( $pto && $pto->has_archive ) {
				$crumbs[] = [
					'label' => esc_html( $pto->labels->name ),
					'url'   => esc_url( get_post_type_archive_link( $post_type ) ),
				];
			}
		}

		$crumbs[] = [ 'label' => esc_html( get_the_title() ), 'url' => null ];

	// ── Hierarchical pages ────────────────────────────────────
	} elseif ( is_page() ) {
		if ( $post->post_parent ) {
			foreach ( array_reverse( get_post_ancestors( $post->ID ) ) as $ancestor_id ) {
				$crumbs[] = [
					'label' => esc_html( get_the_title( $ancestor_id ) ),
					'url'   => esc_url( get_permalink( $ancestor_id ) ),
				];
			}
		}
		$crumbs[] = [ 'label' => esc_html( get_the_title() ), 'url' => null ];

	// ── CPT archive ───────────────────────────────────────────
	} elseif ( is_post_type_archive() ) {
		$crumbs[] = [ 'label' => esc_html( post_type_archive_title( '', false ) ), 'url' => null ];

	// ── Author archive ────────────────────────────────────────
	} elseif ( is_author() ) {
		$crumbs[] = [ 'label' => esc_html( get_queried_object()->display_name ), 'url' => null ];

	// ── Date archive ──────────────────────────────────────────
	} elseif ( is_year() ) {
		$crumbs[] = [ 'label' => get_the_date( 'Y' ), 'url' => null ];

	} elseif ( is_month() ) {
		$crumbs[] = [
			'label' => get_the_date( 'Y' ),
			'url'   => esc_url( get_year_link( get_the_date( 'Y' ) ) ),
		];
		$crumbs[] = [ 'label' => get_the_date( 'F Y' ), 'url' => null ];

	} elseif ( is_day() ) {
		$crumbs[] = [
			'label' => get_the_date( 'Y' ),
			'url'   => esc_url( get_year_link( get_the_date( 'Y' ) ) ),
		];
		$crumbs[] = [
			'label' => get_the_date( 'F Y' ),
			'url'   => esc_url( get_month_link( get_the_date( 'Y' ), get_the_date( 'm' ) ) ),
		];
		$crumbs[] = [ 'label' => get_the_date(), 'url' => null ];

	// ── Search results ────────────────────────────────────────
	} elseif ( is_search() ) {
		$crumbs[] = [
			/* translators: %s: search query */
			'label' => sprintf( esc_html__( 'Search: %s', 'minglu' ), esc_html( get_search_query() ) ),
			'url'   => null,
		];

	// ── 404 ───────────────────────────────────────────────────
	} elseif ( is_404() ) {
		$crumbs[] = [ 'label' => esc_html__( 'Page Not Found', 'minglu' ), 'url' => null ];
	}

	// ── Render ────────────────────────────────────────────────
	$last_index = count( $crumbs ) - 1;
	?>
	<div class="breadcrumb" id="breadcrumb">
		<div class="breadcrumb__container">
			<?php foreach ( $crumbs as $index => $crumb ) :
				$is_last = ( $index === $last_index );
			?>
				<?php if ( $index > 0 ) : ?>
					<?php echo $sep; // Already escaped above. ?>
				<?php endif; ?>

				<?php if ( ! $is_last && $crumb['url'] ) : ?>
					<a href="<?php echo $crumb['url']; ?>"><?php echo $crumb['label']; ?></a>
				<?php else : ?>
					<span <?php echo $is_last ? 'id="breadcrumbTitle"' : ''; ?>><?php echo $crumb['label']; ?></span>
				<?php endif; ?>

			<?php endforeach; ?>
		</div>
	</div>
	<?php
}

two

<?php
/**
 * Dynamic WordPress Breadcrumbs Function
 * * Replaces static HTML breadcrumbs with a fully dynamic, SEO-friendly, 
 * and context-aware breadcrumb menu matching your CSS classes.
 *
 * @param array $args Optional arguments to customize labels and behavior.
 * @return void Prints the breadcrumb HTML.
 */
function custom_breadcrumbs( $args = array() ) {
    // Only run on front-end, and skip on the homepage/frontpage unless specified
    if ( is_front_page() || is_home() ) {
        return;
    }

    // Default configuration arguments
    $defaults = array(
        'separator'      => '/', // Your design separator character
        'home_label'     => __( 'Home', 'text-domain' ),
        'show_current'   => true, // Show the current page title at the end
        'container_class'=> 'breadcrumb',
        'inner_class'    => 'breadcrumb__container',
        'sep_class'      => 'breadcrumb__sep',
        'current_id'     => 'breadcrumbTitle',
    );

    // Merge user arguments with defaults
    $args = wp_parse_args( $args, $defaults );

    global $post;

    // Array to hold breadcrumb items: array( 'url' => '', 'label' => '' )
    $crumbs = array();

    // 1. Always start with the Home Link
    $crumbs[] = array(
        'url'   => home_url( '/' ),
        'label' => $args['home_label']
    );

    // 2. Determine Page Context and Build the Hierarchy
    if ( is_page() && ! is_front_page() ) {
        // Handle hierarchical Pages
        if ( $post->post_parent ) {
            $ancestors = array_reverse( get_post_ancestors( $post->ID ) );
            foreach ( $ancestors as $ancestor_id ) {
                $crumbs[] = array(
                    'url'   => get_permalink( $ancestor_id ),
                    'label' => get_the_title( $ancestor_id )
                );
            }
        }
        $crumbs[] = array(
            'url'   => '',
            'label' => get_the_title()
        );

    } elseif ( is_single() ) {
        // Handle Single Posts (including Custom Post Types)
        $post_type = get_post_type();

        if ( $post_type !== 'post' ) {
            // For Custom Post Types, attempt to get the CPT Archive page first
            $post_type_object = get_post_type_object( $post_type );
            $archive_link     = get_post_type_archive_link( $post_type );
            
            if ( $archive_link ) {
                $crumbs[] = array(
                    'url'   => $archive_link,
                    'label' => $post_type_object->labels->name
                );
            }
            
            // Handle custom taxonomies if associated with CPT
            $taxonomies = get_object_taxonomies( $post_type, 'objects' );
            if ( ! empty( $taxonomies ) ) {
                // Grab the first custom taxonomy assigned to this post
                foreach ( $taxonomies as $tax_name => $tax_obj ) {
                    if ( $tax_obj->hierarchical ) {
                        $terms = get_the_terms( $post->ID, $tax_name );
                        if ( ! empty( $terms ) && ! is_wp_error( $terms ) ) {
                            $main_term = $terms[0];
                            // Get term ancestors if any
                            $term_ancestors = array_reverse( get_ancestors( $main_term->term_id, $tax_name ) );
                            foreach ( $term_ancestors as $ancestor_id ) {
                                $ancestor_term = get_term( $ancestor_id, $tax_name );
                                $crumbs[] = array(
                                    'url'   => get_term_link( $ancestor_term ),
                                    'label' => $ancestor_term->name
                                );
                            }
                            $crumbs[] = array(
                                'url'   => get_term_link( $main_term ),
                                'label' => $main_term->name
                            );
                            break; // Stop after first taxonomy found
                        }
                    }
                }
            }
        } else {
            // Standard Blog Post: Get category hierarchy
            $categories = get_the_category();
            if ( ! empty( $categories ) ) {
                // Respect Yoast Primary Category if installed, otherwise grab the first category
                $primary_cat_id = class_exists( 'WPSEO_Primary_Term' ) 
                    ? ( new WPSEO_Primary_Term( 'category', $post->ID ) )->get_primary_term() 
                    : null;
                
                $category = $primary_cat_id ? get_term( $primary_cat_id ) : $categories[0];
                
                // Fetch category ancestors
                $cat_ancestors = array_reverse( get_ancestors( $category->term_id, 'category' ) );
                foreach ( $cat_ancestors as $ancestor_id ) {
                    $ancestor_cat = get_category( $ancestor_id );
                    $crumbs[] = array(
                        'url'   => get_category_link( $ancestor_id ),
                        'label' => $ancestor_cat->name
                    );
                }
                
                $crumbs[] = array(
                    'url'   => get_category_link( $category->term_id ),
                    'label' => $category->name
                );
            }
        }

        $crumbs[] = array(
            'url'   => '',
            'label' => get_the_title()
        );

    } elseif ( is_category() ) {
        // Category Archive
        $current_cat = get_queried_object();
        if ( $current_cat->parent ) {
            $cat_ancestors = array_reverse( get_ancestors( $current_cat->term_id, 'category' ) );
            foreach ( $cat_ancestors as $ancestor_id ) {
                $ancestor_cat = get_category( $ancestor_id );
                $crumbs[] = array(
                    'url'   => get_category_link( $ancestor_id ),
                    'label' => $ancestor_cat->name
                );
            }
        }
        $crumbs[] = array(
            'url'   => '',
            'label' => $current_cat->name
        );

    } elseif ( is_tag() ) {
        // Tag Archive
        $crumbs[] = array(
            'url'   => '',
            'label' => single_tag_title( '', false )
        );

    } elseif ( is_tax() ) {
        // Custom Taxonomy Archive
        $current_term = get_queried_object();
        $taxonomy     = $current_term->taxonomy;
        if ( $current_term->parent ) {
            $term_ancestors = array_reverse( get_ancestors( $current_term->term_id, $taxonomy ) );
            foreach ( $term_ancestors as $ancestor_id ) {
                $ancestor_term = get_term( $ancestor_id, $taxonomy );
                $crumbs[] = array(
                    'url'   => get_term_link( $ancestor_term ),
                    'label' => $ancestor_term->name
                );
            }
        }
        $crumbs[] = array(
            'url'   => '',
            'label' => $current_term->name
        );

    } elseif ( is_post_type_archive() ) {
        // Custom Post Type Archive Page
        $post_type_object = get_queried_object();
        $crumbs[] = array(
            'url'   => '',
            'label' => $post_type_object->labels->name
        );

    } elseif ( is_search() ) {
        // Search Results Page
        $crumbs[] = array(
            'url'   => '',
            'label' => sprintf( __( 'Search results for: "%s"', 'text-domain' ), get_search_query() )
        );

    } elseif ( is_day() ) {
        // Daily Archive
        $crumbs[] = array(
            'url'   => '',
            'label' => get_the_date()
        );

    } elseif ( is_month() ) {
        // Monthly Archive
        $crumbs[] = array(
            'url'   => '',
            'label' => get_the_date( 'F Y' )
        );

    } elseif ( is_year() ) {
        // Yearly Archive
        $crumbs[] = array(
            'url'   => '',
            'label' => get_the_date( 'Y' )
        );

    } elseif ( is_author() ) {
        // Author Archive
        $author = get_queried_object();
        $crumbs[] = array(
            'url'   => '',
            'label' => sprintf( __( 'Articles by: %s', 'text-domain' ), $author->display_name )
        );

    } elseif ( is_404() ) {
        // 404 Error Page
        $crumbs[] = array(
            'url'   => '',
            'label' => __( 'Page Not Found', 'text-domain' )
        );
    }

    // 3. Render Output
    if ( ! empty( $crumbs ) ) {
        echo '<div class="' . esc_attr( $args['container_class'] ) . '" id="breadcrumb">';
        echo '<div class="' . esc_attr( $args['inner_class'] ) . '">';

        $total_crumbs = count( $crumbs );

        foreach ( $crumbs as $index => $crumb ) {
            $is_last = ( $index === $total_crumbs - 1 );

            if ( $is_last ) {
                // The current page is always unlinked and styled with the unique ID
                if ( $args['show_current'] ) {
                    echo '<span id="' . esc_attr( $args['current_id'] ) . '">' . esc_html( $crumb['label'] ) . '</span>';
                }
            } else {
                // Normal linked breadcrumb
                echo '<a href="' . esc_url( $crumb['url'] ) . '">' . esc_html( $crumb['label'] ) . '</a>';
                
                // Add separator
                echo '<span class="' . esc_attr( $args['sep_class'] ) . '">' . esc_html( $args['separator'] ) . '</span>';
            }
        }

        echo '</div>';
        echo '</div>';
    }
}
×
two breadcrumbs functions

two breadcrumbs functions

one <?php /** * D...