<?php

/**
 * Yoast SEO.
 *
 * @link    https://aiopodcasting.com
 * @since   1.0.0
 *
 * @package AiO_Podcast_Studio
 */

// Exit if accessed directly
if ( ! defined( 'WPINC' ) ) {
	die;
}

/**
 * AIOPOD_Public_Yoast class.
 *
 * @since 1.0.0
 */
class AIOPOD_Public_Yoast {

	/**
	 * Construct Yoast SEO title for our category and user podcasts pages.
	 *
	 * @since  1.0.0
	 * @param  array $title The Yoast title.
	 * @return              Filtered title.
	 */
	public function wpseo_title( $title ) {	
		global $post;

		if ( ! isset( $post ) ) {
			return $title;
		}

		$pages_settings = aiopod_get_option( 'aiopod_pages_settings' );

		if ( $post->ID !== (int) $pages_settings['category'] && $post->ID !== (int) $pages_settings['tag'] ) {
			return $title;
		}

		$wpseo_titles = get_option( 'wpseo_titles' );

		$sep_options = WPSEO_Option_Titles::get_instance()->get_separator_options();

		if ( isset( $wpseo_titles['separator'] ) && isset( $sep_options[ $wpseo_titles['separator'] ] ) ) {
			$sep = $sep_options[ $wpseo_titles['separator'] ];
		} else {
			$sep = '-'; // Setting default separator if Admin didn't set it from backed
		}

		$replacements = array(
			'%%sep%%'              => $sep,						
			'%%page%%'             => '',
			'%%primary_category%%' => '',
			'%%sitename%%'         => sanitize_text_field( get_bloginfo( 'name' ) )
		);

		$title_template = '';
		
		// Category page
		if ( $post->ID === (int) $pages_settings['category'] ) {			
			if ( $slug = get_query_var( 'aiopod_category' ) ) {
				// Get Archive SEO title
				if ( array_key_exists( 'title-tax-aiopod_categories', $wpseo_titles ) ) {
					$title_template = $wpseo_titles['title-tax-aiopod_categories'];
				}

				// Get Term SEO title
				if ( $term = get_term_by( 'slug', $slug, 'aiopod_categories' ) ) {		
					$replacements['%%term_title%%'] = $term->name;
					
					$meta = get_option( 'wpseo_taxonomy_meta' );

					if ( array_key_exists( 'aiopod_categories', $meta ) ) {
						if ( array_key_exists( $term->term_id, $meta['aiopod_categories'] ) ) {
							if ( array_key_exists( 'wpseo_title', $meta['aiopod_categories'][ $term->term_id ] ) ) {
								$title_template = $meta['aiopod_categories'][ $term->term_id ]['wpseo_title'];
							}
						}
					}
				}
			}				
		}

		// Tag page
		if ( $post->ID === (int) $pages_settings['tag'] ) {			
			if ( $slug = get_query_var( 'aiopod_tag' ) ) {
				// Get Archive SEO title
				if ( array_key_exists( 'title-tax-aiopod_tags', $wpseo_titles ) ) {
					$title_template = $wpseo_titles['title-tax-aiopod_tags'];
				}

				// Get Term SEO title
				if ( $term = get_term_by( 'slug', $slug, 'aiopod_tags' ) ) {		
					$replacements['%%term_title%%'] = $term->name;
					
					$meta = get_option( 'wpseo_taxonomy_meta' );

					if ( array_key_exists( 'aiopod_tags', $meta ) ) {
						if ( array_key_exists( $term->term_id, $meta['aiopod_tags'] ) ) {
							if ( array_key_exists( 'wpseo_title', $meta['aiopod_tags'][ $term->term_id ] ) ) {
								$title_template = $meta['aiopod_tags'][ $term->term_id ]['wpseo_title'];
							}
						}
					}
				}
			}				
		}

		// Participant page
		if ( $post->ID === (int) $pages_settings['participant'] ) {			
			if ( $slug = get_query_var( 'aiopod_participant' ) ) {
				// Get Archive SEO title
				if ( array_key_exists( 'title-tax-aiopod_participants', $wpseo_titles ) ) {
					$title_template = $wpseo_titles['title-tax-aiopod_participants'];
				}

				// Get Term SEO title
				if ( $term = get_term_by( 'slug', $slug, 'aiopod_participants' ) ) {		
					$replacements['%%term_title%%'] = $term->name;
					
					$meta = get_option( 'wpseo_taxonomy_meta' );

					if ( array_key_exists( 'aiopod_participants', $meta ) ) {
						if ( array_key_exists( $term->term_id, $meta['aiopod_participants'] ) ) {
							if ( array_key_exists( 'wpseo_title', $meta['aiopod_participants'][ $term->term_id ] ) ) {
								$title_template = $meta['aiopod_participants'][ $term->term_id ]['wpseo_title'];
							}
						}
					}
				}
			}				
		}
		
		// Return
		if ( ! empty( $title_template ) ) {
			$title = strtr( $title_template, $replacements );
		}

		return $title;	
	}

	/**
	 * Construct Yoast SEO description for our category and user podcasts pages.
	 *
	 * @since  1.0.0
	 * @param  array $desc The Yoast description.
	 * @return             Filtered description.
	 */
	public function wpseo_metadesc( $desc ) {	
		global $post;

		if ( ! isset( $post ) ) {
			return $desc;
		}

		$pages_settings = aiopod_get_option( 'aiopod_pages_settings' );
		
		if ( $post->ID != $pages_settings['category'] && $post->ID != $pages_settings['tag'] ) {
			return $desc;
		}

		$wpseo_titles = get_option( 'wpseo_titles' );

		$sep_options = WPSEO_Option_Titles::get_instance()->get_separator_options();

		if ( isset( $wpseo_titles['separator'] ) && isset( $sep_options[ $wpseo_titles['separator'] ] ) ) {
			$sep = $sep_options[ $wpseo_titles['separator'] ];
		} else {
			$sep = '-'; // Setting default separator if Admin didn't set it from backed
		}

		$replacements = array(
			'%%sep%%'              => $sep,						
			'%%page%%'             => '',
			'%%title%%'            => '',
			'%%primary_category%%' => '',
			'%%sitename%%'         => sanitize_text_field( get_bloginfo( 'name' ) )
		);

		$desc_template = '';

		// Category page
		if ( $post->ID === (int) $pages_settings['category'] ) {			
			if ( $slug = get_query_var( 'aiopod_category' ) ) {
				// Get Archive SEO desc
				if ( array_key_exists( 'metadesc-tax-aiopod_categories', $wpseo_titles ) ) {
					$desc_template = $wpseo_titles['metadesc-tax-aiopod_categories'];
				}

				// Get Term SEO desc
				if ( $term = get_term_by( 'slug', $slug, 'aiopod_categories' ) ) {
					$replacements['%%term_title%%'] = $term->name;
					
					$meta = get_option( 'wpseo_taxonomy_meta' );

					if ( array_key_exists( 'aiopod_categories', $meta ) ) {
						if ( array_key_exists( $term->term_id, $meta['aiopod_categories'] ) ) {
							if ( array_key_exists( 'wpseo_desc', $meta['aiopod_categories'][ $term->term_id ] ) ) {
								$desc_template = $meta['aiopod_categories'][ $term->term_id ]['wpseo_desc'];
							}
						}
					}
				}
			}				
		}

		// Tag page
		if ( $post->ID === (int) $pages_settings['tag'] ) {			
			if ( $slug = get_query_var( 'aiopod_tag' ) ) {
				// Get Archive SEO desc
				if ( array_key_exists( 'metadesc-tax-aiopod_tags', $wpseo_titles ) ) {
					$desc_template = $wpseo_titles['metadesc-tax-aiopod_tags'];
				}

				// Get Term SEO desc
				if ( $term = get_term_by( 'slug', $slug, 'aiopod_tags' ) ) {
					$replacements['%%term_title%%'] = $term->name;	
					
					$meta = get_option( 'wpseo_taxonomy_meta' );

					if ( array_key_exists( 'aiopod_tags', $meta ) ) {
						if ( array_key_exists( $term->term_id, $meta['aiopod_tags'] ) ) {
							if ( array_key_exists( 'wpseo_desc', $meta['aiopod_tags'][ $term->term_id ] ) ) {
								$desc_template = $meta['aiopod_tags'][ $term->term_id ]['wpseo_desc'];
							}
						}
					}
				}
			}				
		}

		// Participant page
		if ( $post->ID === (int) $pages_settings['participant'] ) {			
			if ( $slug = get_query_var( 'aiopod_participant' ) ) {
				// Get Archive SEO desc
				if ( array_key_exists( 'metadesc-tax-aiopod_participants', $wpseo_titles ) ) {
					$desc_template = $wpseo_titles['metadesc-tax-aiopod_participants'];
				}

				// Get Term SEO desc
				if ( $term = get_term_by( 'slug', $slug, 'aiopod_participants' ) ) {
					$replacements['%%term_title%%'] = $term->name;	
					
					$meta = get_option( 'wpseo_taxonomy_meta' );

					if ( array_key_exists( 'aiopod_participants', $meta ) ) {
						if ( array_key_exists( $term->term_id, $meta['aiopod_participants'] ) ) {
							if ( array_key_exists( 'wpseo_desc', $meta['aiopod_participants'][ $term->term_id ] ) ) {
								$desc_template = $meta['aiopod_participants'][ $term->term_id ]['wpseo_desc'];
							}
						}
					}
				}
			}				
		}
		
		// Return
		if ( ! empty( $desc_template ) ) {
			$desc = strtr( $desc_template, $replacements );
		}

		return $desc;	
	}

	/**
	 * Override the Yoast SEO canonical URL on our category and user podcasts pages.
	 *
	 * @since  1.0.0
	 * @param  array $url The Yoast canonical URL.
	 * @return            Filtered canonical URL.
	 */
	public function wpseo_canonical( $url ) {	
		global $post;

		if ( ! isset( $post ) ) {
			return $url;
		}
		
		$pages_settings = aiopod_get_option( 'aiopod_pages_settings' );

		// Category page
		if ( $post->ID === (int) $pages_settings['category'] ) {			
			if ( $slug = get_query_var( 'aiopod_category' ) ) {
				if ( $term = get_term_by( 'slug', $slug, 'aiopod_categories' ) ) {
					$url = aiopod_get_category_page_url( $term );
				}
			}				
		}

		// Tag page
		if ( $post->ID === (int) $pages_settings['tag'] ) {			
			if ( $slug = get_query_var( 'aiopod_tag' ) ) {
				if ( $term = get_term_by( 'slug', $slug, 'aiopod_tags' ) ) {
					$url = aiopod_get_tag_page_url( $term );
				}
			}				
		}

		// Participant page
		if ( $post->ID === (int) $pages_settings['participant'] ) {			
			if ( $slug = get_query_var( 'aiopod_participant' ) ) {
				if ( $term = get_term_by( 'slug', $slug, 'aiopod_participants' ) ) {
					$url = aiopod_get_participant_page_url( $term );
				}
			}				
		}
		
		// Return
		return $url;	
	}

	/**
	 * Override the Yoast SEO Open Graph image URLs on our plugin pages.
	 *
	 * @since  1.0.0
	 * @param  array $url The Yoast image URL.
	 * @return            Filtered image URL.
	 */
	public function wpseo_opengraph_image( $url ) {
		global $post;

		if ( ! isset( $post ) ) {
			return $url;
		}
		
		if ( is_singular( array( 'aiopod_podcasts', 'aiopod_episodes' ) ) ) {
			$image = get_post_meta( $post->ID, '_yoast_wpseo_opengraph-image', true );

			if ( empty( $image ) ) {
				$image_data = aiopod_get_image(	array(
					'post_id' => $post->ID,
					'size'    => 'large',
					'alt'     => ''
				) );

				$image = $image_data['src'];
			}
			
			if ( ! empty( $image ) ) {
				$url = $image;
			}			
		} else {
			$pages_settings = aiopod_get_option( 'aiopod_pages_settings' );

			// Category page
			if ( $post->ID === (int) $pages_settings['category'] ) {			
				if ( $slug = get_query_var( 'aiopod_category' ) ) {
					if ( $term = get_term_by( 'slug', $slug, 'aiopod_categories' ) ) {
						$meta  = get_option( 'wpseo_taxonomy_meta' );
						$image = '';

						if ( array_key_exists( 'aiopod_categories', $meta ) ) { // Get custom share image from Yoast
							if ( array_key_exists( $term->term_id, $meta['aiopod_categories'] ) ) {
								if ( array_key_exists( 'wpseo_opengraph-image', $meta['aiopod_categories'][ $term->term_id ] ) ) {
									$image = $meta['aiopod_categories'][ $term->term_id ]['wpseo_opengraph-image'];
								}
							}
						}

						if ( empty( $image ) ) {
							$image_data = aiopod_get_image(	array(
								'term_id' => $term->term_id,
								'size'    => 'large',
								'alt'     => ''
							) );

							$image = $image_data['src'];
						}

						if ( ! empty( $image ) ) {
							$url = $image;
						}
					}
				}				
			}

			// Tag page
			if ( $post->ID === (int) $pages_settings['tag'] ) {			
				if ( $slug = get_query_var( 'aiopod_tag' ) ) {
					if ( $term = get_term_by( 'slug', $slug, 'aiopod_tags' ) ) {
						$meta  = get_option( 'wpseo_taxonomy_meta' );
						$image = '';

						if ( array_key_exists( 'aiopod_tags', $meta ) ) { // Get custom share image from Yoast
							if ( array_key_exists( $term->term_id, $meta['aiopod_tags'] ) ) {
								if ( array_key_exists( 'wpseo_opengraph-image', $meta['aiopod_tags'][ $term->term_id ] ) ) {
									$image = $meta['aiopod_tags'][ $term->term_id ]['wpseo_opengraph-image'];
								}
							}
						}

						if ( ! empty( $image ) ) {
							$url = $image;
						}
					}
				}				
			}

			// Participant page
			if ( $post->ID === (int) $pages_settings['participant'] ) {			
				if ( $slug = get_query_var( 'aiopod_participant' ) ) {
					if ( $term = get_term_by( 'slug', $slug, 'aiopod_participants' ) ) {
						$meta  = get_option( 'wpseo_taxonomy_meta' );
						$image = '';

						if ( array_key_exists( 'aiopod_participants', $meta ) ) { // Get custom share image from Yoast
							if ( array_key_exists( $term->term_id, $meta['aiopod_participants'] ) ) {
								if ( array_key_exists( 'wpseo_opengraph-image', $meta['aiopod_participants'][ $term->term_id ] ) ) {
									$image = $meta['aiopod_participants'][ $term->term_id ]['wpseo_opengraph-image'];
								}
							}
						}

						if ( ! empty( $image ) ) {
							$url = $image;
						}
					}
				}				
			}
		}

		// Return
		return $url;
	}

	/**
	 * Add custom Twitter Social Share images for Yoast SEO.
	 *
	 * @since  1.0.0
	 * @param  array $url The Yoast image URL.
	 * @return            Filtered image URL.
	 */
	public function wpseo_twitter_image( $url ) {
		global $post;

		if ( ! isset( $post ) ) {
			return $url;
		}
		
		if ( is_singular( array( 'aiopod_podcasts', 'aiopod_episodes' ) ) ) {
			$image = get_post_meta( $post->ID, '_yoast_wpseo_twitter-image', true );

			if ( empty( $image ) ) {
				$image_data = aiopod_get_image(	array(
					'post_id' => $post->ID,
					'size'    => 'large',
					'alt'     => ''
				) );

				$image = $image_data['src'];
			}
			
			if ( ! empty( $image ) ) {
				$url = $image;
			}			
		} else {
			$pages_settings = aiopod_get_option( 'aiopod_pages_settings' );

			// Category page
			if ( $post->ID === (int) $pages_settings['category'] ) {			
				if ( $slug = get_query_var( 'aiopod_category' ) ) {
					if ( $term = get_term_by( 'slug', $slug, 'aiopod_categories' ) ) {
						$meta  = get_option( 'wpseo_taxonomy_meta' );
						$image = '';

						if ( array_key_exists( 'aiopod_categories', $meta ) ) { // Get custom share image from Yoast
							if ( array_key_exists( $term->term_id, $meta['aiopod_categories'] ) ) {
								if ( array_key_exists( 'wpseo_twitter-image', $meta['aiopod_categories'][ $term->term_id ] ) ) {
									$image = $meta['aiopod_categories'][ $term->term_id ]['wpseo_twitter-image'];
								}
							}
						}

						if ( empty( $image ) ) {
							$image_data = aiopod_get_image(	array(
								'term_id' => $term->term_id,
								'size'    => 'large',
								'alt'     => ''
							) );

							$image = $image_data['src'];
						}

						if ( ! empty( $image ) ) {
							$url = $image;
						}	
					}				
				}				
			}

			// Tag page
			if ( $post->ID === (int) $pages_settings['tag'] ) {			
				if ( $slug = get_query_var( 'aiopod_tag' ) ) {
					if ( $term = get_term_by( 'slug', $slug, 'aiopod_tags' ) ) {
						$meta  = get_option( 'wpseo_taxonomy_meta' );
						$image = '';

						if ( array_key_exists( 'aiopod_tags', $meta ) ) { // Get custom share image from Yoast
							if ( array_key_exists( $term->term_id, $meta['aiopod_tags'] ) ) {
								if ( array_key_exists( 'wpseo_twitter-image', $meta['aiopod_tags'][ $term->term_id ] ) ) {
									$image = $meta['aiopod_tags'][ $term->term_id ]['wpseo_twitter-image'];
								}
							}
						}

						if ( ! empty( $image ) ) {
							$url = $image;	
						}
					}				
				}				
			}

			// Participant page
			if ( $post->ID === (int) $pages_settings['participant'] ) {			
				if ( $slug = get_query_var( 'aiopod_participant' ) ) {
					if ( $term = get_term_by( 'slug', $slug, 'aiopod_participants' ) ) {
						$meta  = get_option( 'wpseo_taxonomy_meta' );
						$image = '';

						if ( array_key_exists( 'aiopod_participants', $meta ) ) { // Get custom share image from Yoast
							if ( array_key_exists( $term->term_id, $meta['aiopod_participants'] ) ) {
								if ( array_key_exists( 'wpseo_twitter-image', $meta['aiopod_participants'][ $term->term_id ] ) ) {
									$image = $meta['aiopod_participants'][ $term->term_id ]['wpseo_twitter-image'];
								}
							}
						}

						if ( ! empty( $image ) ) {
							$url = $image;	
						}
					}				
				}				
			}
		}

		// Return
		return $url;
	}

	/**
	 * Filter Yoast SEO breadcrumbs.
	 *
	 * @since  1.0.0
	 * @param  array $crumbs Array of crumbs.
	 * @return array $crumbs Filtered array of crumbs.
	 */
	public function wpseo_breadcrumb_links( $crumbs ) {
		global $post;

		if ( empty( $post ) ) {
			return $crumbs;
		}

		// Explicit CPT → option key mapping (future-proof)
		$archive_map = array(
			'aiopod_podcasts' => 'podcast_archive_page',
			'aiopod_episodes' => 'episode_archive_page'
		);

		$allowed_post_types = array_keys( $archive_map );

		if ( is_singular( $allowed_post_types ) ) {
			// The queried object, not the global $post, so a theme calling the breadcrumbs from
			// inside a secondary loop still gets the trail for the page being viewed
			$crumbs = $this->add_archive_page_crumbs( $crumbs, get_post_type( get_queried_object_id() ), $archive_map );
		} else {
			$pages_settings = aiopod_get_option( 'aiopod_pages_settings' );

			// On every page the plugin manages, fill in any ancestor Yoast has not supplied
			// itself, so a page nested under the podcast archive reads as the whole path to it
			$plugin_pages = array( 'category', 'tag', 'participant', 'podcast_archive_page', 'episode_archive_page' );

			foreach ( $plugin_pages as $page_key ) {
				if ( ! empty( $pages_settings[ $page_key ] ) && $post->ID === (int) $pages_settings[ $page_key ] ) {
					$crumbs = $this->add_page_ancestor_crumbs( $crumbs, $post->ID );

					break;
				}
			}

			if ( $post->ID === (int) $pages_settings['category'] ) {
				if ( $slug = get_query_var( 'aiopod_category' ) ) {
					if ( $term = get_term_by( 'slug', $slug, 'aiopod_categories' ) ) {
						// Include the parent categories if available
						if ( $ancestors = get_ancestors( $term->term_id, 'aiopod_categories' ) ) {
							$ancestors = array_reverse( $ancestors );

							foreach ( $ancestors as $term_id ) {
								if ( $parent_term = get_term_by( 'term_id', $term_id, 'aiopod_categories' ) ) {
									$crumbs[] = array(
										'text' => $parent_term->name,
										'url'  => aiopod_get_category_page_url( $parent_term )
									);
								}
							}
						}

						// Include the current category page. The URL matters: Yoast drops the whole
						// BreadcrumbList when a crumb has no `url` key at all
						$crumbs[] = array(
							'text' => $term->name,
							'url'  => aiopod_get_category_page_url( $term )
						);	
					}		
				}
			}

			if ( $post->ID === (int) $pages_settings['tag'] ) {
				if ( $slug = get_query_var( 'aiopod_tag' ) ) {
					if ( $term = get_term_by( 'slug', $slug, 'aiopod_tags' ) ) {
						$crumbs[] = array(
							'text' => $term->name,
							'url'  => aiopod_get_tag_page_url( $term )
						);	
					}		
				}
			}

			if ( $post->ID === (int) $pages_settings['participant'] ) {
				if ( $slug = get_query_var( 'aiopod_participant' ) ) {
					if ( $term = get_term_by( 'slug', $slug, 'aiopod_participants' ) ) {
						$crumbs[] = array(
							'text' => $term->name,
							'url'  => aiopod_get_participant_page_url( $term )
						);	
					}		
				}
			}
		}

		return $crumbs;
	}

	/**
	 * Build the trail of a single podcast or episode.
	 *
	 * An episode reads `Home > Podcasts > Show > Episode`: the show it belongs to is the useful step,
	 * and the episode archive is not on the way to it, so that crumb is replaced rather than kept.
	 * A podcast reads `Home > Podcasts > Show`. Both are the same shape whatever the archive pages
	 * are set to, which is the point.
	 *
	 * @access private
	 * @since  1.0.4
	 * @param  array  $crumbs      Array of crumbs.
	 * @param  string $post_type   Post type of the single being viewed.
	 * @param  array  $archive_map CPT → archive page option key.
	 * @return array  $crumbs      Filtered array of crumbs.
	 */
	private function add_archive_page_crumbs( $crumbs, $post_type, $archive_map ) {
		if ( empty( $archive_map[ $post_type ] ) ) {
			return $crumbs;
		}

		if ( 'aiopod_episodes' === $post_type ) {
			$episode_id = get_queried_object_id();
			$podcast_id = aiopod_get_episode_podcast_id( $episode_id );

			// An episode with no published show of its own keeps the episode archive trail
			if ( $podcast_id ) {
				$chain = $this->get_archive_crumbs( 'aiopod_podcasts', $archive_map );

				if ( ! empty( $chain ) ) {
					$chain[] = $this->get_page_crumb( $podcast_id );

					$crumbs = $this->remove_archive_crumb( $crumbs, $post_type );

					return $this->insert_crumb_chain( $crumbs, $chain );
				}
			}

			$crumbs = $this->remove_unpublished_podcast_crumb( $crumbs, $episode_id );
		}

		$chain = $this->get_archive_crumbs( $post_type, $archive_map, true );

		if ( empty( $chain ) ) {
			return $crumbs;
		}

		// Yoast adds its own archive crumb for a post type that still has an archive. Where it did,
		// its text is the owner's Search Appearance setting, so only the URL is redirected
		$page_url = $chain[ count( $chain ) - 1 ]['url'];

		foreach ( $crumbs as $index => $crumb ) {
			if ( ! empty( $crumb['ptarchive'] ) && $crumb['ptarchive'] === $post_type ) {
				$crumbs[ $index ]['url'] = $page_url;

				return $crumbs;
			}
		}

		return $this->insert_crumb_chain( $crumbs, $chain );
	}

	/**
	 * Build the crumbs that stand for a post type's archive.
	 *
	 * The assigned archive page where there is one — with its own ancestors, so a nested page reads
	 * as the whole path to it — and the post type's own archive where there is not.
	 *
	 * @access private
	 * @since  1.0.4
	 * @param  string $post_type   Post type whose archive is wanted.
	 * @param  array  $archive_map CPT → archive page option key.
	 * @param  bool   $page_only   Return nothing rather than fall back to the post type archive.
	 * @return array               Crumbs, outermost first. Empty when there is no archive to point at.
	 */
	private function get_archive_crumbs( $post_type, $archive_map, $page_only = false ) {
		$chain = array();

		$pages_settings = aiopod_get_option( 'aiopod_pages_settings' );
		$option_key     = isset( $archive_map[ $post_type ] ) ? $archive_map[ $post_type ] : '';

		if ( $option_key && ! empty( $pages_settings[ $option_key ] ) ) {
			$page_id = (int) $pages_settings[ $option_key ];
			$page    = get_post( $page_id );

			if ( $page && 'publish' === $page->post_status && get_permalink( $page_id ) ) {
				foreach ( array_reverse( get_post_ancestors( $page_id ) ) as $ancestor_id ) {
					$ancestor = get_post( $ancestor_id );

					if ( $ancestor && 'publish' === $ancestor->post_status ) {
						$chain[] = $this->get_page_crumb( $ancestor_id );
					}
				}

				$chain[] = $this->get_page_crumb( $page_id );

				return $chain;
			}
		}

		// No usable page assigned. The caller decides whether the post type's own archive will do:
		// it will for an episode pointed at the podcast archive, and it will not where Yoast has
		// already drawn that same archive crumb itself
		if ( $page_only ) {
			return $chain;
		}

		$url = get_post_type_archive_link( $post_type );
		$obj = get_post_type_object( $post_type );

		if ( ! $url || ! $obj ) {
			return $chain;
		}

		// Yoast's own Search Appearance title for this archive, where the owner set one
		$text = WPSEO_Options::get( 'bctitle-ptarchive-' . $post_type );

		$chain[] = array(
			'url'  => $url,
			'text' => empty( $text ) ? $obj->labels->name : $text
		);

		return $chain;
	}

	/**
	 * Drop the post type archive crumb Yoast drew for a post type.
	 *
	 * @access private
	 * @since  1.0.4
	 * @param  array  $crumbs    Array of crumbs.
	 * @param  string $post_type Post type whose archive crumb is not wanted.
	 * @return array  $crumbs    Filtered array of crumbs.
	 */
	private function remove_archive_crumb( $crumbs, $post_type ) {
		foreach ( $crumbs as $index => $crumb ) {
			if ( ! empty( $crumb['ptarchive'] ) && $crumb['ptarchive'] === $post_type ) {
				unset( $crumbs[ $index ] );

				return array_values( $crumbs );
			}
		}

		return $crumbs;
	}

	/**
	 * Take an unpublished show out of an episode's trail.
	 *
	 * Both SEO plugins build a post's ancestors from `post_parent` without checking status, so a
	 * podcast reverted to draft still appears in the breadcrumbs of its published episodes, named
	 * and linked to an address that answers 404. Declining to add the crumb is not enough — it is
	 * already there, and has to be taken out.
	 *
	 * @access private
	 * @since  1.0.4
	 * @param  array $crumbs     Array of crumbs.
	 * @param  int   $episode_id ID of the episode being viewed.
	 * @return array $crumbs     Filtered array of crumbs.
	 */
	private function remove_unpublished_podcast_crumb( $crumbs, $episode_id ) {
		$podcast_id = (int) get_post_field( 'post_parent', $episode_id );

		// `get_post( 0 )` falls back to the global post, so the parent has to be checked first
		if ( $podcast_id <= 0 ) {
			return $crumbs;
		}

		$podcast = get_post( $podcast_id );

		if ( ! $podcast || 'aiopod_podcasts' !== $podcast->post_type || 'publish' === $podcast->post_status ) {
			return $crumbs;
		}

		$index = $this->find_crumb( $crumbs, $this->get_page_crumb( $podcast_id ) );

		if ( null === $index ) {
			return $crumbs;
		}

		unset( $crumbs[ $index ] );

		return array_values( $crumbs );
	}

	/**
	 * Fill in the ancestors of one of the plugin's overview pages.
	 *
	 * Yoast builds a page's ancestors from its own indexable hierarchy, which is empty until its
	 * indexation has run — and on the category, tag and participant pages the plugin takes the
	 * trail over from there, so the gap shows.
	 *
	 * @access private
	 * @since  1.0.4
	 * @param  array $crumbs  Array of crumbs.
	 * @param  int   $page_id ID of the page being viewed.
	 * @return array $crumbs  Filtered array of crumbs.
	 */
	private function add_page_ancestor_crumbs( $crumbs, $page_id ) {
		$chain = array();

		foreach ( array_reverse( get_post_ancestors( $page_id ) ) as $ancestor_id ) {
			$ancestor = get_post( $ancestor_id );

			if ( $ancestor && 'publish' === $ancestor->post_status ) {
				$chain[] = $this->get_page_crumb( $ancestor_id );
			}
		}

		return $this->insert_crumb_chain( $crumbs, $chain );
	}

	/**
	 * Insert a top-down chain of crumbs into the trail, skipping any already in it.
	 *
	 * The cursor is what keeps a partly-built trail in order: a crumb that is already present moves
	 * the insertion point to just after itself, so anything still missing below it lands in the
	 * right place rather than all of it being stacked behind the home crumb.
	 *
	 * @access private
	 * @since  1.0.4
	 * @param  array $crumbs Array of crumbs.
	 * @param  array $chain  Crumbs to insert, outermost first.
	 * @return array $crumbs Filtered array of crumbs.
	 */
	private function insert_crumb_chain( $crumbs, $chain ) {
		$position = $this->get_crumb_insert_position( $crumbs );

		foreach ( $chain as $crumb ) {
			$existing = $this->find_crumb( $crumbs, $crumb );

			if ( null !== $existing ) {
				$position = $existing + 1;

				continue;
			}

			array_splice( $crumbs, $position, 0, array( $crumb ) );

			$position++;
		}

		return $crumbs;
	}

	/**
	 * Build a Yoast breadcrumb for a post or page.
	 *
	 * @access private
	 * @since  1.0.4
	 * @param  int   $post_id ID of the post or page.
	 * @return array          Breadcrumb for it.
	 */
	private function get_page_crumb( $post_id ) {
		// Yoast's own Breadcrumbs Title field, so an inserted crumb reads the way Yoast would
		// have titled it had it built the crumb itself
		$text = get_post_meta( $post_id, '_yoast_wpseo_bctitle', true );

		if ( empty( $text ) ) {
			$text = get_the_title( $post_id );
		}

		return array(
			'url'  => get_permalink( $post_id ),
			'text' => $text,
			'id'   => $post_id
		);
	}

	/**
	 * Find a crumb already in the trail, by post ID or by URL.
	 *
	 * @access private
	 * @since  1.0.4
	 * @param  array $crumbs Array of crumbs.
	 * @param  array $needle Crumb to look for.
	 * @return int|null      Index of the crumb, or null when it is not in the trail.
	 */
	private function find_crumb( $crumbs, $needle ) {
		foreach ( $crumbs as $index => $crumb ) {
			// Yoast carries the post ID on every crumb it builds for a post or a page
			if ( ! empty( $needle['id'] ) && isset( $crumb['id'] ) && (int) $crumb['id'] === (int) $needle['id'] ) {
				return $index;
			}

			if ( ! empty( $needle['url'] ) && ! empty( $crumb['url'] ) && untrailingslashit( $crumb['url'] ) === untrailingslashit( $needle['url'] ) ) {
				return $index;
			}
		}

		return null;
	}

	/**
	 * Find where an inserted crumb belongs — after the home crumb, where there is one.
	 *
	 * @access private
	 * @since  1.0.4
	 * @param  array $crumbs Array of crumbs.
	 * @return int           Index to insert at.
	 */
	private function get_crumb_insert_position( $crumbs ) {
		if ( empty( $crumbs ) ) {
			return 0;
		}

		// The home crumb is optional, and Yoast's own setting is a surer test than the first
		// crumb's URL — an owner can point a home crumb somewhere other than the site root
		if ( class_exists( 'WPSEO_Options' ) ) {
			return ( '' !== WPSEO_Options::get( 'breadcrumbs-home' ) && ! is_front_page() ) ? 1 : 0;
		}

		if ( ! empty( $crumbs[0]['url'] ) && untrailingslashit( $crumbs[0]['url'] ) === untrailingslashit( home_url() ) ) {
			return 1;
		}

		return 0;
	}

}
