Initial commit: Atomaste website
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
namespace AIOSEO\Plugin\Common\Breadcrumbs;
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Breadcrumb Block.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*/
|
||||
class Block {
|
||||
/**
|
||||
* The primary term list.
|
||||
*
|
||||
* @since 4.3.6
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $primaryTerm = [];
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->register();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the block.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register() {
|
||||
aioseo()->blocks->registerBlock(
|
||||
'aioseo/breadcrumbs', [
|
||||
'attributes' => [
|
||||
'primaryTerm' => [
|
||||
'type' => 'string',
|
||||
'default' => null
|
||||
]
|
||||
],
|
||||
'render_callback' => [ $this, 'render' ]
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the block.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param array $blockAttributes The block attributes.
|
||||
* @return string The output from the output buffering.
|
||||
*/
|
||||
public function render( $blockAttributes ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
||||
// phpcs:disable HM.Security.ValidatedSanitizedInput.InputNotSanitized, HM.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended
|
||||
$postId = ! empty( $_GET['post_id'] ) ? (int) sanitize_text_field( wp_unslash( $_GET['post_id'] ) ) : false;
|
||||
// phpcs:enable
|
||||
|
||||
if ( ! empty( $blockAttributes['primaryTerm'] ) ) {
|
||||
$this->primaryTerm = json_decode( $blockAttributes['primaryTerm'], true );
|
||||
}
|
||||
|
||||
if ( aioseo()->blocks->isRenderingBlockInEditor() && ! empty( $postId ) ) {
|
||||
add_filter( 'aioseo_post_primary_term', [ $this, 'changePrimaryTerm' ], 10, 2 );
|
||||
add_filter( 'get_object_terms', [ $this, 'temporarilyAddTerm' ], 10, 3 );
|
||||
$breadcrumbs = aioseo()->breadcrumbs->frontend->sideDisplay( false, 'post' === get_post_type( $postId ) ? 'post' : 'single', get_post( $postId ) );
|
||||
remove_filter( 'aioseo_post_primary_term', [ $this, 'changePrimaryTerm' ], 10 );
|
||||
remove_filter( 'get_object_terms', [ $this, 'temporarilyAddTerm' ], 10 );
|
||||
|
||||
if (
|
||||
in_array( 'breadcrumbsEnable', aioseo()->internalOptions->deprecatedOptions, true ) &&
|
||||
! aioseo()->options->deprecated->breadcrumbs->enable
|
||||
) {
|
||||
return '<p>' .
|
||||
sprintf(
|
||||
// Translators: 1 - The plugin short name ("AIOSEO"), 2 - Opening HTML link tag, 3 - Closing HTML link tag.
|
||||
__( 'Breadcrumbs are currently disabled, so this block will be rendered empty. You can enable %1$s\'s breadcrumb functionality under %2$sGeneral Settings > Breadcrumbs%3$s.', 'all-in-one-seo-pack' ), // phpcs:ignore Generic.Files.LineLength.MaxExceeded
|
||||
AIOSEO_PLUGIN_SHORT_NAME,
|
||||
'<a href="' . esc_url( admin_url( 'admin.php?page=aioseo-settings#/breadcrumbs' ) ) . '" target="_blank">',
|
||||
'</a>'
|
||||
) .
|
||||
'</p>';
|
||||
}
|
||||
|
||||
return $breadcrumbs;
|
||||
}
|
||||
|
||||
return aioseo()->breadcrumbs->frontend->display( false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporarily adds the primary term to the list of terms.
|
||||
*
|
||||
* @since 4.3.6
|
||||
*
|
||||
* @param array $terms The list of terms.
|
||||
* @param array $objectIds The object IDs.
|
||||
* @param array $taxonomies The taxonomies.
|
||||
* @return array The list of terms.
|
||||
*/
|
||||
public function temporarilyAddTerm( $terms, $objectIds, $taxonomies ) {
|
||||
$taxonomy = $taxonomies[0];
|
||||
if ( empty( $this->primaryTerm ) || empty( $this->primaryTerm[ $taxonomy ] ) ) {
|
||||
return $terms;
|
||||
}
|
||||
|
||||
$term = aioseo()->helpers->getTerm( $this->primaryTerm[ $taxonomy ] );
|
||||
if ( is_a( $term, 'WP_Term' ) ) {
|
||||
$terms[] = $term;
|
||||
}
|
||||
|
||||
return $terms;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the primary term.
|
||||
*
|
||||
* @since 4.3.6
|
||||
*
|
||||
* @param \WP_Term $term The term object.
|
||||
* @param string $taxonomy The taxonomy name.
|
||||
* @return \WP_Term The term object.
|
||||
*/
|
||||
public function changePrimaryTerm( $term, $taxonomy ) {
|
||||
if ( empty( $this->primaryTerm ) || empty( $this->primaryTerm[ $taxonomy ] ) ) {
|
||||
return $term;
|
||||
}
|
||||
|
||||
return aioseo()->helpers->getTerm( $this->primaryTerm[ $taxonomy ], $taxonomy );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,744 @@
|
||||
<?php
|
||||
namespace AIOSEO\Plugin\Common\Breadcrumbs {
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Breadcrumbs.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*/
|
||||
class Breadcrumbs {
|
||||
/** Instance of the frontend class.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @var \AIOSEO\Plugin\Common\Breadcrumbs\Frontend|\AIOSEO\Plugin\Pro\Breadcrumbs\Frontend
|
||||
*/
|
||||
public $frontend;
|
||||
|
||||
/**
|
||||
* Instance of the shortcode class.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @var Shortcode
|
||||
*/
|
||||
public $shortcode;
|
||||
|
||||
/**
|
||||
* Instance of the block class.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @var Block
|
||||
*/
|
||||
public $block;
|
||||
|
||||
/**
|
||||
* Instance of the tags class.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @var Tags
|
||||
*/
|
||||
public $tags;
|
||||
|
||||
/**
|
||||
* Array of crumbs.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @var array An array of crumbs.
|
||||
*/
|
||||
public $breadcrumbs;
|
||||
|
||||
/**
|
||||
* Breadcrumbs constructor.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->frontend = new Frontend();
|
||||
$this->shortcode = new Shortcode();
|
||||
$this->block = new Block();
|
||||
|
||||
add_action( 'widgets_init', [ $this, 'registerWidget' ] );
|
||||
|
||||
// Init Tags class later as we need post types registered.
|
||||
add_action( 'init', [ $this, 'init' ], 50 );
|
||||
}
|
||||
|
||||
public function init() {
|
||||
$this->tags = new Tags();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to add crumbs on the breadcrumb array.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param array $crumbs A single crumb or an array of crumbs.
|
||||
* @return void
|
||||
*/
|
||||
public function addCrumbs( $crumbs ) {
|
||||
if ( empty( $crumbs ) || ! is_array( $crumbs ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If it's a single crumb put it inside an array to merge.
|
||||
if ( isset( $crumbs['label'] ) ) {
|
||||
$crumbs = [ $crumbs ];
|
||||
}
|
||||
|
||||
$this->breadcrumbs = array_merge( $this->breadcrumbs, $crumbs );
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a crumb array based on a type and a reference.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param string $type The type of breadcrumb ( post, single, page, category, tag, taxonomy, postTypeArchive, date,
|
||||
* author, search, notFound, blog ).
|
||||
* @param mixed $reference The reference can be an object ( WP_Post | WP_Term | WP_Post_Type | WP_User ), an array, an int or a string.
|
||||
* @param array $paged A reference for a paged crumb.
|
||||
* @return array An array of breadcrumbs with their label, link, type and reference.
|
||||
*/
|
||||
public function buildBreadcrumbs( $type, $reference, $paged = [] ) {
|
||||
// Clear the breadcrumb array and build a new one.
|
||||
$this->breadcrumbs = [];
|
||||
|
||||
// Add breadcrumb prefix.
|
||||
$this->addCrumbs( $this->getPrefixCrumb( $type, $reference ) );
|
||||
|
||||
// Set a home page in the beginning of the breadcrumb.
|
||||
$this->addCrumbs( $this->maybeGetHomePageCrumb( $type, $reference ) );
|
||||
|
||||
// Woocommerce shop page support.
|
||||
$this->addCrumbs( $this->maybeGetWooCommerceShopCrumb() );
|
||||
|
||||
// Blog home.
|
||||
if (
|
||||
aioseo()->options->breadcrumbs->showBlogHome &&
|
||||
in_array( $type, [ 'category', 'tag', 'post', 'author', 'date' ], true )
|
||||
) {
|
||||
$this->addCrumbs( $this->getBlogCrumb() );
|
||||
}
|
||||
|
||||
switch ( $type ) {
|
||||
case 'post':
|
||||
case 'single':
|
||||
$this->addCrumbs( $this->getPostArchiveCrumb( $reference ) );
|
||||
$this->addCrumbs( $this->getPostTaxonomyCrumbs( $reference ) );
|
||||
$this->addCrumbs( $this->getPostParentCrumbs( $reference ) );
|
||||
$this->addCrumbs( $this->getPostCrumb( $reference ) );
|
||||
break;
|
||||
case 'page':
|
||||
$this->addCrumbs( $this->getPostParentCrumbs( $reference, 'page' ) );
|
||||
$this->addCrumbs( $this->getPostCrumb( $reference, 'page' ) );
|
||||
break;
|
||||
case 'category':
|
||||
case 'tag':
|
||||
case 'taxonomy':
|
||||
$this->addCrumbs( $this->getTermTaxonomyParentCrumbs( $reference ) );
|
||||
$this->addCrumbs( $this->getTermTaxonomyCrumb( $reference ) );
|
||||
break;
|
||||
case 'postTypeArchive':
|
||||
$this->addCrumbs( $this->getPostTypeArchiveCrumb( $reference ) );
|
||||
break;
|
||||
case 'date':
|
||||
$this->addCrumbs( $this->getDateCrumb( $reference ) );
|
||||
break;
|
||||
case 'author':
|
||||
$this->addCrumbs( $this->getAuthorCrumb( $reference ) );
|
||||
break;
|
||||
case 'blog':
|
||||
$this->addCrumbs( $this->getBlogCrumb() );
|
||||
break;
|
||||
case 'search':
|
||||
$this->addCrumbs( $this->getSearchCrumb( $reference ) );
|
||||
break;
|
||||
case 'notFound':
|
||||
$this->addCrumbs( $this->getNotFoundCrumb() );
|
||||
break;
|
||||
case 'preview':
|
||||
$this->addCrumbs( $this->getPreviewCrumb( $reference ) );
|
||||
break;
|
||||
case 'wcProduct':
|
||||
$this->addCrumbs( $this->getPostTaxonomyCrumbs( $reference ) );
|
||||
$this->addCrumbs( $this->getPostParentCrumbs( $reference ) );
|
||||
$this->addCrumbs( $this->getPostCrumb( $reference ) );
|
||||
break;
|
||||
case 'buddypress':
|
||||
$this->addCrumbs( aioseo()->standalone->buddyPress->component->getCrumbs() );
|
||||
break;
|
||||
}
|
||||
|
||||
// Paged crumb.
|
||||
if ( ! empty( $paged['paged'] ) ) {
|
||||
$this->addCrumbs( $this->getPagedCrumb( $paged ) );
|
||||
}
|
||||
|
||||
// Maybe remove the last crumb.
|
||||
if ( ! $this->showCurrentItem( $type, $reference ) ) {
|
||||
array_pop( $this->breadcrumbs );
|
||||
}
|
||||
|
||||
// Remove empty crumbs.
|
||||
$this->breadcrumbs = array_filter( $this->breadcrumbs );
|
||||
|
||||
return $this->breadcrumbs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the prefix crumb.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param string $type The type of breadcrumb.
|
||||
* @param mixed $reference The breadcrumb reference.
|
||||
* @return array A crumb.
|
||||
*/
|
||||
public function getPrefixCrumb( $type, $reference ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
||||
if ( 0 === strlen( aioseo()->options->breadcrumbs->breadcrumbPrefix ) ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->makeCrumb( aioseo()->options->breadcrumbs->breadcrumbPrefix, '', 'prefix' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the 404 crumb.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @return array A crumb.
|
||||
*/
|
||||
public function getNotFoundCrumb() {
|
||||
return $this->makeCrumb( aioseo()->options->breadcrumbs->errorFormat404, '', 'notFound' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the search crumb.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param string $searchQuery The search query for reference.
|
||||
* @return array A crumb.
|
||||
*/
|
||||
public function getSearchCrumb( $searchQuery ) {
|
||||
return $this->makeCrumb( aioseo()->options->breadcrumbs->searchResultFormat, get_search_link( $searchQuery ), 'search', $searchQuery );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the preview crumb.
|
||||
*
|
||||
* @since 4.1.5
|
||||
*
|
||||
* @param string $label The preview label.
|
||||
* @return array A crumb.
|
||||
*/
|
||||
public function getPreviewCrumb( $label ) {
|
||||
return $this->makeCrumb( $label, '', 'preview' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the post type archive crumb.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param \WP_Post_Type $postType The post type object for reference.
|
||||
* @return array A crumb.
|
||||
*/
|
||||
public function getPostTypeArchiveCrumb( $postType ) {
|
||||
return $this->makeCrumb( aioseo()->options->breadcrumbs->archiveFormat, get_post_type_archive_link( $postType->name ), 'postTypeArchive', $postType );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a post crumb.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param \WP_Post $post A post object for reference.
|
||||
* @param string $type The breadcrumb type.
|
||||
* @param string $subType The breadcrumb subType.
|
||||
* @return array A crumb.
|
||||
*/
|
||||
public function getPostCrumb( $post, $type = 'single', $subType = '' ) {
|
||||
return $this->makeCrumb( get_the_title( $post ), get_permalink( $post ), $type, $post, $subType );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the term crumb.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param \WP_Term $term The term object for reference.
|
||||
* @param string $subType The breadcrumb subType.
|
||||
* @return array A crumb.
|
||||
*/
|
||||
public function getTermTaxonomyCrumb( $term, $subType = '' ) {
|
||||
return $this->makeCrumb( $term->name, get_term_link( $term ), 'taxonomy', $term, $subType );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the paged crumb.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param array $reference The paged array for reference.
|
||||
* @return array A crumb.
|
||||
*/
|
||||
public function getPagedCrumb( $reference ) {
|
||||
return $this->makeCrumb( sprintf( '%1$s %2$s', __( 'Page', 'all-in-one-seo-pack' ), $reference['paged'] ), $reference['link'], 'paged', $reference );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the author crumb.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param \WP_User $wpUser A WP_User object.
|
||||
* @return array A crumb.
|
||||
*/
|
||||
public function getAuthorCrumb( $wpUser ) {
|
||||
return $this->makeCrumb( $wpUser->display_name, get_author_posts_url( $wpUser->ID ), 'author', $wpUser );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the date crumb.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param array $reference An array of year, month and day values.
|
||||
* @return array A crumb.
|
||||
*/
|
||||
public function getDateCrumb( $reference ) {
|
||||
$dateCrumb = [];
|
||||
$addMonth = false;
|
||||
$addYear = false;
|
||||
if ( ! empty( $reference['day'] ) ) {
|
||||
$addMonth = true;
|
||||
$addYear = true;
|
||||
$dateCrumb[] = $this->makeCrumb(
|
||||
zeroise( (int) $reference['day'], 2 ),
|
||||
get_day_link( $reference['year'], $reference['month'], $reference['day'] ),
|
||||
'day',
|
||||
$reference['day']
|
||||
);
|
||||
}
|
||||
if ( ! empty( $reference['month'] ) || $addMonth ) {
|
||||
$addYear = true;
|
||||
$dateCrumb[] = $this->makeCrumb(
|
||||
zeroise( (int) $reference['month'], 2 ),
|
||||
get_month_link( $reference['year'], $reference['month'] ),
|
||||
'month',
|
||||
$reference['month']
|
||||
);
|
||||
|
||||
}
|
||||
if ( ! empty( $reference['year'] ) || $addYear ) {
|
||||
$dateCrumb[] = $this->makeCrumb(
|
||||
$reference['year'],
|
||||
get_year_link( $reference['year'] ),
|
||||
'year',
|
||||
$reference['year']
|
||||
);
|
||||
}
|
||||
|
||||
return array_reverse( $dateCrumb );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of crumbs parents for the term.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param \WP_Term $term A WP_Term object.
|
||||
* @return array An array of parent crumbs.
|
||||
*/
|
||||
public function getTermTaxonomyParentCrumbs( $term ) {
|
||||
$crumbs = [];
|
||||
|
||||
$termHierarchy = $this->getTermHierarchy( $term->term_id, $term->taxonomy );
|
||||
if ( ! empty( $termHierarchy ) ) {
|
||||
foreach ( $termHierarchy as $parentTermId ) {
|
||||
$parentTerm = aioseo()->helpers->getTerm( $parentTermId, $term->taxonomy );
|
||||
$crumbs[] = $this->getTermTaxonomyCrumb( $parentTerm, 'parent' );
|
||||
}
|
||||
}
|
||||
|
||||
return $crumbs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create a standard crumb array.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param string $label The crumb label.
|
||||
* @param string $link The crumb url.
|
||||
* @param null $type The crumb type.
|
||||
* @param null $reference The crumb reference.
|
||||
* @param null $subType The crumb subType ( single/parent ).
|
||||
* @return array A crumb array.
|
||||
*/
|
||||
public function makeCrumb( $label, $link = '', $type = null, $reference = null, $subType = null ) {
|
||||
return [
|
||||
'label' => $label,
|
||||
'link' => $link,
|
||||
'type' => $type,
|
||||
'subType' => $subType,
|
||||
'reference' => $reference
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a post archive crumb if it's post type has archives.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param int|\WP_Post $post An ID or a WP_Post object.
|
||||
* @return array A crumb.
|
||||
*/
|
||||
public function getPostArchiveCrumb( $post ) {
|
||||
$postType = get_post_type_object( get_post_type( $post ) );
|
||||
if ( ! $postType || ! $postType->has_archive ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $this->makeCrumb( $postType->labels->name, get_post_type_archive_link( $postType->name ), 'postTypeArchive', $postType );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a post's taxonomy crumbs.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param int|\WP_Post $post An ID or a WP_Post object.
|
||||
* @param null $taxonomy A taxonomy to use. If none is provided the first one with terms selected will be used.
|
||||
* @return array An array of term crumbs.
|
||||
*/
|
||||
public function getPostTaxonomyCrumbs( $post, $taxonomy = null ) {
|
||||
$crumbs = [];
|
||||
|
||||
if ( $taxonomy && ! is_array( $taxonomy ) ) {
|
||||
$taxonomy = [ $taxonomy ];
|
||||
}
|
||||
|
||||
$termHierarchy = $this->getPostTaxTermHierarchy( $post, $taxonomy );
|
||||
if ( ! empty( $termHierarchy['terms'] ) ) {
|
||||
foreach ( $termHierarchy['terms'] as $termId ) {
|
||||
$term = aioseo()->helpers->getTerm( $termId, $termHierarchy['taxonomy'] );
|
||||
$crumbs[] = $this->makeCrumb( $term->name, get_term_link( $term, $termHierarchy['taxonomy'] ), 'taxonomy', $term, 'parent' );
|
||||
}
|
||||
}
|
||||
|
||||
return $crumbs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the post's parent crumbs.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param int|\WP_Post $post An ID or a WP_Post object.
|
||||
* @param string $type The crumb type.
|
||||
* @return array An array of the post parent crumbs.
|
||||
*/
|
||||
public function getPostParentCrumbs( $post, $type = 'single' ) {
|
||||
$crumbs = [];
|
||||
if ( ! is_post_type_hierarchical( get_post_type( $post ) ) ) {
|
||||
return $crumbs;
|
||||
}
|
||||
|
||||
$postHierarchy = $this->getPostHierarchy( $post );
|
||||
if ( ! empty( $postHierarchy ) ) {
|
||||
foreach ( $postHierarchy as $parentID ) {
|
||||
// Do not include the Home Page.
|
||||
if ( aioseo()->helpers->getHomePageId() === $parentID ) {
|
||||
continue;
|
||||
}
|
||||
$crumbs[] = $this->getPostCrumb( get_post( $parentID ), $type, 'parent' );
|
||||
}
|
||||
}
|
||||
|
||||
return $crumbs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to extend on pro for extra functionality.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param string $type The type of breadcrumb.
|
||||
* @param mixed $reference The breadcrumb reference.
|
||||
* @return bool Show current item.
|
||||
*/
|
||||
public function showCurrentItem( $type = null, $reference = null ) {
|
||||
return apply_filters( 'aioseo_breadcrumbs_show_current_item', aioseo()->options->breadcrumbs->showCurrentItem, $type, $reference );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a home page crumb.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param string $type The type of breadcrumb.
|
||||
* @param mixed $reference The breadcrumb reference.
|
||||
* @return array|void The home crumb.
|
||||
*/
|
||||
public function maybeGetHomePageCrumb( $type = null, $reference = null ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
||||
if ( aioseo()->options->breadcrumbs->homepageLink ) {
|
||||
return $this->getHomePageCrumb();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a home page crumb.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @return array The home crumb.
|
||||
*/
|
||||
public function getHomePageCrumb() {
|
||||
$homePageId = aioseo()->helpers->getHomePageId();
|
||||
|
||||
$label = '';
|
||||
if ( $homePageId ) {
|
||||
$label = get_the_title( $homePageId );
|
||||
}
|
||||
|
||||
if ( 0 < strlen( aioseo()->options->breadcrumbs->homepageLabel ) ) {
|
||||
$label = aioseo()->options->breadcrumbs->homepageLabel;
|
||||
}
|
||||
|
||||
// Label fallback.
|
||||
if ( empty( $label ) ) {
|
||||
$label = __( 'Home', 'all-in-one-seo-pack' );
|
||||
}
|
||||
|
||||
return $this->makeCrumb( $label, get_home_url(), 'homePage', aioseo()->helpers->getHomePage() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the blog crumb.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @return array The blog crumb.
|
||||
*/
|
||||
public function getBlogCrumb() {
|
||||
$crumb = [];
|
||||
|
||||
$blogPage = aioseo()->helpers->getBlogPage();
|
||||
if ( null !== $blogPage ) {
|
||||
$crumb = $this->makeCrumb( $blogPage->post_title, get_permalink( $blogPage ), 'blog', $blogPage );
|
||||
}
|
||||
|
||||
return $crumb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe add the shop crumb to products and product categories.
|
||||
*
|
||||
* @since 4.5.5
|
||||
*
|
||||
* @return array The shop crumb.
|
||||
*/
|
||||
public function maybeGetWooCommerceShopCrumb() {
|
||||
$crumb = [];
|
||||
if (
|
||||
aioseo()->helpers->isWooCommerceShopPage() ||
|
||||
aioseo()->helpers->isWooCommerceProductPage() ||
|
||||
aioseo()->helpers->isWooCommerceTaxonomyPage()
|
||||
) {
|
||||
$crumb = $this->getWooCommerceShopCrumb();
|
||||
}
|
||||
|
||||
return $crumb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the shop crumb.
|
||||
* @see WC_Breadcrumb::prepend_shop_page()
|
||||
*
|
||||
* @since 4.5.5
|
||||
*
|
||||
* @return array The shop crumb.
|
||||
*/
|
||||
public function getWooCommerceShopCrumb() {
|
||||
$crumb = [];
|
||||
|
||||
if (
|
||||
! function_exists( 'wc_get_page_id' ) ||
|
||||
apply_filters( 'aioseo_woocommerce_breadcrumb_hide_shop', false )
|
||||
) {
|
||||
return $crumb;
|
||||
}
|
||||
|
||||
$shopPageId = wc_get_page_id( 'shop' );
|
||||
$shopPage = get_post( $shopPageId );
|
||||
|
||||
// WC checks if the permalink contains the shop page in the URI, but we prefer to
|
||||
// always show the shop page as the first crumb if it exists and it's not the home page.
|
||||
if (
|
||||
$shopPageId &&
|
||||
$shopPage &&
|
||||
aioseo()->helpers->getHomePageId() !== $shopPageId
|
||||
) {
|
||||
$crumb = $this->makeCrumb( get_the_title( $shopPage ), get_permalink( $shopPage ), 'wcShop' );
|
||||
}
|
||||
|
||||
return $crumb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a post's term hierarchy for a list of taxonomies selecting the one that has a lengthier hierarchy.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param int|\WP_Post $post An ID or a WP_Post object.
|
||||
* @param array $taxonomies An array of taxonomy names.
|
||||
* @param false $skipUnselectedTerms Allow unselected terms to be filtered out from the crumbs.
|
||||
* @return array An array of the taxonomy name + a term hierarchy.
|
||||
*/
|
||||
public function getPostTaxTermHierarchy( $post, $taxonomies = [], $skipUnselectedTerms = false ) {
|
||||
// Get all taxonomies attached to the post.
|
||||
if ( empty( $taxonomies ) ) {
|
||||
$taxonomies = get_object_taxonomies( get_post_type( $post ), 'objects' );
|
||||
$taxonomies = wp_filter_object_list( $taxonomies, [ 'public' => true ], 'and', 'name' );
|
||||
}
|
||||
|
||||
foreach ( $taxonomies as $taxonomy ) {
|
||||
$primaryTerm = aioseo()->standalone->primaryTerm->getPrimaryTerm( $post->ID, $taxonomy );
|
||||
$terms = wp_get_object_terms( $post->ID, $taxonomy, [
|
||||
'orderby' => 'term_id',
|
||||
'order' => 'ASC',
|
||||
] );
|
||||
// Use the first taxonomy with terms.
|
||||
if ( empty( $terms ) || is_wp_error( $terms ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determines the lengthier term hierarchy.
|
||||
$termHierarchy = [];
|
||||
foreach ( $terms as $term ) {
|
||||
// Gets our filtered ancestors.
|
||||
$ancestors = $this->getFilteredTermHierarchy( $term->term_id, $term->taxonomy, $skipUnselectedTerms ? $terms : [] );
|
||||
|
||||
// Merge the current term to be used in the breadcrumbs.
|
||||
$ancestors = array_merge( $ancestors, [ $term->term_id ] );
|
||||
|
||||
// If the current term is the primary term, use it.
|
||||
if ( is_a( $primaryTerm, 'WP_Term' ) && $primaryTerm->term_id === $term->term_id ) {
|
||||
$termHierarchy = $ancestors;
|
||||
break;
|
||||
}
|
||||
|
||||
$termHierarchy = ( count( $termHierarchy ) < count( $ancestors ) ) ? $ancestors : $termHierarchy;
|
||||
}
|
||||
|
||||
// Return a top to bottom hierarchy.
|
||||
return [
|
||||
'taxonomy' => $taxonomy,
|
||||
'terms' => $termHierarchy
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters a term's parent hierarchy against other terms.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param int $termId A term id.
|
||||
* @param string $taxonomy The taxonomy name.
|
||||
* @param array $termsToFilterAgainst Terms to filter out of the hierarchy.
|
||||
* @return array The term's parent hierarchy.
|
||||
*/
|
||||
public function getFilteredTermHierarchy( $termId, $taxonomy, $termsToFilterAgainst = [] ) {
|
||||
$ancestors = $this->getTermHierarchy( $termId, $taxonomy );
|
||||
|
||||
// Keep only selected terms in the hierarchy.
|
||||
if ( ! empty( $termsToFilterAgainst ) ) {
|
||||
// If it's a WP_Term array make it a term_id array.
|
||||
if ( is_a( current( $termsToFilterAgainst ), 'WP_Term' ) ) {
|
||||
$termsToFilterAgainst = wp_list_pluck( $termsToFilterAgainst, 'term_id' );
|
||||
}
|
||||
|
||||
$ancestors = array_intersect( $ancestors, $termsToFilterAgainst );
|
||||
}
|
||||
|
||||
return $ancestors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a term's parent hierarchy.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param int $termId A term id.
|
||||
* @param string $taxonomy A taxonomy name.
|
||||
* @return array The term parent hierarchy.
|
||||
*/
|
||||
public function getTermHierarchy( $termId, $taxonomy ) {
|
||||
// Return a top to bottom hierarchy.
|
||||
return array_reverse( get_ancestors( $termId, $taxonomy, 'taxonomy' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a post's parent hierarchy.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param int|\WP_Post $post An ID or a WP_Post object.
|
||||
* @return array The post parent hierarchy.
|
||||
*/
|
||||
public function getPostHierarchy( $post ) {
|
||||
$postId = ! empty( $post->ID ) ? $post->ID : $post;
|
||||
|
||||
// Return a top to bottom hierarchy.
|
||||
return array_reverse( get_ancestors( $postId, '', 'post_type' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register our breadcrumb widget.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function registerWidget() {
|
||||
if ( aioseo()->helpers->canRegisterLegacyWidget( 'aioseo-breadcrumb-widget' ) ) {
|
||||
register_widget( 'AIOSEO\Plugin\Common\Breadcrumbs\Widget' );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'aioseo_breadcrumbs' ) ) {
|
||||
/**
|
||||
* Global function for breadcrumbs output.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param boolean $echo Echo or return the output.
|
||||
* @return string|void The output.
|
||||
*/
|
||||
function aioseo_breadcrumbs( $echo = true ) {
|
||||
return aioseo()->breadcrumbs->frontend->display( $echo );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,344 @@
|
||||
<?php
|
||||
namespace AIOSEO\Plugin\Common\Breadcrumbs;
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
use AIOSEO\Plugin\Common\Integrations\BuddyPress as BuddyPressIntegration;
|
||||
|
||||
/**
|
||||
* Class Frontend.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*/
|
||||
class Frontend {
|
||||
/**
|
||||
* A local 'cached' crumb array.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $breadcrumbs = [];
|
||||
|
||||
/**
|
||||
* Gets the current page's breadcrumbs.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getBreadcrumbs() {
|
||||
if ( ! empty( $this->breadcrumbs ) ) {
|
||||
return apply_filters( 'aioseo_breadcrumbs_trail', $this->breadcrumbs );
|
||||
}
|
||||
|
||||
$reference = get_queried_object();
|
||||
$type = '';
|
||||
if ( BuddyPressIntegration::isComponentPage() ) {
|
||||
$type = 'buddypress';
|
||||
}
|
||||
|
||||
if ( ! $type ) {
|
||||
// These types need the queried object for reference.
|
||||
if ( is_object( $reference ) ) {
|
||||
if ( is_single() ) {
|
||||
$type = 'single';
|
||||
}
|
||||
|
||||
if ( is_singular( 'post' ) ) {
|
||||
$type = 'post';
|
||||
}
|
||||
|
||||
if ( is_page() && ! is_front_page() ) {
|
||||
$type = 'page';
|
||||
}
|
||||
|
||||
if ( is_category() || is_tag() ) {
|
||||
$type = 'category';
|
||||
}
|
||||
|
||||
if ( is_tax() ) {
|
||||
$type = 'taxonomy';
|
||||
}
|
||||
|
||||
if ( is_post_type_archive() ) {
|
||||
$type = 'postTypeArchive';
|
||||
}
|
||||
|
||||
if ( is_author() ) {
|
||||
$type = 'author';
|
||||
}
|
||||
|
||||
if ( is_home() ) {
|
||||
$type = 'blog';
|
||||
}
|
||||
|
||||
// Support WC shop page.
|
||||
if ( aioseo()->helpers->isWooCommerceShopPage() ) {
|
||||
$type = 'wcShop';
|
||||
}
|
||||
|
||||
// Support WC products.
|
||||
if ( aioseo()->helpers->isWooCommerceProductPage() ) {
|
||||
$type = 'wcProduct';
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_date() ) {
|
||||
$type = 'date';
|
||||
$reference = [
|
||||
'year' => get_query_var( 'year' ),
|
||||
'month' => get_query_var( 'monthnum' ),
|
||||
'day' => get_query_var( 'day' )
|
||||
];
|
||||
}
|
||||
|
||||
if ( is_search() ) {
|
||||
$type = 'search';
|
||||
$reference = htmlspecialchars( sanitize_text_field( get_search_query() ) );
|
||||
}
|
||||
|
||||
if ( is_404() ) {
|
||||
$type = 'notFound';
|
||||
}
|
||||
}
|
||||
|
||||
$paged = false;
|
||||
if ( is_paged() || ( is_singular() && 1 < get_query_var( 'page' ) ) ) {
|
||||
global $wp;
|
||||
$paged = [
|
||||
'paged' => get_query_var( 'paged' ) ? get_query_var( 'paged' ) : get_query_var( 'page' ),
|
||||
'link' => home_url( $wp->request )
|
||||
];
|
||||
}
|
||||
|
||||
return apply_filters( 'aioseo_breadcrumbs_trail', aioseo()->breadcrumbs->buildBreadcrumbs( $type, $reference, $paged ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to display breadcrumbs for a specific page.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param bool $echo Print out the breadcrumb.
|
||||
* @param string $type The type for the breadcrumb.
|
||||
* @param string $reference A reference to be used for rendering the breadcrumb.
|
||||
* @return string|void A html breadcrumb.
|
||||
*/
|
||||
public function sideDisplay( $echo = true, $type = '', $reference = '' ) {
|
||||
// Save previously built breadcrumbs.
|
||||
$previousCrumbs = $this->breadcrumbs;
|
||||
|
||||
// Build and run the sideDisplay.
|
||||
$this->breadcrumbs = aioseo()->breadcrumbs->buildBreadcrumbs( $type, $reference );
|
||||
$sideDisplay = $this->display( $echo );
|
||||
|
||||
// Restore previously built breadcrumbs.
|
||||
$this->breadcrumbs = $previousCrumbs;
|
||||
|
||||
return $sideDisplay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a generic breadcrumb preview.
|
||||
*
|
||||
* @since 4.1.5
|
||||
*
|
||||
* @param bool $echo Print out the breadcrumb.
|
||||
* @param string $label The preview crumb label.
|
||||
* @return string|void A html breadcrumb.
|
||||
*/
|
||||
public function preview( $echo = true, $label = '' ) {
|
||||
// Translators: "Crumb" refers to a part of the breadcrumb trail.
|
||||
$label = empty( $label ) ? __( 'Sample Crumb', 'all-in-one-seo-pack' ) : $label;
|
||||
|
||||
return $this->sideDisplay( $echo, 'preview', $label );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the breadcrumb in the frontend.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param bool $echo Print out the breadcrumb.
|
||||
* @return string|void A html breadcrumb.
|
||||
*/
|
||||
public function display( $echo = true ) {
|
||||
if (
|
||||
in_array( 'breadcrumbsEnable', aioseo()->internalOptions->deprecatedOptions, true ) &&
|
||||
! aioseo()->options->deprecated->breadcrumbs->enable
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! apply_filters( 'aioseo_breadcrumbs_output', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We can only run after this action because we need all post types loaded.
|
||||
if ( ! did_action( 'init' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$breadcrumbs = $this->getBreadcrumbs();
|
||||
if ( empty( $breadcrumbs ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$breadcrumbsCount = count( $breadcrumbs );
|
||||
|
||||
$display = '<div class="aioseo-breadcrumbs">';
|
||||
foreach ( $breadcrumbs as $breadcrumb ) {
|
||||
--$breadcrumbsCount;
|
||||
|
||||
$breadcrumbDisplay = $this->breadcrumbToDisplay( $breadcrumb );
|
||||
|
||||
// Strip link from Last crumb.
|
||||
if (
|
||||
0 === $breadcrumbsCount &&
|
||||
aioseo()->breadcrumbs->showCurrentItem() &&
|
||||
! $this->linkCurrentItem() &&
|
||||
'default' === $breadcrumbDisplay['templateType']
|
||||
) {
|
||||
$breadcrumbDisplay['template'] = $this->stripLink( $breadcrumbDisplay['template'] );
|
||||
}
|
||||
|
||||
$display .= $breadcrumbDisplay['template'];
|
||||
|
||||
if ( 0 < $breadcrumbsCount ) {
|
||||
$display .= $this->getSeparator();
|
||||
}
|
||||
}
|
||||
$display .= '</div>';
|
||||
|
||||
// Final security cleaning.
|
||||
$display = wp_kses_post( $display );
|
||||
|
||||
if ( $echo ) {
|
||||
echo $display; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
return $display;
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns a crumb array into a rendered html crumb.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param array $item The crumb array.
|
||||
* @return string|void The crumb html.
|
||||
*/
|
||||
protected function breadcrumbToDisplay( $item ) {
|
||||
$templateItem = $this->getCrumbTemplate( $item );
|
||||
if ( empty( $templateItem['template'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do tags.
|
||||
$templateItem['template'] = aioseo()->breadcrumbs->tags->replaceTags( $templateItem['template'], $item );
|
||||
$templateItem['template'] = preg_replace_callback(
|
||||
'/>(?![^<]*>)(?![^>]*")([^<]*?)>/',
|
||||
function ( $matches ) {
|
||||
return '>' . $matches[1] . '>';
|
||||
},
|
||||
htmlentities( $templateItem['template'] )
|
||||
);
|
||||
|
||||
// Restore html.
|
||||
$templateItem['template'] = aioseo()->helpers->decodeHtmlEntities( $templateItem['template'] );
|
||||
|
||||
// Remove html link if it comes back from the template but we passed no links to it.
|
||||
if ( empty( $item['link'] ) ) {
|
||||
$templateItem['template'] = $this->stripLink( $templateItem['template'] );
|
||||
}
|
||||
|
||||
// Allow shortcodes to run in the final html.
|
||||
$templateItem['template'] = do_shortcode( $templateItem['template'] );
|
||||
|
||||
return $templateItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get a crumb's template.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param array $crumb The crumb array.
|
||||
* @return string The html template.
|
||||
*/
|
||||
protected function getTemplate( $crumb ) {
|
||||
return $this->getDefaultTemplate( $crumb );
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get a crumb's template.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param array $crumb The crumb array.
|
||||
* @return array The template type and html.
|
||||
*/
|
||||
protected function getCrumbTemplate( $crumb ) {
|
||||
return [
|
||||
'templateType' => 'default',
|
||||
'template' => $this->getTemplate( $crumb )
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Default html template.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param string $type The crumb's type.
|
||||
* @param mixed $reference The crumb's reference.
|
||||
* @return string The default crumb template.
|
||||
*/
|
||||
public function getDefaultTemplate( $type = '', $reference = '' ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
||||
return <<<TEMPLATE
|
||||
<span class="aioseo-breadcrumb">
|
||||
<a href="#breadcrumb_link" title="#breadcrumb_label">#breadcrumb_label</a>
|
||||
</span>
|
||||
TEMPLATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to strip a html link from the crumb.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param string $html The crumb's html.
|
||||
* @return string A crumb html without links.
|
||||
*/
|
||||
public function stripLink( $html ) {
|
||||
return preg_replace( '/<a\s.*?>|<\/a>/is', '', (string) $html );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the breadcrumb configured separator.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @return string The separator html.
|
||||
*/
|
||||
public function getSeparator() {
|
||||
$separator = apply_filters( 'aioseo_breadcrumbs_separator_symbol', aioseo()->options->breadcrumbs->separator );
|
||||
|
||||
return apply_filters( 'aioseo_breadcrumbs_separator', '<span class="aioseo-breadcrumb-separator">' . esc_html( $separator ) . '</span>' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to filter the linkCurrentItem option.
|
||||
*
|
||||
* @since 4.1.3
|
||||
*
|
||||
* @return bool Link current item.
|
||||
*/
|
||||
public function linkCurrentItem() {
|
||||
return apply_filters( 'aioseo_breadcrumbs_link_current_item', aioseo()->options->breadcrumbs->linkCurrentItem );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
namespace AIOSEO\Plugin\Common\Breadcrumbs;
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Shortcode.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*/
|
||||
class Shortcode {
|
||||
/**
|
||||
* Shortcode constructor.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*/
|
||||
public function __construct() {
|
||||
add_shortcode( 'aioseo_breadcrumbs', [ $this, 'display' ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcode callback.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @return string|void The breadcrumb html.
|
||||
*/
|
||||
public function display() {
|
||||
return aioseo()->breadcrumbs->frontend->display( false );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,308 @@
|
||||
<?php
|
||||
namespace AIOSEO\Plugin\Common\Breadcrumbs;
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to replace tag values with their data counterparts.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*/
|
||||
class Tags {
|
||||
/**
|
||||
* Tags constructor.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*/
|
||||
public function __construct() {
|
||||
aioseo()->tags->addContext( $this->getContexts() );
|
||||
aioseo()->tags->addTags( $this->getTags() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace the tags in the string provided.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param string $string The string with tags.
|
||||
* @param array $item The breadcrumb item.
|
||||
* @param boolean $stripPunctuation Whether we should strip punctuation after the tags have been converted.
|
||||
* @return string The string with tags replaced.
|
||||
*/
|
||||
public function replaceTags( $string, $item, $stripPunctuation = false ) {
|
||||
if ( ! $string || ! preg_match( '/#/', (string) $string ) ) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
// Replace separator tag so we don't strip it as punctuation.
|
||||
$separatorTag = aioseo()->tags->denotationChar . 'separator_sa';
|
||||
$string = preg_replace( "/$separatorTag(?![a-zA-Z0-9_])/im", '>thisisjustarandomplaceholder<', (string) $string );
|
||||
|
||||
// Replace custom breadcrumb tags.
|
||||
foreach ( $this->getTags() as $tag ) {
|
||||
$tagId = aioseo()->tags->denotationChar . $tag['id'];
|
||||
$pattern = "/$tagId(?![a-zA-Z0-9_])/im";
|
||||
if ( preg_match( $pattern, (string) $string ) ) {
|
||||
$tagValue = str_replace( '$', '\$', $this->getTagValue( $tag, $item ) );
|
||||
$string = preg_replace( $pattern, $tagValue, (string) $string );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $stripPunctuation ) {
|
||||
$string = aioseo()->helpers->stripPunctuation( $string );
|
||||
}
|
||||
|
||||
// Remove any remaining tags from the title attribute.
|
||||
$string = preg_replace_callback( '/title="([^"]*)"/i', function ( $matches ) {
|
||||
$sanitizedTitle = wp_strip_all_tags( html_entity_decode( $matches[1] ) );
|
||||
|
||||
return 'title="' . esc_attr( $sanitizedTitle ) . '"';
|
||||
}, html_entity_decode( $string ) );
|
||||
|
||||
return preg_replace(
|
||||
'/>thisisjustarandomplaceholder<(?![a-zA-Z0-9_])/im',
|
||||
aioseo()->helpers->decodeHtmlEntities( aioseo()->options->searchAppearance->global->separator ),
|
||||
(string) $string
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of the tag to replace.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param string $tag The tag to look for.
|
||||
* @param int $item The crumb array.
|
||||
* @return string The value of the tag.
|
||||
*/
|
||||
public function getTagValue( $tag, $item ) {
|
||||
$product = false;
|
||||
if ( 0 === stripos( $tag['id'], 'breadcrumb_wc_product_' ) ) {
|
||||
$product = wc_get_product( $item['reference'] );
|
||||
if ( ! $product ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch ( $tag['id'] ) {
|
||||
case 'breadcrumb_link':
|
||||
return $item['link'];
|
||||
case 'breadcrumb_separator':
|
||||
return aioseo()->breadcrumbs->frontend->getSeparator();
|
||||
case 'breadcrumb_wc_product_price':
|
||||
return $product ? wc_price( $product->get_price() ) : '';
|
||||
case 'breadcrumb_wc_product_sku':
|
||||
return $product ? $product->get_sku() : '';
|
||||
case 'breadcrumb_wc_product_brand':
|
||||
return $product ? aioseo()->helpers->getWooCommerceBrand( $product->get_id() ) : '';
|
||||
case 'breadcrumb_author_first_name':
|
||||
return $item['reference']->first_name;
|
||||
case 'breadcrumb_author_last_name':
|
||||
return $item['reference']->last_name;
|
||||
case 'breadcrumb_archive_post_type_name':
|
||||
return $item['reference']->label;
|
||||
case 'breadcrumb_search_string':
|
||||
return $item['reference'];
|
||||
case 'breadcrumb_format_page_number':
|
||||
return $item['reference']['paged'];
|
||||
default:
|
||||
return $item['label'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets our breadcrumb custom tags.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @return array An array of tags.
|
||||
*/
|
||||
public function getTags() {
|
||||
$tags = [
|
||||
[
|
||||
'id' => 'breadcrumb_link',
|
||||
'name' => __( 'Permalink', 'all-in-one-seo-pack' ),
|
||||
'description' => __( 'The permalink.', 'all-in-one-seo-pack' )
|
||||
],
|
||||
[
|
||||
'id' => 'breadcrumb_label',
|
||||
'name' => __( 'Label', 'all-in-one-seo-pack' ),
|
||||
'description' => __( 'The label.', 'all-in-one-seo-pack' )
|
||||
],
|
||||
[
|
||||
'id' => 'breadcrumb_post_title',
|
||||
// Translators: 1 - The type of page (Post, Page, Category, Tag, etc.).
|
||||
'name' => sprintf( __( '%1$s Title', 'all-in-one-seo-pack' ), 'Post' ),
|
||||
'description' => __( 'The original title of the current post.', 'all-in-one-seo-pack' )
|
||||
],
|
||||
[
|
||||
'id' => 'breadcrumb_taxonomy_title',
|
||||
// Translators: 1 - The type of page (Post, Page, Category, Tag, etc.).
|
||||
'name' => sprintf( __( '%1$s Title', 'all-in-one-seo-pack' ), 'Category' ),
|
||||
// Translators: 1 - The name of a taxonomy.
|
||||
'description' => sprintf( __( 'The %1$s title.', 'all-in-one-seo-pack' ), 'Category' )
|
||||
],
|
||||
[
|
||||
'id' => 'breadcrumb_separator',
|
||||
'name' => __( 'Separator', 'all-in-one-seo-pack' ),
|
||||
'description' => __( 'The crumb separator.', 'all-in-one-seo-pack' )
|
||||
],
|
||||
[
|
||||
'id' => 'breadcrumb_blog_page_title',
|
||||
'name' => __( 'Blog Page Title', 'all-in-one-seo-pack' ),
|
||||
'description' => __( 'The blog page title.', 'all-in-one-seo-pack' )
|
||||
],
|
||||
[
|
||||
'id' => 'breadcrumb_author_display_name',
|
||||
'name' => __( 'Author Display Name', 'all-in-one-seo-pack' ),
|
||||
'description' => __( 'The author\'s display name.', 'all-in-one-seo-pack' )
|
||||
],
|
||||
[
|
||||
'id' => 'breadcrumb_author_first_name',
|
||||
'name' => __( 'Author First Name', 'all-in-one-seo-pack' ),
|
||||
'description' => __( 'The author\'s first name.', 'all-in-one-seo-pack' )
|
||||
],
|
||||
[
|
||||
'id' => 'breadcrumb_author_last_name',
|
||||
'name' => __( 'Author Last Name', 'all-in-one-seo-pack' ),
|
||||
'description' => __( 'The author\'s last name.', 'all-in-one-seo-pack' )
|
||||
],
|
||||
[
|
||||
'id' => 'breadcrumb_search_result_format',
|
||||
'name' => __( 'Search result format', 'all-in-one-seo-pack' ),
|
||||
'description' => __( 'The search result format.', 'all-in-one-seo-pack' )
|
||||
],
|
||||
[
|
||||
'id' => 'breadcrumb_404_error_format',
|
||||
'name' => __( '404 Error Format', 'all-in-one-seo-pack' ),
|
||||
'description' => __( 'The 404 error format.', 'all-in-one-seo-pack' )
|
||||
],
|
||||
[
|
||||
'id' => 'breadcrumb_date_archive_year',
|
||||
'name' => __( 'Year', 'all-in-one-seo-pack' ),
|
||||
'description' => __( 'The year.', 'all-in-one-seo-pack' )
|
||||
],
|
||||
[
|
||||
'id' => 'breadcrumb_date_archive_month',
|
||||
'name' => __( 'Month', 'all-in-one-seo-pack' ),
|
||||
'description' => __( 'The month.', 'all-in-one-seo-pack' )
|
||||
],
|
||||
[
|
||||
'id' => 'breadcrumb_date_archive_day',
|
||||
'name' => __( 'Day', 'all-in-one-seo-pack' ),
|
||||
'description' => __( 'The day.', 'all-in-one-seo-pack' )
|
||||
],
|
||||
[
|
||||
'id' => 'breadcrumb_search_string',
|
||||
'name' => __( 'Search String', 'all-in-one-seo-pack' ),
|
||||
'description' => __( 'The search string.', 'all-in-one-seo-pack' )
|
||||
],
|
||||
[
|
||||
'id' => 'breadcrumb_format_page_number',
|
||||
'name' => __( 'Page Number', 'all-in-one-seo-pack' ),
|
||||
'description' => __( 'The page number.', 'all-in-one-seo-pack' )
|
||||
],
|
||||
[
|
||||
'id' => 'breadcrumb_archive_post_type_format',
|
||||
'name' => __( 'Archive format', 'all-in-one-seo-pack' ),
|
||||
'description' => __( 'The archive format.', 'all-in-one-seo-pack' )
|
||||
],
|
||||
[
|
||||
'id' => 'breadcrumb_archive_post_type_name',
|
||||
'name' => __( 'Post Type Name', 'all-in-one-seo-pack' ),
|
||||
'description' => __( 'The archive post type name.', 'all-in-one-seo-pack' )
|
||||
]
|
||||
];
|
||||
|
||||
$postTypes = aioseo()->helpers->getPublicPostTypes();
|
||||
foreach ( $postTypes as $postType ) {
|
||||
if ( 'product' === $postType['name'] && aioseo()->helpers->isWoocommerceActive() ) {
|
||||
$tags[] = [
|
||||
'id' => 'breadcrumb_wc_product_price',
|
||||
// Translators: 1 - The name of a post type.
|
||||
'name' => sprintf( __( '%1$s Price', 'all-in-one-seo-pack' ), $postType['singular'] ),
|
||||
// Translators: 1 - The name of a post type.
|
||||
'description' => sprintf( __( 'The %1$s price.', 'all-in-one-seo-pack' ), $postType['singular'] )
|
||||
];
|
||||
$tags[] = [
|
||||
'id' => 'breadcrumb_wc_product_sku',
|
||||
// Translators: 1 - The name of a post type.
|
||||
'name' => sprintf( __( '%1$s SKU', 'all-in-one-seo-pack' ), $postType['singular'] ),
|
||||
// Translators: 1 - The name of a post type.
|
||||
'description' => sprintf( __( 'The %1$s SKU.', 'all-in-one-seo-pack' ), $postType['singular'] )
|
||||
];
|
||||
$tags[] = [
|
||||
'id' => 'breadcrumb_wc_product_brand',
|
||||
// Translators: 1 - The name of a post type.
|
||||
'name' => sprintf( __( '%1$s Brand', 'all-in-one-seo-pack' ), $postType['singular'] ),
|
||||
// Translators: 1 - The name of a post type.
|
||||
'description' => sprintf( __( 'The %1$s brand.', 'all-in-one-seo-pack' ), $postType['singular'] )
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets our breadcrumb contexts.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @return array An array of contexts.
|
||||
*/
|
||||
public function getContexts() {
|
||||
$contexts = [];
|
||||
|
||||
$baseTags = [ 'breadcrumb_link', 'breadcrumb_separator' ];
|
||||
|
||||
$postTypes = aioseo()->helpers->getPublicPostTypes();
|
||||
foreach ( $postTypes as $postType ) {
|
||||
$contexts[ 'breadcrumbs-post-type-' . $postType['name'] ] = array_merge( $baseTags, [ 'breadcrumb_post_title' ] );
|
||||
|
||||
if ( 'product' === $postType['name'] && aioseo()->helpers->isWoocommerceActive() ) {
|
||||
$contexts[ 'breadcrumbs-post-type-' . $postType['name'] ] = array_merge( $contexts[ 'breadcrumbs-post-type-' . $postType['name'] ], [
|
||||
'breadcrumb_wc_product_price',
|
||||
'breadcrumb_wc_product_sku',
|
||||
'breadcrumb_wc_product_brand'
|
||||
] );
|
||||
}
|
||||
}
|
||||
|
||||
$taxonomies = aioseo()->helpers->getPublicTaxonomies();
|
||||
foreach ( $taxonomies as $taxonomy ) {
|
||||
$contexts[ 'breadcrumbs-taxonomy-' . $taxonomy['name'] ] = array_merge( $baseTags, [ 'breadcrumb_taxonomy_title' ] );
|
||||
}
|
||||
|
||||
$archives = aioseo()->helpers->getPublicPostTypes( false, true, true );
|
||||
foreach ( $archives as $archive ) {
|
||||
$contexts[ 'breadcrumbs-post-type-archive-' . $archive['name'] ] = array_merge( $baseTags, [
|
||||
'breadcrumb_archive_post_type_format',
|
||||
'breadcrumb_archive_post_type_name'
|
||||
] );
|
||||
}
|
||||
|
||||
$contexts['breadcrumbs-blog-archive'] = array_merge( $baseTags, [ 'breadcrumb_blog_page_title' ] );
|
||||
|
||||
$contexts['breadcrumbs-author'] = array_merge( $baseTags, [
|
||||
'breadcrumb_author_display_name',
|
||||
'breadcrumb_author_first_name',
|
||||
'breadcrumb_author_last_name'
|
||||
] );
|
||||
|
||||
$contexts['breadcrumbs-search'] = array_merge( $baseTags, [ 'breadcrumb_search_result_format', 'breadcrumb_search_string' ] );
|
||||
$contexts['breadcrumbs-notFound'] = array_merge( $baseTags, [ 'breadcrumb_404_error_format' ] );
|
||||
$contexts['breadcrumbs-date-archive-year'] = array_merge( $baseTags, [ 'breadcrumb_date_archive_year' ] );
|
||||
$contexts['breadcrumbs-date-archive-month'] = array_merge( $baseTags, [ 'breadcrumb_date_archive_month' ] );
|
||||
$contexts['breadcrumbs-date-archive-day'] = array_merge( $baseTags, [ 'breadcrumb_date_archive_day' ] );
|
||||
|
||||
$contexts['breadcrumbs-format-archive'] = [ 'breadcrumb_archive_post_type_name' ];
|
||||
$contexts['breadcrumbs-format-search'] = [ 'breadcrumb_search_string' ];
|
||||
$contexts['breadcrumbs-format-paged'] = [ 'breadcrumb_format_page_number' ];
|
||||
|
||||
return $contexts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
namespace AIOSEO\Plugin\Common\Breadcrumbs;
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Widget.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*/
|
||||
class Widget extends \WP_Widget {
|
||||
/**
|
||||
* The default attributes.
|
||||
*
|
||||
* @since 4.2.7
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $defaults = [];
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*/
|
||||
public function __construct() {
|
||||
// Widget defaults.
|
||||
$this->defaults = [
|
||||
'title' => ''
|
||||
];
|
||||
|
||||
// Widget Slug.
|
||||
$widgetSlug = 'aioseo-breadcrumb-widget';
|
||||
|
||||
// Widget basics.
|
||||
$widgetOps = [
|
||||
'classname' => $widgetSlug,
|
||||
'description' => esc_html__( 'Display the current page breadcrumb.', 'all-in-one-seo-pack' ),
|
||||
];
|
||||
|
||||
// Widget controls.
|
||||
$controlOps = [
|
||||
'id_base' => $widgetSlug,
|
||||
];
|
||||
|
||||
// Translators: 1 - The plugin short name ("AIOSEO").
|
||||
$name = sprintf( esc_html__( '%1$s - Breadcrumbs', 'all-in-one-seo-pack' ), AIOSEO_PLUGIN_SHORT_NAME );
|
||||
$name .= ' ' . esc_html__( '(legacy)', 'all-in-one-seo-pack' );
|
||||
parent::__construct( $widgetSlug, $name, $widgetOps, $controlOps );
|
||||
}
|
||||
|
||||
/**
|
||||
* Widget callback.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param array $args Widget args.
|
||||
* @param array $instance The widget instance options.
|
||||
* @return void
|
||||
*/
|
||||
public function widget( $args, $instance ) {
|
||||
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
// Merge with defaults.
|
||||
$instance = wp_parse_args( (array) $instance, $this->defaults );
|
||||
|
||||
echo $args['before_widget'];
|
||||
|
||||
// Title.
|
||||
if ( ! empty( $instance['title'] ) ) {
|
||||
echo $args['before_title'];
|
||||
echo apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
|
||||
echo $args['after_title'];
|
||||
}
|
||||
|
||||
// If not being previewed in the Customizer maybe show the dummy preview.
|
||||
if (
|
||||
! is_customize_preview() &&
|
||||
(
|
||||
false !== strpos( wp_get_referer(), admin_url( 'widgets.php' ) ) ||
|
||||
false !== strpos( wp_get_referer(), admin_url( 'customize.php' ) )
|
||||
)
|
||||
) {
|
||||
aioseo()->breadcrumbs->frontend->preview();
|
||||
} else {
|
||||
aioseo()->breadcrumbs->frontend->display();
|
||||
}
|
||||
|
||||
echo $args['after_widget'];
|
||||
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
/**
|
||||
* Widget option update.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param array $newInstance New instance options.
|
||||
* @param array $oldInstance Old instance options.
|
||||
* @return array Processed new instance options.
|
||||
*/
|
||||
public function update( $newInstance, $oldInstance ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
||||
$newInstance['title'] = wp_strip_all_tags( $newInstance['title'] );
|
||||
|
||||
return $newInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Widget options form.
|
||||
*
|
||||
* @since 4.1.1
|
||||
*
|
||||
* @param array $instance The widget instance options.
|
||||
* @return void
|
||||
*/
|
||||
public function form( $instance ) {
|
||||
// Merge with defaults.
|
||||
$instance = wp_parse_args( (array) $instance, $this->defaults );
|
||||
?>
|
||||
<p>
|
||||
<label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>">
|
||||
<?php echo esc_html( __( 'Title:', 'all-in-one-seo-pack' ) ); ?>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"
|
||||
name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>"
|
||||
value="<?php echo esc_attr( $instance['title'] ); ?>"
|
||||
class="widefat"
|
||||
/>
|
||||
</p>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user