<?php
/**
 * Breadcrumbs element.
 *
 * @package BricksExtras
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Breadcrumbs element class.
 */
class X_Breadcrumbs extends \Bricks\Element {

	/**
	 * Element category.
	 *
	 * @var string
	 */
	public $category = 'extras';

	/**
	 * Element name.
	 *
	 * @var string
	 */
	public $name = 'xbreadcrumbs';

	/**
	 * Element icon.
	 *
	 * @var string
	 */
	public $icon = 'ti-angle-double-right';

	/**
	 * CSS selector.
	 *
	 * @var string
	 */
	public $css_selector = '';


	/**
	 * Get element label.
	 *
	 * @return string
	 */
	public function get_label() {
		return esc_html__( 'Site Breadcrumbs', 'bricksextras' );
	}

	/**
	 * Get element keywords.
	 *
	 * @return array
	 */
	public function get_keywords() {
		return array( 'breadcrumbs' );
	}

	/**
	 * Set control groups.
	 *
	 * @return void
	 */
	public function set_control_groups() {

		$not_bricksextras = array(
			'rankmath',
			'navxt',
			'allinone',
			'seopress',
			'yoast',
			'slim',
		);

		$this->control_groups['config'] = array(
			'title'    => esc_html__( 'Configure output', 'bricksextras' ),
			'tab'      => 'content',
			'required' => array( 'source', '!=', $not_bricksextras ),
		);

		$this->control_groups['configSlim'] = array(
			'title'    => esc_html__( 'Configure output', 'bricksextras' ),
			'tab'      => 'content',
			'required' => array( 'source', '=', 'slim' ),
		);

		$this->control_groups['separator'] = array(
			'title'    => esc_html__( 'Separator', 'bricks' ),
			'tab'      => 'content',
			'required' => array( 'source', '!=', $not_bricksextras ),
		);

		$this->control_groups['breadcrumbPrefix'] = array(
			'title' => esc_html__( 'Prefix', 'bricks' ),
			'tab'   => 'content',
		);

		$this->control_groups['linkStyles'] = array(
			'title' => esc_html__( 'Links', 'bricks' ),
			'tab'   => 'content',
		);

		$this->control_groups['currentItem'] = array(
			'title'    => esc_html__( 'Current page', 'bricks' ),
			'tab'      => 'content',
			'required' => array( 'source', '!=', 'allinone' ),
		);
	}

	/**
	 * Set element controls.
	 *
	 * @return void
	 */
	public function set_controls() {

		$breadcrumb_source = array(
			'extras'   => 'BricksExtras',
			'rankmath' => 'Rank Math',
			'navxt'    => 'NavXT',
			'allinone' => 'All in One SEO',
			'seopress' => 'SEOPress Pro',
			'yoast'    => 'Yoast',
			'slim'     => 'Slim SEO',
		);

		$not_bricksextras = array(
			'rankmath',
			'navxt',
			'allinone',
			'seopress',
			'yoast',
			'slim',
		);

		$this->controls['source'] = array(
			'tab'         => 'content',
			'label'       => esc_html__( 'Breadcrumbs source', 'bricksextras' ),
			'type'        => 'select',
			'options'     => $breadcrumb_source,
			'clearable'   => false,
			'inline'      => true,
			'placeholder' => 'BricksExtras',
		);

		$this->controls['overallTypography'] = array(
			'tab'   => 'content',
			'type'  => 'typography',
			'label' => esc_html__( 'Typography', 'bricks' ),
			'css'   => array(
				array(
					'property' => 'font',
					'selector' => '',
				),
			),
		);

		$this->controls['displayMode'] = array(
			'tab'         => 'content',
			'label'       => esc_html__( 'Display mode', 'bricks' ),
			'type'        => 'select',
			'inline'      => true,
			'options'     => array(
				'flex'   => esc_html__( 'Flex', 'bricks' ),
				'inline' => esc_html__( 'Inline', 'bricks' ),
			),
			'placeholder' => esc_html__( 'Flex', 'bricks' ),
			'info'        => esc_html__( 'Inline mode allows breadcrumbs to wrap like regular text', 'bricksextras' ),
			'required'    => array( 'source', '=', array( 'extras', '' ) ),
		);

		$this->controls['listGap'] = array(
			'tab'            => 'content',
			'label'          => esc_html__( 'Gap', 'bricks' ) . ' (' . esc_html__( 'List', 'bricks' ) . ')',
			'inline'         => true,
			'type'           => 'number',
			'units'          => true,
			'placeholder'    => '5px',
			'hasDynamicData' => false,
			'css'            => array(
				array(
					'property' => '--x-breadcrumbs-gap',
					'selector' => '',
				),
			),
		);

		$this->controls['maybeLink'] = array(
			'tab'         => 'content',
			'label'       => esc_html__( 'Breadcrumb links', 'bricksextras' ),
			'type'        => 'select',
			'inline'      => true,
			'options'     => array(
				'enable'  => esc_html__( 'Enable', 'bricks' ),
				'disable' => esc_html__( 'Disable', 'bricks' ),
			),
			'placeholder' => esc_html__( 'Enable', 'bricks' ),
			'required'    =>
			array(
				'source',
				'=',
				array(
					'navxt',
				),
			),
		);

		$this->controls['maybeReverse'] = array(
			'tab'         => 'content',
			'label'       => esc_html__( 'Reverse order', 'bricksextras' ),
			'type'        => 'select',
			'inline'      => true,
			'options'     => array(
				'enable'  => esc_html__( 'Enable', 'bricks' ),
				'disable' => esc_html__( 'Disable', 'bricks' ),
			),
			'placeholder' => esc_html__( 'Disable', 'bricks' ),
			'required'    =>
			array(
				'source',
				'=',
				array(
					'navxt',
				),
			),
		);

		$this->controls['maybeForce'] = array(
			'tab'         => 'content',
			'label'       => esc_html__( 'Bypass internal caching', 'bricksextras' ),
			'type'        => 'select',
			'inline'      => true,
			'options'     => array(
				'enable'  => esc_html__( 'Enable', 'bricks' ),
				'disable' => esc_html__( 'Disable', 'bricks' ),
			),
			'placeholder' => esc_html__( 'Disable', 'bricks' ),
			'required'    =>
			array(
				'source',
				'=',
				array(
					'navxt',
				),
			),
		);

		$this->controls['breadcrumbPrefix'] = array(
			'tab'    => 'content',
			'label'  => esc_html__( 'Prefix', 'bricks' ),
			'inline' => true,
			'type'   => 'text',
			'group'  => 'breadcrumbPrefix',
		);

			$this->controls['removePrefix'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Remove prefix on front page', 'bricksextras' ),
				'type'        => 'checkbox',
				'inline'      => true,
				'placeholder' => esc_html__( 'False', 'bricks' ),
				'group'       => 'breadcrumbPrefix',
			);

			$this->controls['prefixTypography'] = array(
				'tab'   => 'content',
				'group' => 'breadcrumbPrefix',
				'type'  => 'typography',
				'label' => esc_html__( 'Typography', 'bricks' ),
				'css'   => array(
					array(
						'property' => 'font',
						'selector' => '.x-breadcrumbs_prefix',
					),
				),
			);

			$this->controls['prefixGap'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Gap', 'bricks' ),
				'inline'      => true,
				'type'        => 'number',
				'units'       => true,
				'placeholder' => '10px',
				'css'         => array(
					array(
						'property' => 'gap',
						'selector' => '',
					),
				),
				'group'       => 'breadcrumbPrefix',
			);

			$this->controls['prefixBackgroundColor'] = array(
				'tab'   => 'content',
				'group' => 'breadcrumbPrefix',
				'type'  => 'color',
				'label' => esc_html__( 'Background', 'bricks' ),
				'css'   => array(
					array(
						'property' => 'background-color',
						'selector' => '.x-breadcrumbs_prefix',
					),
				),
			);

			$this->controls['prefixBorder'] = array(
				'tab'   => 'content',
				'group' => 'breadcrumbPrefix',
				'type'  => 'border',
				'label' => esc_html__( 'Border', 'bricks' ),
				'css'   => array(
					array(
						'property' => 'border',
						'selector' => '.x-breadcrumbs_prefix',
					),
				),
			);

			$this->controls['prefixBoxShadow'] = array(
				'tab'   => 'content',
				'group' => 'breadcrumbPrefix',
				'label' => esc_html__( 'Box Shadow', 'bricks' ),
				'type'  => 'box-shadow',
				'css'   => array(
					array(
						'property' => 'box-shadow',
						'selector' => '.x-breadcrumbs_prefix',
					),
				),
			);

			$this->controls['homeSep'] = array(
				'type'  => 'separator',
				'label' => esc_html__( 'Home', 'bricks' ),
				'group' => 'config',
			);

			$this->controls['maybeHome'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Include home page link', 'bricksextras' ),
				'type'        => 'select',
				'inline'      => true,
				'options'     => array(
					'enable'  => esc_html__( 'Enable', 'bricks' ),
					'disable' => esc_html__( 'Disable', 'bricks' ),
				),
				'placeholder' => esc_html__( 'Enable', 'bricks' ),
				'group'       => 'config',
			);

			$this->controls['homeLabel'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Text', 'bricks' ),
				'inline'      => true,
				'type'        => 'text',
				'placeholder' => 'Home',
				'group'       => 'config',
				'required'    => array(
					array( 'maybeHome', '!=', 'disable' ),
				),
			);

			$this->controls['homeURL'] = array(
				'tab'         => 'content',
				'label'       => 'URL',
				'inline'      => true,
				'type'        => 'text',
				'placeholder' => '{site_url}',
				'group'       => 'config',
				'required'    => array(
					array( 'maybeHome', '!=', 'disable' ),
				),
			);

			$this->controls['homeLinkType'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Link type', 'bricks' ),
				'type'        => 'select',
				'inline'      => true,
				'options'     => array(
					'text' => esc_html__( 'Text', 'bricks' ),
					'icon' => esc_html__( 'Icon', 'bricks' ),
				),
				'placeholder' => esc_html__( 'Text', 'bricks' ),
				'group'       => 'config',
				'small'       => true,
				'required'    => array( 'maybeHome', '!=', 'disable' ),
			);

			$home_icon_selector = '.x-breadcrumbs_list-item .screen-reader-text + *';

			$this->controls['homeIcon'] = array(
				'tab'      => 'content',
				'group'    => 'config',
				'label'    => esc_html__( 'Icon', 'bricks' ),
				'type'     => 'icon',
				'css'      => array(
					array(
						'selector' => $home_icon_selector,
					),
				),
				'default'  => array(
					'library' => 'themify',
					'icon'    => 'ti-home',
				),
				'required' => array(
					array( 'maybeHome', '!=', 'disable' ),
					array( 'homeLinkType', '=', 'icon' ),
				),
			);

			$this->controls['homeIconTypography'] = array(
				'tab'      => 'content',
				'type'     => 'typography',
				'label'    => esc_html__( 'Icon typography', 'bricks' ),
				'css'      => array(
					array(
						'property' => 'font',
						'selector' => '.x-breadcrumbs_list-item .screen-reader-text + *',
					),
				),
				'group'    => 'config',
				'required' => array(
					array( 'maybeHome', '!=', 'disable' ),
					array( 'homeLinkType', '=', 'icon' ),
				),
			);

			$this->controls['homeIconBackgroundColor'] = array(
				'tab'      => 'content',
				'group'    => 'config',
				'type'     => 'color',
				'label'    => esc_html__( 'Background', 'bricks' ),
				'css'      => array(
					array(
						'property' => 'background-color',
						'selector' => $home_icon_selector,
					),
				),
				'required' => array(
					array( 'maybeHome', '!=', 'disable' ),
					array( 'homeLinkType', '=', 'icon' ),
				),
			);

			$this->controls['homeIconBorder'] = array(
				'tab'      => 'content',
				'group'    => 'config',
				'type'     => 'border',
				'label'    => esc_html__( 'Border', 'bricks' ),
				'css'      => array(
					array(
						'property' => 'border',
						'selector' => $home_icon_selector,
					),
				),
				'required' => array(
					array( 'maybeHome', '!=', 'disable' ),
					array( 'homeLinkType', '=', 'icon' ),
				),
			);

			$this->controls['homeIconBoxShadow'] = array(
				'tab'      => 'content',
				'group'    => 'config',
				'label'    => esc_html__( 'Box Shadow', 'bricks' ),
				'type'     => 'box-shadow',
				'css'      => array(
					array(
						'property' => 'box-shadow',
						'selector' => $home_icon_selector,
					),
				),
				'required' => array(
					array( 'maybeHome', '!=', 'disable' ),
					array( 'homeLinkType', '=', 'icon' ),
				),
			);

			$this->controls['homeIconPadding'] = array(
				'tab'      => 'content',
				'group'    => 'config',
				'label'    => esc_html__( 'Icon padding', 'bricks' ),
				'type'     => 'spacing',
				'css'      => array(
					array(
						'property' => 'padding',
						'selector' => $home_icon_selector,
					),
				),
				'required' => array(
					array( 'maybeHome', '!=', 'disable' ),
					array( 'homeLinkType', '=', 'icon' ),
				),
			);

			$this->controls['searchSep'] = array(
				'tab'   => 'content',
				'type'  => 'separator',
				'group' => 'config',
				'label' => esc_html__( 'Search', 'bricks' ),
			);

			$this->controls['searchPrefix'] = array(
				'tab'     => 'content',
				'label'   => esc_html__( 'Prefix', 'bricks' ),
				'inline'  => true,
				'type'    => 'text',
				'default' => 'Search results for',
				'group'   => 'config',
			);

			$this->controls['tagPrefix'] = array(
				'tab'     => 'content',
				'label'   => esc_html__( 'Prefix', 'bricks' ) . ' (' . esc_html__( 'Tag', 'bricks' ) . ')',
				'inline'  => true,
				'type'    => 'text',
				'default' => 'Posts tagged',
				'group'   => 'config',
			);

			$this->controls['authorPrefix'] = array(
				'tab'     => 'content',
				'label'   => esc_html__( 'Prefix', 'bricks' ) . ' (' . esc_html__( 'Author', 'bricks' ) . ')',
				'inline'  => true,
				'type'    => 'text',
				'default' => 'Archives for',
				'group'   => 'config',
			);

			$this->controls['error404Prefix'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( '404 Error Page', 'bricks' ),
				'inline'      => true,
				'type'        => 'text',
				'placeholder' => '404 Error: Page not found',
				'group'       => 'config',
			);

			$this->controls['ariaLabel'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'aria-label', 'bricksextras' ),
				'inline'      => true,
				'type'        => 'text',
				'placeholder' => 'breadcrumbs',
				'group'       => 'config',
			);

			$this->controls['errorSep'] = array(
				'tab'   => 'content',
				'type'  => 'separator',
				'group' => 'config',
			);

			$this->controls['removeTitle'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Remove current post/page title', 'bricksextras' ),
				'type'        => 'select',
				'inline'      => true,
				'options'     => array(
					'enable'  => esc_html__( 'Enable', 'bricks' ),
					'disable' => esc_html__( 'Disable', 'bricks' ),
				),
				'placeholder' => esc_html__( 'Disable', 'bricks' ),
				'group'       => 'config',
			);

			$this->controls['truncateMaxLength'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Truncate title (Max characters)', 'bricksextras' ),
				'inline'      => true,
				'type'        => 'number',
				'placeholder' => '100',
				'info'        => esc_html__( 'Set the max number of characters to display in post/page titles. After will show ...', 'bricksextras' ),
				'group'       => 'config',
				'required'    => array( 'removeTitle', '!=', 'enable' ),
			);

			$this->controls['maybeBlog'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Include posts page link', 'bricksextras' ),
				'type'        => 'select',
				'inline'      => true,
				'options'     => array(
					'enable'  => esc_html__( 'Enable', 'bricks' ),
					'disable' => esc_html__( 'Disable', 'bricks' ),
				),
				'placeholder' => esc_html__( 'Disable', 'bricks' ),
				'group'       => 'config',
			);

			$this->controls['taxNesting'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Nest taxonomies', 'bricksextras' ),
				'type'        => 'select',
				'inline'      => true,
				'options'     => array(
					'enable'  => esc_html__( 'Enable', 'bricks' ),
					'disable' => esc_html__( 'Disable', 'bricks' ),
				),
				'placeholder' => esc_html__( 'Enable', 'bricks' ),
				'group'       => 'config',
			);

			$this->controls['maybeLinks'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Links', 'bricks' ),
				'type'        => 'select',
				'inline'      => true,
				'options'     => array(
					'enable'  => esc_html__( 'Enable', 'bricks' ),
					'disable' => esc_html__( 'Disable', 'bricks' ),
				),
				'placeholder' => esc_html__( 'Enable', 'bricks' ),
				'group'       => 'config',
				'required'    => array( 'source', '!=', $not_bricksextras ),
			);

			$this->controls['maybeSchema'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Schema markup', 'bricksextras' ),
				'type'        => 'select',
				'inline'      => true,
				'options'     => array(
					'enable'  => esc_html__( 'Enable', 'bricks' ),
					'disable' => esc_html__( 'Disable', 'bricks' ),
				),
				'placeholder' => esc_html__( 'Enable', 'bricks' ),
				'group'       => 'config',
				'required'    => array( 'source', '!=', $not_bricksextras ),
			);

			$all_categories = $this->getCategories();

			$this->controls['categorySp'] = array(
				'tab'   => 'content',
				'type'  => 'separator',
				'group' => 'config',
			);

			$this->controls['maybePostCategory'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Include Category', 'bricksextras' ),
				'type'        => 'select',
				'inline'      => true,
				'options'     => array(
					'enable'  => esc_html__( 'Enable', 'bricks' ),
					'disable' => esc_html__( 'Disable', 'bricks' ),
				),
				'placeholder' => esc_html__( 'Enable', 'bricks' ),
				'group'       => 'config',
				'required'    => array( 'source', '!=', $not_bricksextras ),
			);

			$this->controls['priorityCategory'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Priority Category', 'bricksextras' ),
				'type'        => 'select',
				'inline'      => true,
				'options'     => $all_categories,
				'placeholder' => esc_html__( 'Select option', 'bricks' ),
				'group'       => 'config',
				'required'    => array( 'source', '!=', $not_bricksextras ),
			);

			$this->controls['excludeCategories'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Exclude Categories', 'bricksextras' ),
				'type'        => 'select',
				'multiple'    => true,
				'inline'      => true,
				'options'     => $all_categories,
				'placeholder' => esc_html__( 'Select option', 'bricks' ),
				'group'       => 'config',
				'required'    => array( 'source', '!=', $not_bricksextras ),
			);

			if ( class_exists( 'WooCommerce' ) ) {

				$all_product_categories = $this->getProductCategories();

				$this->controls['wooSep'] = array(
					'tab'   => 'content',
					'type'  => 'separator',
					'group' => 'config',
				);

				$this->controls['maybeProductCategory'] = array(
					'tab'         => 'content',
					'label'       => esc_html__( 'Include Product Category', 'bricksextras' ),
					'type'        => 'select',
					'inline'      => true,
					'options'     => array(
						'enable'  => esc_html__( 'Enable', 'bricks' ),
						'disable' => esc_html__( 'Disable', 'bricks' ),
					),
					'placeholder' => esc_html__( 'Disable', 'bricks' ),
					'group'       => 'config',
					'required'    => array( 'source', '!=', $not_bricksextras ),
				);

				$this->controls['excludeProductCategories'] = array(
					'tab'         => 'content',
					'label'       => esc_html__( 'Exclude Product Categories', 'bricksextras' ),
					'type'        => 'select',
					'multiple'    => true,
					'inline'      => true,
					'options'     => $all_product_categories,
					'placeholder' => esc_html__( 'Select option', 'bricks' ),
					'group'       => 'config',
					'required'    => array( 'source', '!=', $not_bricksextras ),
				);

				$this->controls['maybeShop'] = array(
					'tab'         => 'content',
					'label'       => esc_html__( 'Include Shop Page', 'bricksextras' ),
					'type'        => 'select',
					'inline'      => true,
					'options'     => array(
						'enable'  => esc_html__( 'Enable', 'bricks' ),
						'disable' => esc_html__( 'Disable', 'bricks' ),
					),
					'placeholder' => esc_html__( 'Enable', 'bricks' ),
					'group'       => 'config',
					'required'    => array( 'source', '!=', $not_bricksextras ),
				);

			}

			$this->controls['cptSep'] = array(
				'tab'   => 'content',
				'type'  => 'separator',
				'label' => esc_html__( 'Custom post types', 'bricksextras' ),
				'group' => 'config',
			);

			$this->controls['maybeCPTarchive'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Include CPT archive link for taxonomies', 'bricksextras' ),
				'type'        => 'select',
				'inline'      => true,
				'options'     => array(
					'enable'  => esc_html__( 'Enable', 'bricks' ),
					'disable' => esc_html__( 'Disable', 'bricks' ),
				),
				'placeholder' => esc_html__( 'Disable', 'bricks' ),
				'group'       => 'config',
				'required'    => array( 'source', '!=', $not_bricksextras ),
			);

			$taxonomies = \Bricks\Setup::$control_options['taxonomies'];
			unset( $taxonomies['wp_template_part_area'] );
			unset( $taxonomies['wp_pattern_category'] );

			$this->controls['cpt'] = array(
				'tab'           => 'content',
				'type'          => 'repeater',
				'group'         => 'config',
				'label'         => esc_html__( 'Choose which taxonomy to display for each custom post type', 'bricksextras' ),
				'titleProperty' => 'postType',
				'fields'        => array(
					'postType' => array(
						'type'        => 'select',
						'options'     => \BricksExtras\Helpers::get_public_post_types(),
						'label'       => esc_html__( 'Post type', 'bricks' ),
						'placeholder' => esc_html__( 'Select custom post type', 'bricksextras' ),
						'inline'      => true,
					),
					'taxonomy' => array(
						'type'    => 'select',
						'options' => $taxonomies,
						'label'   => esc_html__( 'Taxonomy', 'bricks' ),
						'inline'  => true,
					),
				),
				'required'      => array( 'source', '!=', $not_bricksextras ),
			);

			/* slim */

			$this->controls['slimLabelSep'] = array(
				'tab'   => 'content',
				'type'  => 'separator',
				'label' => esc_html__( 'Labels', 'bricks' ),
				'group' => 'configSlim',
			);

			$this->controls['slimhomeLabel'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Home', 'bricks' ),
				'inline'      => true,
				'type'        => 'text',
				'placeholder' => 'Home',
				'group'       => 'configSlim',
			);

			$this->controls['slimsearchLabel'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Search', 'bricks' ),
				'inline'      => true,
				'type'        => 'text',
				'placeholder' => 'Results for &#8220;%s&#8221;',
				'group'       => 'configSlim',
			);

			$this->controls['slimerrorLabel'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( '404 Error Page', 'bricks' ),
				'inline'      => true,
				'type'        => 'text',
				'placeholder' => 'Page not found',
				'group'       => 'configSlim',
			);

			$this->controls['slimdisplayCurrent'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Display current', 'bricksextras' ),
				'options'     => array(
					'true'  => esc_html__( 'Enable', 'bricks' ),
					'false' => esc_html__( 'Disable', 'bricks' ),
				),
				'inline'      => true,
				'type'        => 'select',
				'placeholder' => esc_html__( 'Enable', 'bricks' ),
				'group'       => 'configSlim',
			);

			$this->controls['slimTaxonomy'] = array(
				'tab'            => 'content',
				'label'          => esc_html__( 'Taxonomy', 'bricks' ),
				'inline'         => true,
				'type'           => 'text',
				'hasDynamicData' => false,
				'placeholder'    => 'category',
				'group'          => 'configSlim',
				'info'           => 'The taxonomy that you want to output in the breadcrumb trail when on a single post',
			);

			$this->controls['slimseparator'] = array(
				'tab'            => 'content',
				'label'          => esc_html__( 'Separator', 'bricks' ),
				'inline'         => true,
				'type'           => 'text',
				'placeholder'    => '»',
				'hasDynamicData' => false,
				'group'          => 'configSlim',
			);

			$this->controls['separatorType'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Separator type', 'bricks' ),
				'type'        => 'select',
				'inline'      => true,
				'options'     => array(
					'text' => esc_html__( 'Text', 'bricks' ),
					'icon' => esc_html__( 'Icon', 'bricks' ),
				),
				'placeholder' => esc_html__( 'Text', 'bricks' ),
				'group'       => 'separator',
			);

			$this->controls['separator'] = array(
				'tab'            => 'content',
				'label'          => esc_html__( 'Separator', 'bricks' ),
				'inline'         => true,
				'type'           => 'text',
				'default'        => '»',
				'hasDynamicData' => false,
				'css'            => array(
					array(
						'property' => '--x-breadcrumb-separator',
						'selector' => 'ol',
						'value'    => '"%s"',
					),
				),
				'group'          => 'separator',
				'required'       => array(
					array( 'separatorType', '!=', 'icon' ),
				),
			);

			$this->controls['separatorIcon'] = array(
				'tab'      => 'content',
				'group'    => 'separator',
				'label'    => esc_html__( 'Icon', 'bricks' ),
				'type'     => 'icon',
				'css'      => array(
					array(
						'selector' => '.x-breadcrumbs_separator > *',
					),
				),
				'default'  => array(
					'library' => 'ionicons',
					'icon'    => 'ion-ios-arrow-forward',
				),
				'required' => array(
					array( 'separatorType', '=', 'icon' ),
				),
			);

			$this->controls['separatorTypography'] = array(
				'tab'   => 'content',
				'type'  => 'typography',
				'label' => esc_html__( 'Typography', 'bricks' ),
				'css'   => array(
					array(
						'property' => 'font',
						'selector' => 'li:not(:first-child):before, .x-breadcrumbs_separator',
					),
				),
				'group' => 'separator',
			);

			/* link styles */

			$link_selector = 'a';

			$this->controls['linkTypography'] = array(
				'tab'   => 'content',
				'group' => 'linkStyles',
				'type'  => 'typography',
				'label' => esc_html__( 'Typography', 'bricks' ),
				'css'   => array(
					array(
						'property' => 'font',
						'selector' => $link_selector,
					),
				),
			);

			$this->controls['linkBackgroundColor'] = array(
				'tab'   => 'content',
				'group' => 'linkStyles',
				'type'  => 'color',
				'label' => esc_html__( 'Background', 'bricks' ),
				'css'   => array(
					array(
						'property' => 'background-color',
						'selector' => $link_selector,
					),
				),
			);

			$this->controls['linkBorder'] = array(
				'tab'   => 'content',
				'group' => 'linkStyles',
				'type'  => 'border',
				'label' => esc_html__( 'Border', 'bricks' ),
				'css'   => array(
					array(
						'property' => 'border',
						'selector' => $link_selector,
					),
				),
			);

			$this->controls['linkBoxShadow'] = array(
				'tab'   => 'content',
				'group' => 'linkStyles',
				'label' => esc_html__( 'Box Shadow', 'bricks' ),
				'type'  => 'box-shadow',
				'css'   => array(
					array(
						'property' => 'box-shadow',
						'selector' => $link_selector,
					),
				),
			);

			$this->controls['listPadding'] = array(
				'tab'   => 'content',
				'group' => 'linkStyles',
				'label' => esc_html__( 'Padding', 'bricks' ) . ' (' . esc_html__( 'List item', 'bricks' ) . ')',
				'type'  => 'spacing',
				'css'   => array(
					array(
						'property' => 'padding',
						'selector' => $link_selector,
					),
				),
			);

			$current_list_item = '.x-breadcrumbs_list [aria-current=page] > span, .rank-math-breadcrumb .last:last-child, .breadcrumbs .current-item, .breadcrumb_last, .breadcrumb--last, .breadcrumb-item.active';

			$this->controls['currentListTypography'] = array(
				'tab'   => 'content',
				'group' => 'currentItem',
				'type'  => 'typography',
				'label' => esc_html__( 'Typography', 'bricks' ),
				'css'   => array(
					array(
						'property' => 'font',
						'selector' => $current_list_item,
					),
				),
			);

			$this->controls['currentBackgroundColor'] = array(
				'tab'   => 'content',
				'group' => 'currentItem',
				'type'  => 'color',
				'label' => esc_html__( 'Background', 'bricks' ),
				'css'   => array(
					array(
						'property' => 'background-color',
						'selector' => $current_list_item,
					),
				),
			);

			$this->controls['currentBorder'] = array(
				'tab'   => 'content',
				'group' => 'currentItem',
				'type'  => 'border',
				'label' => esc_html__( 'Border', 'bricks' ),
				'css'   => array(
					array(
						'property' => 'border',
						'selector' => $current_list_item,
					),
				),
			);

			$this->controls['currentBoxShadow'] = array(
				'tab'   => 'content',
				'group' => 'currentItem',
				'label' => esc_html__( 'Box Shadow', 'bricks' ),
				'type'  => 'box-shadow',
				'css'   => array(
					array(
						'property' => 'box-shadow',
						'selector' => $current_list_item,
					),
				),
			);
	}


	/**
	 * Enqueue element scripts and styles.
	 *
	 * @return void
	 */
	public function enqueue_scripts() {
		if ( ! \BricksExtras\Helpers::element_css_added( $this->name ) ) {
			wp_enqueue_style( 'x-breadcrumbs', BRICKSEXTRAS_URL . 'components/assets/css/breadcrumbs.css', array(), \BricksExtras\Plugin::VERSION );
		}
	}

	/**
	 * Breadcrumb arguments.
	 *
	 * @var array
	 */
	public $args = array();

	/**
	 * Render element.
	 *
	 * @return void
	 */
	public function render() {

		$source            = isset( $this->settings['source'] ) ? esc_html( $this->settings['source'] ) : 'extras';
		$breadcrumb_prefix = isset( $this->settings['breadcrumbPrefix'] ) ? bricks_render_dynamic_data( $this->settings['breadcrumbPrefix'] ) : '';

		if ( isset( $this->settings['removePrefix'] ) && is_front_page() ) {
			$breadcrumb_prefix = false;
		}

		$output = '';

		$this->set_attribute( '_root', 'data-source', $source );

		if ( 'rankmath' === $source ) {

			$output .= "<div {$this->render_attributes( '_root' )}>";

			if ( function_exists( 'rank_math_the_breadcrumbs' ) ) {
				if ( $breadcrumb_prefix ) {
					$output .= "<span class='x-breadcrumbs_prefix'>" . esc_html( $breadcrumb_prefix ) . ' </span>';
				}
				ob_start();
				rank_math_the_breadcrumbs();
				$output .= ob_get_clean();
			} else {
				$output .= $this->render_element_placeholder(
					array(
						'title' => esc_html__( 'Not found', 'bricks' ) . ' (Rank Math) ',
					)
				);
			}

			$output .= '</div>';

		} elseif ( 'navxt' === $source ) {

			$this->set_attribute( 'navxt_list', 'class', 'breadcrumbs' );
			$this->set_attribute( 'navxt_list', 'typeof', 'BreadcrumbList' );
			$this->set_attribute( 'navxt_list', 'vocab', 'https://schema.org/' );

			$maybe_link    = isset( $this->settings['maybeLink'] ) ? 'enable' === $this->settings['maybeLink'] : true;
			$maybe_reverse = isset( $this->settings['maybeReverse'] ) ? 'enable' === $this->settings['maybeReverse'] : false;
			$maybe_force   = isset( $this->settings['maybeForce'] ) ? 'enable' === $this->settings['maybeForce'] : false;

			$output .= "<div {$this->render_attributes( '_root' )}>";

			if ( function_exists( 'bcn_display' ) ) {
				if ( $breadcrumb_prefix ) {
					$output .= "<span class='x-breadcrumbs_prefix'>" . esc_html( $breadcrumb_prefix ) . ' </span>';
				}

				$output .= "<div {$this->render_attributes( 'navxt_list' )}>";
				$return  = true;
				$output .= bcn_display( $return, $maybe_link, $maybe_reverse, $maybe_force );
				$output .= '</div>';
			} else {
				$output .= $this->render_element_placeholder(
					array(
						'title' => esc_html__( 'Not found', 'bricks' ) . ' (NavXT) ',
					)
				);
			}

			$output .= '</div>';

		} elseif ( 'slim' === $source ) {

			$output .= "<div {$this->render_attributes( '_root' )}>";

			if ( class_exists( '\SlimSEO\Breadcrumbs' ) ) {

				$slim_separater       = isset( $this->settings['slimseparator'] ) ? esc_html( $this->settings['slimseparator'] ) : '»';
				$slim_display_current = isset( $this->settings['slimdisplayCurrent'] ) ? esc_html( $this->settings['slimdisplayCurrent'] ) : 'true';
				$slim_home            = isset( $this->settings['slimhomeLabel'] ) ? esc_html( bricks_render_dynamic_data( $this->settings['slimhomeLabel'] ) ) : 'Home';
				$slim_search          = isset( $this->settings['slimsearchLabel'] ) ? esc_html( bricks_render_dynamic_data( $this->settings['slimsearchLabel'] ) ) : 'Results for &#8220;%s&#8221;';
				$slimerror_label      = isset( $this->settings['slimerrorLabel'] ) ? esc_html( bricks_render_dynamic_data( $this->settings['slimerrorLabel'] ) ) : 'Page not found';
				$slim_taxonomy        = isset( $this->settings['slimTaxonomy'] ) ? esc_html( $this->settings['slimTaxonomy'] ) : 'category';

				$slim_shortcode = '[slim_seo_breadcrumbs separator="' . $slim_separater . '" display_current="' . $slim_display_current . '" label_home="' . $slim_home . '" label_search="' . $slim_search . '" label_404="' . $slimerror_label . '" taxonomy="' . $slim_taxonomy . '"]';

				if ( $breadcrumb_prefix ) {
					$output .= "<span class='x-breadcrumbs_prefix'>" . esc_html( $breadcrumb_prefix ) . ' </span>';
				}

				if ( shortcode_exists( 'slim_seo_breadcrumbs' ) ) {
					$output .= do_shortcode( $slim_shortcode );
				}
			} else {
				$output .= $this->render_element_placeholder(
					array(
						'title' => esc_html__( 'Not found', 'bricks' ) . ' (Slim SEO) ',
					)
				);
			}

			$output .= '</div>';

		} elseif ( 'allinone' === $source ) {

			$output .= "<div {$this->render_attributes( '_root' )}>";

			if ( function_exists( 'aioseo_breadcrumbs' ) ) {
				if ( $breadcrumb_prefix ) {
					$output .= "<span class='x-breadcrumbs_prefix'>" . esc_html( $breadcrumb_prefix ) . ' </span>';
				}
				ob_start();
				aioseo_breadcrumbs();
				$output .= ob_get_clean();
			} else {
				$output .= $this->render_element_placeholder(
					array(
						'title' => esc_html__( 'Not found', 'bricks' ) . ' (All in One SEO) ',
					)
				);
			}

			$output .= '</div>';

		} elseif ( 'seopress' === $source ) {

			$output .= "<div {$this->render_attributes( '_root' )}>";

			if ( function_exists( 'seopress_display_breadcrumbs' ) ) {
				if ( $breadcrumb_prefix ) {
					$output .= "<span class='x-breadcrumbs_prefix'>" . esc_html( $breadcrumb_prefix ) . ' </span>';
				}
				ob_start();
				seopress_display_breadcrumbs();
				$output .= ob_get_clean();
			} else {
				$output .= '';
			}

			$output .= '</div>';

		} elseif ( 'yoast' === $source ) {

			$output .= "<div {$this->render_attributes( '_root' )}>";

			if ( function_exists( 'yoast_breadcrumb' ) ) {
				if ( $breadcrumb_prefix ) {
					$output .= "<span class='x-breadcrumbs_prefix'>" . esc_html( $breadcrumb_prefix ) . ' </span>';
				}
				ob_start();
				yoast_breadcrumb();
				$output .= ob_get_clean();
			} else {
				$output .= $this->render_element_placeholder(
					array(
						'title' => esc_html__( 'Not found', 'bricks' ) . ' (Yoast) ',
					)
				);
			}

			$output .= '</div>';

		} else {

			$maybe_schema     = isset( $this->settings['maybeSchema'] ) ? 'enable' === $this->settings['maybeSchema'] : true;
			$maybe_parent_tax = isset( $this->settings['taxNesting'] ) ? 'enable' === $this->settings['taxNesting'] : true;
			$maybe_home       = isset( $this->settings['maybeHome'] ) ? 'enable' === $this->settings['maybeHome'] : true;
			$maybe_blog       = isset( $this->settings['maybeBlog'] ) ? 'enable' === $this->settings['maybeBlog'] : false;

			$maybe_product_category = isset( $this->settings['maybeProductCategory'] ) ? 'enable' === $this->settings['maybeProductCategory'] : false;
			$maybe_shop             = isset( $this->settings['maybeShop'] ) ? 'enable' === $this->settings['maybeShop'] : true;

			$maybe_cpt_archive = isset( $this->settings['maybeCPTarchive'] ) ? 'enable' === $this->settings['maybeCPTarchive'] : false;

			$maybe_post_category = isset( $this->settings['maybePostCategory'] ) ? 'enable' === $this->settings['maybePostCategory'] : true;

			$maybe_links = isset( $this->settings['maybeLinks'] ) ? 'disable' !== $this->settings['maybeLinks'] : true;

			$archive_format = isset( $this->settings['archiveFormat'] ) ? esc_html( $this->settings['archiveFormat'] ) : 'Archives for';

			$home_url       = isset( $this->settings['homeURL'] ) ? esc_html( bricks_render_dynamic_data( $this->settings['homeURL'] ) ) : '{site_url}';
			$home_link_type = isset( $this->settings['homeLinkType'] ) ? $this->settings['homeLinkType'] : 'text';
			$home_icon      = empty( $this->settings['homeIcon'] ) ? false : self::render_icon( $this->settings['homeIcon'] );
			$home_label     = isset( $this->settings['homeLabel'] ) ? esc_html( bricks_render_dynamic_data( $this->settings['homeLabel'] ) ) : 'Home';

			$search_prefix   = isset( $this->settings['searchPrefix'] ) ? esc_html( bricks_render_dynamic_data( $this->settings['searchPrefix'] ) ) : '';
			$author_prefix   = isset( $this->settings['authorPrefix'] ) ? esc_html( bricks_render_dynamic_data( $this->settings['authorPrefix'] ) ) : '';
			$tag_prefix      = isset( $this->settings['tagPrefix'] ) ? esc_html( bricks_render_dynamic_data( $this->settings['tagPrefix'] ) ) : false;
			$error404_prefix = isset( $this->settings['error404Prefix'] ) ? esc_html( bricks_render_dynamic_data( $this->settings['error404Prefix'] ) ) : '404 Error: Page not found';

			$priority_category          = isset( $this->settings['priorityCategory'] ) ? esc_html( $this->settings['priorityCategory'] ) : false;
			$exclude_categories         = isset( $this->settings['excludeCategories'] ) ? array_map( 'intval', $this->settings['excludeCategories'] ) : array();
			$exclude_product_categories = isset( $this->settings['excludeProductCategories'] ) ? array_map( 'intval', $this->settings['excludeProductCategories'] ) : array();

			$max_length   = isset( $this->settings['truncateMaxLength'] ) ? $this->settings['truncateMaxLength'] : 100;
			$remove_title = isset( $this->settings['removeTitle'] ) ? 'enable' === $this->settings['removeTitle'] : false;

			$cpt = ! empty( $this->settings['cpt'] ) ? $this->settings['cpt'] : false;

			$separator_type = isset( $this->settings['separatorType'] ) ? esc_attr( $this->settings['separatorType'] ) : 'text';
			$separator_icon = empty( $this->settings['separatorIcon'] ) ? false : self::render_icon( $this->settings['separatorIcon'] );

			$display_mode = isset( $this->settings['displayMode'] ) ? esc_attr( $this->settings['displayMode'] ) : 'flex';

			$aria_label = isset( $this->settings['ariaLabel'] ) ? esc_attr( bricks_render_dynamic_data( $this->settings['ariaLabel'] ) ) : esc_attr__( 'breadcrumbs', 'bricksextras' );
			$this->set_attribute( '_root', 'aria-label', $aria_label );
			$this->set_attribute( '_root', 'data-separator-type', $separator_type );
			$this->set_attribute( '_root', 'data-display-mode', $display_mode );

			if ( $maybe_schema ) {
				$this->set_attribute( 'x-breadcrumbs_list', 'itemscope', '' );
				$this->set_attribute( 'x-breadcrumbs_list', 'itemtype', 'http://schema.org/BreadcrumbList' );
			}

			$this->set_attribute( 'x-breadcrumbs_list', 'class', 'x-breadcrumbs_list' );

			$output .= "<nav {$this->render_attributes( '_root' )}>";

			if ( $breadcrumb_prefix ) {
				$output .= "<span class='x-breadcrumbs_prefix'>" . esc_html( $breadcrumb_prefix ) . ' </span>';
			}

			$output .= "<ol {$this->render_attributes( 'x-breadcrumbs_list' )}>";

			$crumbs = array();

			if ( is_front_page() || $maybe_home ) {
				$crumbs[] = $this->get_home_crumb( $home_label, $maybe_schema, $home_url, $maybe_links, $home_link_type, $home_icon );
			}

			global $wp_query;

			if ( is_home() && ! is_front_page() ) {
				$crumbs[] = $this->get_blog_crumb( $home_label );
			} elseif ( is_search() ) {
				$crumbs[] = $maybe_schema ? $search_prefix . " <span itemprop='name'>'" . esc_html( get_search_query( false ) ) . "'</span>" : $search_prefix . " '" . esc_html( get_search_query( false ) ) . "'";
			} elseif ( is_404() ) {
				$crumbs[] = $error404_prefix;
			} elseif ( is_page() && ! is_front_page() ) {
				$crumbs[] = $this->get_page_crumb( $maybe_schema, $maybe_links, $max_length );
			} elseif ( is_archive() ) {

				if ( is_category() ) {
					$crumbs[] = $this->get_category_crumb( $maybe_parent_tax, $maybe_schema, $maybe_links );
				} elseif ( is_tag() ) {
					$crumbs[] = $tag_prefix ? single_term_title( $tag_prefix . ' "', false ) . '"' : single_term_title( '', false );
				} elseif ( is_tax() ) {
					$crumbs[] = $this->get_tax_crumb( $maybe_parent_tax, $maybe_schema, $maybe_links, $maybe_cpt_archive, $maybe_shop );
				} elseif ( is_year() ) {
					$crumbs[] = $this->get_year_crumb();
				} elseif ( is_month() ) {
					$crumbs[] = $this->get_month_crumb( $maybe_schema, $maybe_links );
				} elseif ( is_day() ) {
					$crumbs[] = $this->get_day_crumb( $maybe_schema, $maybe_links );
				} elseif ( is_author() ) {
					$crumbs[] = $author_prefix . ' ' . esc_html( $wp_query->queried_object->display_name );
				} elseif ( is_post_type_archive() ) {
					$crumbs[] = $this->get_post_type_crumb();
				}
			} elseif ( is_singular() && ! is_front_page() ) {
				$crumbs[] = $this->get_single_crumb( $maybe_parent_tax, $maybe_schema, $priority_category, $maybe_links, $maybe_blog, $maybe_product_category, $maybe_shop, $maybe_post_category, $exclude_categories, $exclude_product_categories, $max_length, $cpt );
			}

			$output .= $this->render_breadcrumbs( $crumbs, $maybe_schema, $remove_title, $separator_type, $separator_icon );

			$output .= '</ol>';

			$output .= '</nav>';

		}

		echo $output;
	}

	/**
	 * Get single post breadcrumb.
	 *
	 * @param bool   $maybe_parent_tax Whether to include parent taxonomy.
	 * @param bool   $maybe_schema Whether to include schema markup.
	 * @param string $priority_category Priority category.
	 * @param bool   $maybe_links Whether to include links.
	 * @param bool   $maybe_blog Whether to include blog.
	 * @param bool   $maybe_product_category Whether to include product category.
	 * @param bool   $maybe_shop Whether to include shop.
	 * @param bool   $maybe_post_category Whether to include post category.
	 * @param array  $exclude_categories Categories to exclude.
	 * @param array  $exclude_product_categories Product categories to exclude.
	 * @param int    $max_length Maximum length.
	 * @param string $cpt Custom post type.
	 * @return array
	 */
	public function get_single_crumb( $maybe_parent_tax, $maybe_schema, $priority_category, $maybe_links, $maybe_blog, $maybe_product_category, $maybe_shop, $maybe_post_category, $exclude_categories, $exclude_product_categories, $max_length, $cpt ) {

		if ( is_attachment() ) {
			$crumb = $this->get_attachment_crumb( $maybe_schema, $maybe_links, $max_length );
		} elseif ( is_singular( 'post' ) ) {
			$crumb   = $this->get_post_crumb( $maybe_parent_tax, $maybe_schema, $priority_category, $maybe_links, $maybe_blog, $maybe_post_category, $exclude_categories );
			$crumb[] = '<span itemprop="name">' . $this->truncate_title( single_post_title( '', false ), $max_length ) . '</span>';
		} elseif ( is_singular( 'product' ) && class_exists( 'WooCommerce' ) ) {
			$crumb   = $this->get_product_crumb( $maybe_parent_tax, $maybe_schema, $maybe_links, $maybe_product_category, $maybe_shop, $exclude_product_categories );
			$crumb[] = '<span itemprop="name">' . $this->truncate_title( single_post_title( '', false ), $max_length ) . '</span>';
		} else {
			$crumb   = $this->get_cpt_crumb( $maybe_parent_tax, $maybe_schema, $maybe_links, $cpt );
			$crumb[] = '<span itemprop="name">' . $this->truncate_title( single_post_title( '', false ), $max_length ) . '</span>';
		}

		return $crumb;
	}


	/**
	 * Get home breadcrumb.
	 *
	 * @param string $home_label Home label.
	 * @param bool   $maybe_schema Whether to include schema markup.
	 * @param string $home_url Home URL.
	 * @param bool   $maybe_links Whether to include links.
	 * @param string $home_link_type Home link type.
	 * @param string $home_icon Home icon.
	 * @return string
	 */
	public function get_home_crumb( $home_label, $maybe_schema, $home_url, $maybe_links, $home_link_type, $home_icon ) {

		if ( 'text' === $home_link_type ) {
			$crumb = ( is_front_page() ) ? '<span itemprop="name">' . $home_label . '</span>' : $this->get_breadcrumb_link( $home_url, $home_label, $maybe_schema, $maybe_links );
		} else {
			$has_icon = ! empty( $home_icon );
			$crumb    = ( is_front_page() ) ? '<span itemprop="name"><span class=screen-reader-text>' . $home_label . '</span>' . $home_icon . '</span>' : $this->get_breadcrumb_link( $home_url, '<span class=screen-reader-text>' . $home_label . '</span>' . $home_icon, $maybe_schema, $maybe_links, $has_icon );
		}

		return $crumb;
	}


	/**
	 * Get blog breadcrumb.
	 *
	 * @param string $home_label Home label.
	 * @return string
	 */
	public function get_blog_crumb( $home_label ) {

		$crumb = get_the_title( get_option( 'page_for_posts', true ) );
		return '<span itemprop="name">' . $crumb . '</span>';
	}

	/**
	 * Truncate title to maximum length.
	 *
	 * @param string $post_title Post title.
	 * @param int    $max_length Maximum length.
	 * @return string
	 */
	public function truncate_title( $post_title, $max_length ) {

		if ( ! $post_title ) {
			return '';
		}

		$end_title = strlen( $post_title ) > $max_length ? '...' : '';

		$post_title_output = mb_substr( $post_title, 0, $max_length, 'UTF-8' ) . $end_title;

		return $post_title_output;
	}


	/**
	 * Get page breadcrumb.
	 *
	 * @param bool $maybe_schema Whether to include schema markup.
	 * @param bool $maybe_links Whether to include links.
	 * @param int  $max_length Maximum length.
	 * @return array
	 */
	public function get_page_crumb( $maybe_schema, $maybe_links, $max_length ) {

		/* woocommerce endpoints */

		if ( ! function_exists( 'is_wc_endpoint_url' ) || ! is_wc_endpoint_url() ) {

			global $wp_query;

			$crumbs = array();

			$post = $wp_query->get_queried_object();

			if ( $post->post_parent ) {
				if ( false !== get_post_status( $post->post_parent ) ) {
					if ( isset( $post->ancestors ) ) {
						if ( is_array( $post->ancestors ) ) {
							$ancestors = array_values( $post->ancestors );
						} else {
							$ancestors = array( $post->ancestors );
						}
					} else {
						$ancestors = array( $post->post_parent );
					}

					foreach ( $ancestors as $ancestor ) {
						array_unshift(
							$crumbs,
							$this->get_breadcrumb_link(
								get_permalink( $ancestor ),
								get_the_title( $ancestor ),
								$maybe_schema,
								$maybe_links
							)
						);
					}
				}
			}

			$post_title = get_the_title();

			$crumbs[] = '<span itemprop=name>' . $this->truncate_title( $post_title, $max_length ) . '</span>';

			return $crumbs;

		} else {

			$crumbs = array();

			$action         = \BricksExtras\Helpers::get_get_value( 'action' );
			$endpoint       = is_wc_endpoint_url() ? WC()->query->get_current_endpoint() : '';
			$endpoint_title = $endpoint ? WC()->query->get_endpoint_title( $endpoint, $action ) : '';

			$crumbs[] = $this->get_breadcrumb_link(
				get_permalink(),
				get_the_title(),
				$maybe_schema,
				$maybe_links
			);

			$crumbs[] = '<span itemprop=name>' . $endpoint_title . '</span>';

			return $crumbs;

		}
	}



	/**
	 * Get attachment breadcrumb.
	 *
	 * @param bool $maybe_schema Whether to include schema markup.
	 * @param bool $maybe_links Whether to include links.
	 * @param int  $max_length Maximum length.
	 * @return string
	 */
	public function get_attachment_crumb( $maybe_schema, $maybe_links, $max_length ) {

		$post = get_post();

		$crumb = '';
		if ( $post->post_parent && $this->args['heirarchial_attachments'] ) {

			$attachment_parent = get_post( $post->post_parent );
			$crumb             = $this->get_breadcrumb_link(
				get_permalink( $post->post_parent ),
				$attachment_parent->post_title,
				$maybe_schema,
				$maybe_links
			);
		}
		$crumb .= $this->truncate_title( single_post_title( '', false ), $max_length );

		return $crumb;
	}


	/**
	 * Get post breadcrumb.
	 *
	 * @param bool   $maybe_parent_tax Whether to include parent taxonomy.
	 * @param bool   $maybe_schema Whether to include schema markup.
	 * @param string $priority_category Priority category.
	 * @param bool   $maybe_links Whether to include links.
	 * @param bool   $maybe_blog Whether to include blog.
	 * @param bool   $maybe_post_category Whether to include post category.
	 * @param array  $exclude_categories Categories to exclude.
	 * @return array
	 */
	public function get_post_crumb( $maybe_parent_tax, $maybe_schema, $priority_category, $maybe_links, $maybe_blog, $maybe_post_category, $exclude_categories ) {

		$categories = get_the_category();

		$cat_crumb = '';

		$crumbs = array();

		if ( $maybe_blog && get_option( 'page_for_posts', true ) ) {
			$crumbs[] = $this->get_breadcrumb_link(
				get_permalink( get_option( 'page_for_posts' ) ),
				get_the_title( get_option( 'page_for_posts', true ) ),
				$maybe_schema,
				$maybe_links
			);
		}

		if ( $maybe_post_category ) {

			if ( 1 === count( $categories ) ) {
				if ( ! in_array( $categories[0]->cat_ID, $exclude_categories, true ) ) {
					$crumbs[] = $this->get_term_parents( $categories[0]->cat_ID, 'category', true, $maybe_parent_tax, $maybe_schema, $maybe_links, $exclude_categories );
				}
			}

			if ( count( $categories ) > 1 ) {

				if ( (bool) $priority_category && in_category( $priority_category ) ) {
					$crumbs[] = $this->get_term_parents( $priority_category, 'category', true, $maybe_parent_tax, $maybe_schema, $maybe_links, $exclude_categories );
				} elseif ( ! in_array( $categories[0]->cat_ID, $exclude_categories, true ) ) {
						$crumbs[] = $this->get_term_parents( $categories[1]->cat_ID, 'category', true, $maybe_parent_tax, $maybe_schema, $maybe_links, $exclude_categories );
				} else {
					$crumbs[] = $this->get_term_parents( $categories[0]->cat_ID, 'category', true, $maybe_parent_tax, $maybe_schema, $maybe_links, $exclude_categories );
				}
			}
		}

		$crumbs = $this->nestedToSingle( $crumbs );

		return $crumbs;
	}


	/**
	 * Get custom post type breadcrumb.
	 *
	 * @param bool   $maybe_parent_tax Whether to include parent taxonomy.
	 * @param bool   $maybe_schema Whether to include schema markup.
	 * @param bool   $maybe_links Whether to include links.
	 * @param string $cpt Custom post type.
	 * @return array
	 */
	public function get_cpt_crumb( $maybe_parent_tax, $maybe_schema, $maybe_links, $cpt ) {

		$post_type        = get_query_var( 'post_type' );
		$post_type_object = get_post_type_object( $post_type );

		if ( null === $post_type_object ) {
			return array();
		}

		$crumbs = array();

		$cpt_archive_link = get_post_type_archive_link( $post_type );
		if ( $cpt_archive_link ) {
			$crumbs[] = $this->get_breadcrumb_link(
				$cpt_archive_link,
				$post_type_object->labels->name,
				$maybe_schema,
				$maybe_links
			);
		}

		/* if ancestors */

		$crumbs_ancestors = array();
		$taxonomy_term    = array();

		global $wp_query;

		$post = $wp_query->get_queried_object();

		if ( $post && isset( $post->post_parent ) && $post->post_parent ) {

			if ( false !== get_post_status( $post->post_parent ) ) {
				if ( isset( $post->ancestors ) ) {
					if ( is_array( $post->ancestors ) ) {
						$ancestors = array_values( $post->ancestors );
					} else {
						$ancestors = array( $post->ancestors );
					}
				} else {
					$ancestors = array( $post->post_parent );
				}

				foreach ( $ancestors as $ancestor ) {

					array_unshift(
						$crumbs_ancestors,
						$this->get_breadcrumb_link(
							get_permalink( $ancestor ),
							get_the_title( $ancestor ),
							$maybe_schema,
							$maybe_links
						)
					);
				}
			}

			$crumbs = array_merge( $crumbs, $crumbs_ancestors );

		} else {

			if ( (bool) $cpt && is_array( $cpt ) ) {

				foreach ( $cpt as $cpt ) {

					if ( isset( $cpt['taxonomy'] ) && taxonomy_exists( $cpt['taxonomy'] ) ) {

						$taxonomy_terms = get_the_terms( $post->id, $cpt['taxonomy'] );

						if ( $taxonomy_terms ) {

							if ( 1 === count( $taxonomy_terms ) ) {
								$taxonomy_term[] = $this->get_term_parents( $taxonomy_terms[0]->term_id, $cpt['taxonomy'], true, $maybe_parent_tax, $maybe_schema, $maybe_links );
							}

							if ( count( $taxonomy_terms ) > 1 ) {
								$taxonomy_term[] = $this->get_term_parents( $taxonomy_terms[0]->term_id, $cpt['taxonomy'], true, $maybe_parent_tax, $maybe_schema, $maybe_links );
							}
						}
					}
				}
			}

			$crumbs = array_merge( $crumbs, $taxonomy_term );

			$crumbs = $this->nestedToSingle( $crumbs );

		}

		return $crumbs;
	}


	/**
	 * Get product breadcrumb.
	 *
	 * @param bool  $maybe_parent_tax Whether to include parent taxonomy.
	 * @param bool  $maybe_schema Whether to include schema markup.
	 * @param bool  $maybe_links Whether to include links.
	 * @param bool  $maybe_product_category Whether to include product category.
	 * @param bool  $maybe_shop Whether to include shop.
	 * @param array $exclude_product_categories Product categories to exclude.
	 * @return array
	 */
	public function get_product_crumb( $maybe_parent_tax, $maybe_schema, $maybe_links, $maybe_product_category, $maybe_shop, $exclude_product_categories ) {

		$post_type        = get_query_var( 'post_type' );
		$post_type_object = get_post_type_object( $post_type );

		$crumbs = array();

		$cpt_archive_link = get_post_type_archive_link( $post_type );

		$shop_title = function_exists( 'woocommerce_page_title' ) ? woocommerce_page_title( false ) : $post_type_object->labels->name;

		if ( $maybe_shop ) {

			if ( $cpt_archive_link ) {
				$crumbs[] = $this->get_breadcrumb_link(
					$cpt_archive_link,
					$shop_title,
					$maybe_schema,
					$maybe_links
				);
			} else {
				$crumbs[] = $shop_title;
			}
		}

		/* if product category */

		global $product;

		if ( is_object( $product ) ) {
			$productid = $product->get_id();
		} else {
			$productid = get_the_ID();
		}

		if ( taxonomy_exists( 'product_cat' ) ) {

			$product_cats = get_the_terms( $productid, 'product_cat' );

			if ( $maybe_product_category ) {
				if ( ! empty( $product_cats ) && ! is_wp_error( $product_cats ) ) {
					foreach ( $product_cats as $cat ) {
						if ( ! in_array( $cat->term_id, $exclude_product_categories, true ) ) {
							$crumbs[] = $this->get_term_parents( $cat->term_id, 'product_cat', true, $maybe_parent_tax, $maybe_schema, $maybe_links, $exclude_product_categories );
							break;
						}
					}
				}
			}
		}

		$crumbs = $this->nestedToSingle( $crumbs );

		return $crumbs;
	}



	/**
	 * Get category breadcrumb.
	 *
	 * @param bool $maybe_parent_tax Whether to include parent taxonomy.
	 * @param bool $maybe_schema Whether to include schema markup.
	 * @param bool $maybe_links Whether to include links.
	 * @return array
	 */
	public function get_category_crumb( $maybe_parent_tax, $maybe_schema, $maybe_links ) {
		$crumbs[] = $this->get_term_parents( get_query_var( 'cat' ), 'category', false, $maybe_parent_tax, $maybe_schema, $maybe_links );
		$crumbs   = $this->nestedToSingle( $crumbs );
		return $crumbs;
	}

	/**
	 * Get taxonomy breadcrumb.
	 *
	 * @param bool $maybe_parent_tax Whether to include parent taxonomy.
	 * @param bool $maybe_schema Whether to include schema markup.
	 * @param bool $maybe_links Whether to include links.
	 * @param bool $maybe_cpt_archive Whether to include CPT archive.
	 * @param bool $maybe_shop Whether to include shop.
	 * @return array
	 */
	public function get_tax_crumb( $maybe_parent_tax, $maybe_schema, $maybe_links, $maybe_cpt_archive, $maybe_shop ) {

		global $wp_query;

		$crumbs = array();

		$term     = $wp_query->get_queried_object();
		$taxonomy = get_taxonomy( $term->taxonomy );

		if ( $maybe_cpt_archive ) {

			if ( ! empty( $taxonomy->object_type ) && 1 === count( $taxonomy->object_type ) ) {

				$cpt_object = get_post_type_object( $taxonomy->object_type[0] );

				if ( $cpt_object->has_archive ) {

					if ( 'product' !== $cpt_object->name || $maybe_shop ) {

						$archive_label = class_exists( 'WooCommerce' ) && 'product' === $cpt_object->name ? get_the_title( get_option( 'woocommerce_shop_page_id' ) ) : $cpt_object->label;

						$crumbs[] = $this->get_breadcrumb_link(
							get_post_type_archive_link( $taxonomy->object_type[0] ),
							$archive_label,
							$maybe_schema,
							$maybe_links
						);

					}
				}
			}
		}

		$crumbs[] = $this->get_term_parents( $term->term_id, $term->taxonomy, false, $maybe_parent_tax, $maybe_schema, $maybe_links );
		$crumbs   = $this->nestedToSingle( $crumbs );

		return $crumbs;
	}

	/**
	 * Get year breadcrumb.
	 *
	 * @return string
	 */
	public function get_year_crumb() {

		$year  = get_query_var( 'm' ) ? get_query_var( 'm' ) : get_query_var( 'year' );
		$crumb = $year;

		return $crumb;
	}

	/**
	 * Get month breadcrumb.
	 *
	 * @param bool $maybe_schema Whether to include schema markup.
	 * @param bool $maybe_links Whether to include links.
	 * @return string
	 */
	public function get_month_crumb( $maybe_schema, $maybe_links ) {

		$year = get_query_var( 'm' ) ? mb_substr( get_query_var( 'm' ), 0, 4 ) : get_query_var( 'year' );

		$crumb  = $this->get_breadcrumb_link(
			get_year_link( $year ),
			$year,
			$maybe_schema,
			$maybe_links
		);
		$crumb .= single_month_title( ' ', false );

		return $crumb;
	}



	/**
	 * Get day breadcrumb.
	 *
	 * @param bool $maybe_schema Whether to include schema markup.
	 * @param bool $maybe_links Whether to include links.
	 * @return string
	 */
	public function get_day_crumb( $maybe_schema, $maybe_links ) {

		global $wp_locale;

		$year  = get_query_var( 'm' ) ? mb_substr( get_query_var( 'm' ), 0, 4 ) : get_query_var( 'year' );
		$month = get_query_var( 'm' ) ? mb_substr( get_query_var( 'm' ), 4, 2 ) : get_query_var( 'monthnum' );
		$day   = get_query_var( 'm' ) ? mb_substr( get_query_var( 'm' ), 6, 2 ) : get_query_var( 'day' );

		$crumb  = $this->get_breadcrumb_link(
			get_year_link( $year ),
			$year,
			$maybe_schema,
			$maybe_links
		);
		$crumb .= $this->get_breadcrumb_link(
			get_month_link( $year, $month ),
			$wp_locale->get_month( $month ),
			$maybe_schema,
			$maybe_links
		);
		$crumb .= $this->args['labels']['date'] . $day . gmdate( 'S', mktime( 0, 0, 0, 1, $day ) );

		return $crumb;
	}

	/**
	 * Get post type breadcrumb.
	 *
	 * @return string
	 */
	public function get_post_type_crumb() {

		$crumb = '<span itemprop="name">' . esc_html( post_type_archive_title( '', false ) ) . '</span>';
		return $crumb;
	}

	/**
	 * Get term parents.
	 *
	 * @param int|string $parent_id Parent ID.
	 * @param string     $taxonomy Taxonomy name.
	 * @param bool       $link Whether to include link.
	 * @param bool       $maybe_parent_tax Whether to include parent taxonomy.
	 * @param bool       $maybe_schema Whether to include schema markup.
	 * @param bool       $maybe_links Whether to include links.
	 * @param array      $exclude Terms to exclude.
	 * @param array      $visited Visited terms.
	 * @return array
	 */
	public function get_term_parents( $parent_id, $taxonomy, $link = false, $maybe_parent_tax = true, $maybe_schema = true, $maybe_links = true, array $exclude = array(), array $visited = array() ) {

		$parent = get_term( (int) $parent_id, $taxonomy );

		if ( is_wp_error( $parent ) ) {
			return array();
		}

		if ( $maybe_parent_tax ) {

			if ( $parent->parent && ( $parent->parent !== $parent->term_id ) && ! in_array( $parent->parent, $visited, true ) && ! in_array( $parent->parent, $exclude, true ) ) {
				$visited[] = $parent->parent;
				$chain[]   = $this->get_term_parents( $parent->parent, $taxonomy, true, $maybe_parent_tax, $maybe_schema, $maybe_links, $exclude, $visited );
			}
		}

		if ( $link && ! is_wp_error( get_term_link( get_term( $parent->term_id, $taxonomy ), $taxonomy ) ) ) {

			$chain[] = $this->get_breadcrumb_link(
				get_term_link( get_term( $parent->term_id, $taxonomy ), $taxonomy ),
				$parent->name,
				$maybe_schema,
				$maybe_links
			);

		} else {
			$chain[] = '<span itemprop="name">' . $parent->name . '</span>';
		}

		return $chain;
	}

	/**
	 * Get breadcrumb link.
	 *
	 * @param string $url URL.
	 * @param string $content Content.
	 * @param bool   $maybe_schema Whether to include schema markup.
	 * @param bool   $maybe_links Whether to include links.
	 * @param bool   $has_icon Whether has icon.
	 * @return string
	 */
	public function get_breadcrumb_link( $url, $content, $maybe_schema = true, $maybe_links = true, $has_icon = false ) {
		return \BricksExtras\Helpers::breadcrumb_item( $url, $content, $maybe_links, $maybe_schema, $has_icon );
	}


	/**
	 * Render breadcrumbs.
	 *
	 * @param array       $crumbs Breadcrumbs array.
	 * @param bool        $maybe_schema Whether to include schema markup.
	 * @param bool        $remove_title Whether to remove title.
	 * @param string      $separator_type Separator type (text or icon).
	 * @param bool|string $separator_icon Separator icon HTML.
	 * @return string
	 */
	public function render_breadcrumbs( $crumbs, $maybe_schema, $remove_title, $separator_type = 'text', $separator_icon = false ) {

		$breadcrumbs_output = '';

		$list_item_schema = $maybe_schema ? ' itemprop="itemListElement" itemscope="" itemtype="http://schema.org/ListItem"' : '';

		$breadcrumbs_flat = $this->array_flatten( $crumbs );

		/* allow users to edit breadcrumbs array */
		$breadcrumbs_flat = apply_filters( 'bricksextras/breadcrumbs/', $breadcrumbs_flat );

		$breadcrumb_count = count( $breadcrumbs_flat ) - 1;

		foreach ( $breadcrumbs_flat as $key => $breadcrumb ) {

			$breakcrumb_active = ( $key === $breadcrumb_count ) ? ' aria-current="page"' : '';

			if ( ! $remove_title || ( $key !== $breadcrumb_count ) || ! is_singular() ) {

				$breadcrumbs_output .= '<li class="x-breadcrumbs_list-item"' . $list_item_schema . $breakcrumb_active . '>';

				if ( 'icon' === $separator_type && $separator_icon && $key > 0 ) {
					$breadcrumbs_output .= '<span class="x-breadcrumbs_separator" aria-hidden="true">' . $separator_icon . '</span>';
				}

				$breadcrumbs_output .= $breadcrumb;
				$breadcrumbs_output .= $maybe_schema ? '<meta itemprop="position" content="' . intVal( $key + 1 ) . '">' : '';
				$breadcrumbs_output .= '</li>';
			}
		}

		return $breadcrumbs_output;
	}


	/* helpers */

	/**
	 * Flatten array.
	 *
	 * @param array $input_array Input array.
	 * @return array
	 */
	public function array_flatten( $input_array ) {
		$return = array();
		foreach ( $input_array as $key => $value ) {
			if ( is_array( $value ) ) {
				$return = array_merge( $return, $this->array_flatten( $value ) );
			} else {
				$return[ $key ] = $value;
			}
		}

		return $return;
	}

	/**
	 * Convert nested array to single dimension.
	 *
	 * @param array $nested_array Nested array.
	 * @return array
	 */
	public function nestedToSingle( array $nested_array ) {

		$single_dim_array = array();

		foreach ( $nested_array as $item ) {

			if ( is_array( $item ) ) {
				$single_dim_array = array_merge( $single_dim_array, $this->nestedToSingle( $item ) );

			} else {
				$single_dim_array[] = $item;
			}
		}

		return $single_dim_array;
	}


	/**
	 * Retrieve all categories taxonomies
	 *
	 * @return array
	 */
	private function getCategories() {

		if ( ! bricks_is_builder() ) {
			return array();
		}

		$out        = array();
		$categories = get_categories(
			array(
				'orderby' => 'name',
				'order'   => 'ASC',
			)
		);

		if ( ! empty( $categories ) ) {

			foreach ( $categories as $category ) {
				$out[ $category->term_id ] = $category->name;
			}
		}

		return $out;
	}

	/**
	 * Retrieve all categories taxonomies
	 *
	 * @return array
	 */
	private function getProductCategories() {

		if ( ! bricks_is_builder() ) {
			return array();
		}

		$out        = array();
		$categories = get_categories(
			array(
				'taxonomy' => 'product_cat',
				'orderby'  => 'name',
				'order'    => 'ASC',
			)
		);

		if ( ! empty( $categories ) ) {

			foreach ( $categories as $category ) {
				$out[ $category->term_id ] = $category->name;
			}
		}

		return $out;
	}
}
