<?php
/**
 * GlobalShortcodes
 *
 * @package CommonFrameworkPlugin
 */

namespace CommonFrameworkPlugin;

use CommonFrameworkPlugin\Utility;
use WP_Query;

/**
 * Creates the CommonFrameworkPlugin post type and shortcodes to output them.
 */
class GlobalShortcodes extends \CommonFrameworkPlugin\Module {

	/**
	 * Lookup table mapping image filenames to fallback alt text.
	 *
	 * This map is used when an image has no alt attribute provided in ACF,
	 * allowing the system to generate meaningful, accessible alt text based
	 * solely on the filename. The keys are image filenames and the values
	 * are human readable descriptions used as alt text.
	 *
	 * @var array<string,string>
	 */
	private $alt_text_map = [
		'desktop-ups.png' => 'vertiv desktop workstation',
		'enterprise-transformerless-ups.png' => 'vertiv enterprise ups',
		'midrange-ups.png' => 'vertiv midrange ups',
		'rackmount-ups.png' => 'vertiv small ups',
		'discontinued.png' => 'red discontinued sign',
		'heat-rejection.png' => 'refrigerant and glycol system',
		'high-heat-density.png' => 'high heat density system',
		'evaporative-cooling.png' => 'outdoor prackge cooling system',
		'large-room-cooling.png' => 'large room cooling system',
		'self-contained-cooling.png' => 'self-contained rack with open door',
		'small-room-cooling.png' => 'small room cooling solution',
		'Vertiv-iMPB.png' => 'vertiv busway and powerbar system',
		'power-distribution-unit.png' => 'vertiv power distribution cabinet',
		'cp-pts-gl-508x635-liebert-sts2-pdu.png' => 'static transfer switch in power distribution unit',
		'integrated-solutions.png' => 'vertiv smartrow unit',
		'rack-pdu.png' => 'white rack pdu split in two',
		'rack-accessories.png' => 'server rack shelf',
		'SmartRow_Top_View_large1.jpg' => 'top view of a vertiv smartrow solution',
		'remote-management-solutions.png' => 'vertiv kvm switch',
		'SmartCabinet-SC-e1466777002161.jpg' => 'smart cabinet on wheels',
		'over-ip-switches.png' => 'black kvm over ip switch',
		'remote-management-high-performance.png' => 'avocent high-performance kvm extension',
		'desktop-kvm.png' => 'desktop kvm switch',
		'secure-desktop-kvm.png' => 'secure desktop kvm switch',
		'advanced-serial-consoles.png' => 'advanced avocent serial console',
		'alber-bms.png' => 'alber bds battery monitoring system',
		'communications-cards.png' => 'building management system interface cards',
		'enterprise-monitoring.png' => 'enterprise monitoring system with red and green sections on screen',
		'leak-detection.png' => 'leak detection system',
		'iCom-s-thermal-system-control.jpg' => 'i-coms thermal system control screen',
		'smb-monitoring-systems.png' => 'vertiv rack power manager on desktop screen',
		'trellis-express-edition.jpg' => 'trellis real-time infrastructure optimization platform on desktop screen',
		'liebert-crv.png' => 'liebert crv cooling unit',
		'rack-brackets.png' => 'black rack bracket',
		'cable-management.png' => 'horizontal cable manager',
		'rack-panels.png' => 'server rack panel',
		'lcd-console-tray.png' => 'lcd console tray holding a computer',
		'cf_mph_1_cropped.jpg' => 'mph2-b rack mount pdu',
	];

	/**
	 * Only register if on an admin page and if fieldmanager plugin is active.
	 *
	 * @return bool
	 */
	public function can_register() {
		return true;
	}

	/**
	 * Register our hooks.
	 *
	 * @return void
	 */
	public function register() {
		add_shortcode( 'company_name', [ $this, 'company_name_shortcode' ] );
		add_shortcode( 'primary_address', [ $this, 'primary_address_shortcode' ] );
		add_shortcode( 'phone_number', [ $this, 'phone_number_shortcode' ] );
		add_shortcode( 'fax_number', [ $this, 'fax_number_shortcode' ] );
		add_shortcode( 'primary_email', [ $this, 'primary_email_shortcode' ] );
		add_shortcode( 'print_service_phones', [ $this, 'print_service_phones_shortcode' ] );
		add_shortcode( 'display_cta', [ $this, 'display_cta' ] );
		add_shortcode( 'site_info', [ $this, 'display_site_info' ] );
		add_shortcode( 'one_sixth', [ $this, 'one_sixth_shortcode' ] );
		add_shortcode( 'five_sixth_last', [ $this, 'five_sixth_last_shortcode' ] );
		add_shortcode( 'blog_id', [ $this, 'get_blog_id_shortocode' ] );
		add_shortcode( 'site_hide', [ $this, 'site_hide_shortcode' ] );
		add_shortcode( 'site_show', [ $this, 'site_show_shortcode' ] );
		add_shortcode( 'post_content', [ $this, 'post_content_shortcode' ] );
		add_shortcode( 'product_page_title', [ $this, 'product_page_title_shortcode' ] );
		add_shortcode( 'product_description', [ $this, 'product_description_shortcode' ] );
		add_shortcode( 'display_tax_product', [ $this, 'display_tax_product_shortcode' ] );
		add_shortcode( 'display_tax_discontinued_product', [ $this, 'display_tax_discontinued_product_shortcode' ] );
		add_shortcode( 'product_links', [ $this, 'product_links_shortcode' ] );
	}

	/**
	 * Generates and returns a company name via a shortcode.
	 * It fetches the company name from a custom field; if not set, it uses the site's default blog name.
	 *
	 * @return string The content of the company name.
	 */
	public function company_name_shortcode() {
		ob_start();

		$content = get_field( 'company_name', 'options' );
		if ( empty( $content ) || is_null( $content ) ) {
			$content = get_bloginfo( 'name' );
		}
		ob_end_clean();
		return $content;
	}

	/**
	 * Generates and returns the primary address via a shortcode.
	 * It retrieves the address from a custom field; if not set, it uses a predefined static address.
	 *
	 * @return string The primary address.
	 */
	public function primary_address_shortcode() {
		ob_start();
		$value = '123 Street St City, State XXXXX';
		if ( get_field( 'primary_address', 'options' ) ) :
			$value = get_field( 'primary_address', 'options' );
		endif;
		ob_end_clean();
		return $value;
	}


	/**
	 * Generates and returns a phone number hyperlink via a shortcode.
	 * It retrieves the phone number from a custom field, formats it, and wraps it in a tel: link.
	 *
	 * @return string The HTML hyperlink with the formatted phone number.
	 */
	public function phone_number_shortcode() {
		ob_start();
		$link = 'XXX.XXX.XXXX';
		if ( get_field( 'phone_number', 'options' ) ) :
			$number = get_field( 'phone_number', 'options' );
			$no_non_num = preg_replace( '/[^0-9]/', '', $number );
			$link = '<a href="tel:' . $no_non_num . '">' . $number . '</a>';
		endif;
		ob_end_clean();
		return $link;
	}

	/**
	 * Generates and returns a fax number hyperlink via a shortcode.
	 * Similar to the phone number, it retrieves the fax number from a custom field, formats it, and wraps it in a tel: link.
	 *
	 * @return string The HTML hyperlink with the formatted fax number.
	 */
	public function fax_number_shortcode() {
		ob_start();
		$link = 'XXX.XXX.XXXX';
		if ( get_field( 'fax_number', 'options' ) ) :
			$number = get_field( 'fax_number', 'options' );
			$no_non_num = preg_replace( '/[^0-9]/', '', $number );
			$link = '<a href="tel:' . $no_non_num . '">' . $number . '</a>';
		endif;
		ob_end_clean();
		return $link;
	}

	/**
	 * Generates and returns an email hyperlink via a shortcode.
	 * It fetches the email from a custom field and wraps it in a mailto: link.
	 *
	 * @return string The HTML hyperlink with the email.
	 */
	public function primary_email_shortcode() {
		ob_start();
		$link = '<a href="mailto:replaceme@fake.com">replaceme@fake.com</a>';
		if ( get_field( 'primary_email', 'options' ) ) :
			$link = '<a href="mailto:' . get_field( 'primary_email', 'options' ) . '">' . get_field( 'primary_email', 'options' ) . '</a>';
		endif;
		ob_end_clean();
		return $link;
	}

	/**
	 * Prints phone number icons and links for contact purposes.
	 * It takes a name, phone number, and optional status to generate a contact link with SVG icons.
	 *
	 * @param string $name The display name for the contact.
	 * @param string $phone_number The phone number to be formatted and displayed.
	 * @param string $status Additional CSS class to style the contact link differently.
	 */
	public function print_phone_num_icons( $name, $phone_number, $status = '' ) {
		$no_non_num = preg_replace( '/[^0-9]/', '', $phone_number );
		?>

		<a class="single-contact<?php echo ' ' . esc_attr( $status ); ?>" href="tel:<?php echo esc_attr( $no_non_num ); ?>">
			<div class="contact-link">
				<svg class="contact-svg" viewBox="0 0 512 512">
					<path d="M511.2 387l-23.25 100.8c-3.266 14.25-15.79 24.22-30.46 24.22C205.2 512 0 306.8 0 54.5c0-14.66 9.969-27.2 24.22-30.45l100.8-23.25C139.7-2.602 154.7 5.018 160.8 18.92l46.52 108.5c5.438 12.78 1.77 27.67-8.98 36.45L144.5 207.1c33.98 69.22 90.26 125.5 159.5 159.5l44.08-53.8c8.688-10.78 23.69-14.51 36.47-8.975l108.5 46.51C506.1 357.2 514.6 372.4 511.2 387z" />
				</svg>
				<div>
					<?php echo wp_kses_post( $name ); ?>
					<br>
					<?php echo wp_kses_post( $phone_number ); ?>
				</div>
			</div>
		</a>
		<?php
	}

	/**
	 * Generates contact information with options to display emergency service phone numbers.
	 * It displays dynamic contact options including phone numbers and emails fetched from custom fields or subfields.
	 *
	 * @param array       $atts Shortcode attributes.
	 * @param string|null $content Additional content if provided.
	 * @return string HTML content for the contact information section.
	 */
	public function print_service_phones_shortcode( $atts, $content = null ) {
		ob_start();

		if ( have_rows( 'emergency_service_phone_numbers', 'options' ) || get_field( 'phone_number', 'options' ) || get_field( 'primary_email', 'options' ) ) :
			?>
			<h2>Contact Information</h2>
			<?php

			if ( get_field( 'phone_number', 'options' ) || get_field( 'primary_email', 'options' ) ) :
				?>
				<h3 class="service-header">Need Services or Parts?</h3>
				<div class="service-contact">
					<?php if ( get_field( 'primary_email', 'options' ) ) : ?>
						<a class="single-contact" href="mailto:<?php echo esc_attr( get_field( 'primary_email', 'options' ) ); ?>">
							<div class="contact-link">
								<svg class="contact-svg" viewBox="0 0 512 512">
									<path d="M256 417.1c-16.38 0-32.88-4.1-46.88-15.12L0 250.9v213.1C0 490.5 21.5 512 48 512h416c26.5 0 48-21.5 48-47.1V250.9l-209.1 151.1C288.9 412 272.4 417.1 256 417.1zM493.6 163C484.8 156 476.4 149.5 464 140.1v-44.12c0-26.5-21.5-48-48-48l-77.5 .0016c-3.125-2.25-5.875-4.25-9.125-6.5C312.6 29.13 279.3-.3732 256 .0018C232.8-.3732 199.4 29.13 182.6 41.5c-3.25 2.25-6 4.25-9.125 6.5L96 48c-26.5 0-48 21.5-48 48v44.12C35.63 149.5 27.25 156 18.38 163C6.75 172 0 186 0 200.8v10.62l96 69.37V96h320v184.7l96-69.37V200.8C512 186 505.3 172 493.6 163zM176 255.1h160c8.836 0 16-7.164 16-15.1c0-8.838-7.164-16-16-16h-160c-8.836 0-16 7.162-16 16C160 248.8 167.2 255.1 176 255.1zM176 191.1h160c8.836 0 16-7.164 16-16c0-8.838-7.164-15.1-16-15.1h-160c-8.836 0-16 7.162-16 15.1C160 184.8 167.2 191.1 176 191.1z" />
								</svg>
								<div>
									Send us an Email
								</div>
							</div>
						</a>
						<?php
					endif;
					if ( get_field( 'phone_number', 'options' ) ) :
						$number = get_field( 'phone_number', 'options' );
						$no_non_num = preg_replace( '/[^0-9]/', '', $number );

						?>
						<a class="single-contact" href="tel:<?php echo esc_attr( $no_non_num ); ?>">
							<div class="contact-link">
								<svg class="contact-svg" viewBox="0 0 512 512">
									<path d="M511.2 387l-23.25 100.8c-3.266 14.25-15.79 24.22-30.46 24.22C205.2 512 0 306.8 0 54.5c0-14.66 9.969-27.2 24.22-30.45l100.8-23.25C139.7-2.602 154.7 5.018 160.8 18.92l46.52 108.5c5.438 12.78 1.77 27.67-8.98 36.45L144.5 207.1c33.98 69.22 90.26 125.5 159.5 159.5l44.08-53.8c8.688-10.78 23.69-14.51 36.47-8.975l108.5 46.51C506.1 357.2 514.6 372.4 511.2 387z" />
								</svg>
								<div>
									<?php echo wp_kses_post( $number ); ?>
								</div>
							</div>
						</a>
					<?php endif; ?>
				</div>
			<?php endif; ?>


			<?php

			if ( have_rows( 'emergency_service_phone_numbers', 'options' ) ) :
				?>
				<h3 class="service-header">In case of an emergency call:</h3>
				<div class="service-contact">
					<?php
					while ( have_rows( 'emergency_service_phone_numbers', 'options' ) ) : the_row();
						$this->print_phone_num_icons( get_sub_field( 'name' ), get_sub_field( 'phone_number' ), 'emergency-number' );
					endwhile;
					?>
				</div>
				<?php
			endif;
		endif;
		?>
		<?php

		$html = ob_get_contents();
		ob_end_clean();
		return $html;
	}

	/**
	 * Displays a Call-To-Action (CTA) based on the context or default settings.
	 * It retrieves a CTA from a custom field or fetches a default if not set, and uses Elementor to render the content.
	 *
	 * @param array $atts Attributes to control the output.
	 * @return string Rendered HTML content of the CTA.
	 */
	public function display_cta( $atts ) {

		$output = '';
		// Check if the current page has a custom field called "cta"
		$cta_post_id = get_field( 'cta' );
		if ( $cta_post_id ) {
			// Display the content of the CTA post
			$output .= \Elementor\Plugin::instance()->frontend->get_builder_content_for_display( $cta_post_id );
			return $output;
		}

		$slug_to_lookup = 'default';
		$taxonomy = 'product-category';
		$vertiv_term = get_term_by( 'slug', 'vertiv', $taxonomy );

		// Helper: recursively find the deepest descendant of a term with a matching CTA
		$find_descendant_cta_slug = function ( $term ) use ( &$find_descendant_cta_slug, $taxonomy ) {
			$children = get_terms(
				[
					'taxonomy'   => $taxonomy,
					'parent'     => $term->term_id,
					'hide_empty' => false,
				]
			);

			// First, check if this term itself has a CTA post
			$maybe_cta = get_page_by_path( $term->slug, OBJECT, 'cta' );
			if ( $maybe_cta ) {
				return $term->slug;
			}

			// Then, recursively check each child
			foreach ( $children as $child ) {
				$found = $find_descendant_cta_slug( $child );
				if ( $found ) {
					return $found;
				}
			}

			return '';
		};

		if ( is_tax( $taxonomy ) ) {
			$current_term = get_queried_object();
			if ( $current_term && $vertiv_term ) {
				$top_term = $current_term;
				while ( $top_term->parent ) {
					$top_term = get_term( $top_term->parent, $taxonomy );
				}

				if ( 'vertiv' === $top_term->slug ) {
					$slug_to_lookup = $find_descendant_cta_slug( $current_term );
					if ( ! $slug_to_lookup ) {
						$slug_to_lookup = $current_term->slug;
					}
				}
			}
		} elseif ( is_singular( 'products' ) ) {
			$terms = get_the_terms( get_the_ID(), $taxonomy );
			if ( $terms && $vertiv_term ) {
				foreach ( $terms as $term ) {
					$top_term = $term;
					while ( $top_term->parent ) {
						$top_term = get_term( $top_term->parent, $taxonomy );
					}

					if ( 'vertiv' === $top_term->slug ) {
						$slug_to_lookup = $find_descendant_cta_slug( $term );
						if ( ! $slug_to_lookup ) {
							$slug_to_lookup = $term->slug;
						}
						break;
					}
				}
			}
		}

		$cta = get_page_by_path( $slug_to_lookup, OBJECT, 'cta' );
		if ( ! $cta ) {
			$cta = get_page_by_path( 'default', OBJECT, 'cta' );
		}

		if ( $cta ) {
			$cta_id = $cta->ID;
			$output .= \Elementor\Plugin::instance()->frontend->get_builder_content_for_display( $cta_id );
		}

		return $output;
	}

	/**
	 * Displays site-specific information based on a provided key in shortcode attributes.
	 * It fetches the information from custom fields set within theme options.
	 *
	 * @param array $atts Attributes where 'key' determines what information to fetch.
	 * @return string The content associated with the specified key, or a placeholder if not set.
	 */
	public function display_site_info( $atts ) {

		$attributes = shortcode_atts(
			array(
				'key'   => null,
			),
			$atts
		);

		$content = get_field( $attributes['key'], 'options' );
		if ( null === $content || '' === trim( $content ) ) {
			$content = '[' . $attributes['key'] . ']';
		}

		return $content;
	}

	/**
	 * Creates a layout block with one-sixth width using shortcodes.
	 * This function starts a block that can be filled with content and styles it to take up one-sixth of the container’s width.
	 *
	 * @param array       $atts Attributes controlling the output, not specifically used here.
	 * @param string|null $content The content to be wrapped within the one-sixth width block.
	 * @return string HTML content for the one-sixth layout block.
	 */
	public function one_sixth_shortcode( $atts, $content = null ) {
		ob_start();

		?>
		<div class="tax-item elementor-text-editor elementor-clearfix">
			<div class="one_sixth">
				<?php echo wp_kses_post( $content ); ?>
			</div>
		<?php

		$html = ob_get_contents();
		ob_end_clean();
		return $html;
	}

	/**
	 * Creates a layout block with five-sixth width, intended as the last block in a row using shortcodes.
	 * This function ends the block started by a previous one-sixth block, filling the rest of the container's width.
	 *
	 * @param array       $atts Attributes controlling the output, not specifically used here.
	 * @param string|null $content The content to be wrapped within the five-sixth width block.
	 * @return string HTML content for the five-sixth layout block.
	 */
	public function five_sixth_last_shortcode( $atts, $content = null ) {
		ob_start();

		?>
			<div class="five_sixth last">
				<?php echo wp_kses_post( $content ); ?>
			</div>
		</div>
		<?php

		$html = ob_get_contents();
		ob_end_clean();
		return $html;
	}

	/**
	 * Returns the current blog ID in a multisite network via shortcode.
	 *
	 * @param array $atts Shortcode attributes, not used here.
	 * @return int The current site's blog ID.
	 */
	public function get_blog_id_shortocode( $atts ) {
		return get_current_blog_id();
	}

	/**
	 * Shortcode to hide content based on the site ID.
	 * It checks if the current site's ID is in an excluded list, and if so, does not display the content.
	 *
	 * @param array       $atts Shortcode attributes where 'exclude' is a list of site IDs to hide the content.
	 * @param string|null $content The content that may be hidden based on the site ID.
	 * @return string Either an empty string or the unmodified content based on the exclusion criteria.
	 */
	public function site_hide_shortcode( $atts, $content = null ) {
		ob_start();
		$atts = shortcode_atts(
			array(
				'exclude' => '',
			),
			$atts
		);
		$exclude_id = array();
		$exclude_id = explode( ',', $atts['exclude'] );
		$blog_id = get_current_blog_id();
		if ( in_array( $blog_id, $exclude_id ) ) {
			echo '';
		} else {
			echo wp_kses_post( $content );
		}
		$site_hide = ob_get_contents();
		ob_end_clean();
		return $site_hide;
	}

	/**
	 * Shortcode to show content based on the site ID.
	 * It displays the content only if the current site's ID is in the included list.
	 *
	 * @param array       $atts Shortcode attributes where 'include' is a list of site IDs that will show the content.
	 * @param string|null $content The content that may be displayed based on the inclusion criteria.
	 * @return string Either an empty string or the unmodified content based on the inclusion criteria.
	 */
	public function site_show_shortcode( $atts, $content = null ) {
		ob_start();
		$atts = shortcode_atts(
			array(
				'include' => '',
			),
			$atts
		);
		$include_id = array();
		$include_id = explode( ',', $atts['include'] );
		$blog_id = get_current_blog_id();
		if ( in_array( $blog_id, $include_id ) ) {
			echo wp_kses_post( $content );
		} else {
			echo '';
		}
		$site_show = ob_get_contents();
		ob_end_clean();
		return $site_show;
	}

	/**
	 * Outputs the content of the current post using a shortcode.
	 * This function captures and returns the main content of the current post.
	 *
	 * @return string The main content of the current post.
	 */
	public function post_content_shortcode() {
		ob_start();
		the_content();
		$content = ob_get_contents();
		ob_end_clean();

		return $content;
	}

	/**
	 * Displays a custom page title for product pages based on the queried category.
	 * It fetches a custom title from ACF fields associated with the product category term.
	 *
	 * @param array $atts Shortcode attributes, not used here.
	 * @return string The custom or default page title.
	 */
	public function product_page_title_shortcode( $atts ) {
		ob_start();

		$term = get_queried_object();
		$term_id = $term->term_id;
		$acf_termid = 'product-category_' . $term_id;

		if ( get_field( 'page_title', $acf_termid ) ) :
			?>
			<h1><?php echo esc_html( get_field( 'page_title', $acf_termid ) ); ?></h1>
			<?php
		endif;

		$content = ob_get_contents();
		ob_end_clean();
		return $content;
	}

	/**
	 * Outputs a custom product description based on the queried category.
	 * It fetches the description from ACF fields linked to the product category term and displays it.
	 *
	 * @param array $atts Shortcode attributes, not used here.
	 * @return string The product description.
	 */
	public function product_description_shortcode( $atts ) {
		ob_start();

		$term = get_queried_object();
		$term_id = $term->term_id;
		$acf_termid = 'product-category_' . $term_id;

		if ( get_field( 'description', $acf_termid ) ) :
			?>
			<?php echo wp_kses_post( get_field( 'description', $acf_termid ) ); ?>
			<?php
		endif;

		$content = ob_get_contents();
		ob_end_clean();
		return $content;
	}

	/**
	 * Shortcode function to display taxonomy information for products.
	 * It outputs additional content, line items, and optionally featured products related to a specific product taxonomy.
	 * This function handles the display of a taxonomy page, including images, links, titles, and descriptions fetched from custom fields.
	 * It also handles displaying child categories and additional products specified in the taxonomy custom fields.
	 *
	 * @param array $atts Attributes passed to the shortcode which may influence the output.
	 * @return string The formatted HTML content containing taxonomy details for products.
	 */
	public function display_tax_product_shortcode( $atts ) {
		ob_start();

		$term = get_queried_object();

		if ( is_null( $term ) ) {
			return;
		}

		$term_id = $term->term_id;
		$acf_termid = 'product-category_' . $term_id;

		if ( get_field( 'additional_item_content', $acf_termid ) ) :
			?>
			<?php echo wp_kses_post( get_field( 'additional_item_content', $acf_termid ) ); ?>
			<?php
		endif;

		if ( have_rows( 'additional_line_items', $acf_termid ) ) :
			while ( have_rows( 'additional_line_items', $acf_termid ) ) : the_row();
				?>
				<div class="tax-item elementor-text-editor elementor-clearfix">
					<div class="one_sixth">
						<?php
						if ( get_sub_field( 'image_source', $acf_termid ) ) {
							$image_url = get_sub_field( 'image_source', $acf_termid );
							?>
							<img src="https://commonframework.us/app/uploads/products/categories/<?php echo esc_attr( $image_url ); ?>" alt="<?php echo esc_attr( $this->get_fallback_alt( $image_url ) ); ?>" title="<?php echo esc_attr( get_sub_field( 'title', $acf_termid ) ); ?>" />
						<?php } ?>
					</div>
					<div class="five_sixth last">
						<?php if ( ! get_sub_field( 'link', $acf_termid ) ) : ?>
							<h2><?php echo esc_html( get_sub_field( 'title', $acf_termid ) ); ?></h2>
						<?php elseif ( get_sub_field( 'external_link', $acf_termid ) ) : ?>
							<h2><a href="<?php echo esc_url( get_sub_field( 'link', $acf_termid ) ); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html( get_sub_field( 'title', $acf_termid ) ); ?></a></h2>
						<?php else : ?>
							<h2><a href="<?php echo esc_url( get_sub_field( 'link', $acf_termid ) ); ?>"><?php echo esc_html( get_sub_field( 'title', $acf_termid ) ); ?></a></h2>
						<?php endif; ?>
						<?php echo wp_kses_post( get_sub_field( 'description', $acf_termid ) ); ?>
					</div>
				</div>
				<?php
			endwhile;
		endif;

		// List any featured products selected
		if ( have_rows( 'featured_products', $acf_termid ) ) {

			$product_ids = array();
			while ( have_rows( 'featured_products', $acf_termid ) ) : the_row();
				$product_id = get_sub_field( 'product' );
				array_push( $product_ids, $product_id );
			endwhile;

			$dynamic_meta_query = array(
				'post_type' => 'products',
				'meta_query' => array(
					'relation' => 'OR',
				),
			);
			foreach ( $product_ids as $product_id ) {
				array_push(
					$dynamic_meta_query['meta_query'],
					array(
						'key' => 'product_id',
						'value' => $product_id,
						'compare' => '=',
					)
				);
			}
			$all_product_objects = get_posts( $dynamic_meta_query );

			foreach ( $all_product_objects as $product_object ) :

				$product_post_id = $product_object->ID;
				?>
				<div class="tax-item elementor-text-editor elementor-clearfix featured-section">
					<span class="featured-tag">Featured Product</span>
					<div class="one_sixth">


						<?php

						if ( get_field( 'product_id', $product_post_id ) && get_field( 'product_images', $product_post_id ) ) {
							$images = get_field( 'product_images', $product_post_id );
							$image = array_shift( $images );
							if ( ! empty( $image ) ) {
								?>
								<img src="https://commonframework.us/app/uploads/products/<?php echo esc_attr( $image['image'] ); ?>" alt="<?php echo esc_attr( $product_object->post_title ); ?>" title="<?php echo esc_attr( $product_object->post_title ); ?>" />
								<?php
							}
						}
						?>
					</div>
					<div class="five_sixth last">
						<h2><a href="<?php echo esc_url( get_permalink( $product_post_id ) ); ?>"><?php echo esc_html( $product_object->post_title ); ?></a></h2>
						<?php echo wp_kses_post( wpautop( $product_object->post_content ) ); ?>
					</div>
				</div>
				<?php
				endforeach;
		}

		// Display Child Categories
		$children = array();
		$children = get_terms(
			array(
				'taxonomy' => 'product-category',
				'hide_empty' => false,
				'parent' => $term_id,
			)
		);

		// Get any additional categories selected
		if ( have_rows( 'additional_categories', $acf_termid ) ) {

			$category_slugs = array();
			while ( have_rows( 'additional_categories', $acf_termid ) ) : the_row();
				$category_slug = get_sub_field( 'category' );
				array_push( $category_slugs, $category_slug );
			endwhile;

			foreach ( $category_slugs as $category_slug ) {
				$category = get_term_by( 'slug', $category_slug, 'product-category' );
				array_push( $children, $category );
			}

			// Sort categories by title ASC
			Utility\array_sort( $children, 'title', SORT_ASC );
		}

		$exclude_categories = array();
		// Add Discontinued term into excluded categories
		$discontinued_term = get_term_by( 'slug', 'discontinued', 'product-category' );
		if ( $discontinued_term ) {
			array_push( $exclude_categories, $discontinued_term->term_id );
		}

		// Display additional and sub categories

		if ( ! empty( $children ) && ! is_wp_error( $children ) ) {
			foreach ( $children as $child ) {
				if ( is_object( $child ) ) {

					$term_id = 'product-category_' . $child->term_id;
					?>
					<div class="tax-item elementor-text-editor elementor-clearfix">
						<div class="one_sixth">
							<?php
							if ( get_field( 'featured_image', $term_id ) ) {
								$image_url = get_field( 'featured_image', $term_id );
								?>
								<img src="https://commonframework.us/app/uploads/products/categories/<?php echo esc_attr( $image_url ); ?>" alt="<?php echo esc_attr( $this->get_fallback_alt( $image_url ) ); ?>" />
							<?php } ?>
						</div>
						<div class="five_sixth last">
							<h2><a href="<?php echo esc_url( get_term_link( $child ) ); ?>"><?php echo esc_html( $child->name ); ?></a></h2>
							<?php echo wp_kses_post( get_field( 'excerpt', $term_id ) ); ?>
						</div>
					</div>
					<?php
					array_push( $exclude_categories, $child->term_id );
				}
			}
			// reset term_id
			$term_id = $term->term_id;
		}

		// ADD ADDITIONAL PRODUCTS FROM additional_products repeater HERE.
		// SORT THEM INTO POSTS ARRAY LATER
		if ( have_rows( 'additional_products', $acf_termid ) ) {

			// TODO loop through it get the ids then add the ids into one query then do one query for what we get back.

			$product_ids = array();
			while ( have_rows( 'additional_products', $acf_termid ) ) : the_row();
				$product_id = get_sub_field( 'product' );
				array_push( $product_ids, $product_id );
			endwhile;

			$dynamic_meta_query = array(
				'post_type' => 'products',
				'meta_query' => array(
					'relation' => 'OR',
				),
			);
			foreach ( $product_ids as $product_id ) {
				array_push(
					$dynamic_meta_query['meta_query'],
					array(
						'key' => 'product_id',
						'value' => $product_id,
						'compare' => '=',
					)
				);
			}

			$all_product_objects = get_posts( $dynamic_meta_query );

			foreach ( $all_product_objects as $product_object ) :

				$product_post_id = $product_object->ID;
				?>
				<div class="tax-item elementor-text-editor elementor-clearfix">
					<div class="one_sixth">
						<?php
						$alt_tag = get_bloginfo( 'name' ) . ' ' . $product_object->post_title;
						if ( get_field( 'product_id', $product_post_id ) && get_field( 'product_images', $product_post_id ) ) {
							$images = get_field( 'product_images', $product_post_id );
							$image = array_shift( $images );
							if ( ! empty( $image ) ) {
								?>
								<img src="https://commonframework.us/app/uploads/products/<?php echo esc_attr( $image['image'] ); ?>" alt="<?php echo esc_attr( $alt_tag ); ?>" title="<?php echo esc_attr( $alt_tag ); ?>" />
								<?php
							}
						}
						?>
					</div>
					<div class="five_sixth last">
						<h2><a href="<?php echo esc_url( get_the_permalink( $product_post_id ) ); ?>"><?php echo esc_html( $product_object->post_title ); ?></a></h2>
						<?php echo wp_kses_post( wpautop( $product_object->post_content ) ); ?>
					</div>
				</div>

				<?php
			endforeach;
		}

		/**
		 * Show Products when no more categories can be shown OR if Show Products field is set to true.
		 * The Show Products field is used to show products even if the page has child categories.
		 */

		if ( 'true' == get_field( 'show_products', $acf_termid ) || empty( $children ) ) {

			$args = array(
				'post_type' => 'products',
				'post_status' => 'publish',
				'posts_per_page' => '-1',
				'order' => 'ASC',
				'orderby' => 'title',
				'tax_query' => array(
					'relation' => 'AND',
					array(
						'taxonomy' => 'product-category',
						'field'    => 'term_id',
						'terms'    => $term_id,
						'operator' => 'IN',
					),
					array(
						'taxonomy' => 'product-category',
						'field'       => 'term_id',
						'terms'    => $exclude_categories,
						'operator' => 'NOT IN',
					),
				),
			);

			$query = new WP_Query( $args );

			if ( $query->have_posts() ) {

				while ( $query->have_posts() ) {

					$query->the_post();

					if ( empty( get_field( 'parent_product_id' ) ) ) {
						?>
						<div class="tax-item elementor-text-editor elementor-clearfix">
							<div class="one_sixth">
								<?php $alt_tag = get_bloginfo( 'name' ) . ' ' . get_the_title(); ?>
								<?php
								if ( get_field( 'product_id' ) && get_field( 'product_images' ) ) {
									$images = get_field( 'product_images' );
									$image = array_shift( $images );
									if ( ! empty( $image ) ) {
										?>
										<img src="https://commonframework.us/app/uploads/products/<?php echo esc_attr( $image['image'] ); ?>" alt="<?php echo esc_attr( $alt_tag ); ?>" title="<?php echo esc_attr( $alt_tag ); ?>" />
									<?php } ?>
								<?php } ?>
							</div>
							<div class="five_sixth last">
								<h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
								<?php the_content(); ?>
							</div>
						</div>

						<?php
					}
				}
				wp_reset_postdata();
			}
		}

		// ADD ADDITIONAL CONTENT from additional_content textarea HERE
		// Show link to discontinued page with query string that filters the page.

		if ( $term_id && $discontinued_term ) {
			$args = array(
				'post_type' => 'products',
				'post_status' => 'publish',
				'posts_per_page' => '-1',
				'order' => 'ASC',
				'orderby' => 'title',
				'tax_query' => array(
					array(
						'taxonomy' => 'product-category',
						'field' => 'id',
						'terms' => array( $term_id, $discontinued_term->term_id ),
						'include_children' => false,
						'operator' => 'AND',
					),
				),
			);

			if ( get_posts( $args ) ) {

				$discontinued_id = 'product-category_' . $discontinued_term->term_id;
				?>
	
				<div class="tax-item elementor-text-editor elementor-clearfix">
					<div class="one_sixth">
						<?php
						if ( get_field( 'featured_image', $discontinued_id ) ) {
							$image_url = get_field( 'featured_image', $discontinued_id );
							?>
							<img src="https://commonframework.us/app/uploads/products/<?php echo esc_attr( $image_url ); ?>" alt="<?php echo esc_attr( $this->get_fallback_alt( $image_url ) ); ?>" />
						<?php } ?>
					</div>
					<div class="five_sixth last">
						<h2><a href="<?php echo esc_url( get_term_link( $discontinued_term->term_id ) ); ?>?category=<?php echo esc_attr( $term->slug ); ?>">Discontinued <?php echo esc_html( $term->name ); ?> Products</a></h2>
						<p>View the whole line of Discontinued <?php echo esc_html( $term->name ); ?> products that we support.</p>
					</div>
				</div>
	
				<?php
			}

			wp_reset_postdata();
		}

		$products_tax = ob_get_contents();
		ob_end_clean();
		return $products_tax;
	}

	/**
	 * Generates a shortcode output for displaying a list of discontinued products.
	 * The function retrieves both discontinued products and their related categories based on the taxonomy term 'product-category'.
	 * If a category parameter is provided via URL query, it filters the display to include only those products and subcategories under the specified category.
	 * Otherwise, it displays all products and subcategories under the discontinued products category.
	 *
	 * @param array $atts An associative array of shortcode attributes, with 'slug' indicating the parent category slug if provided.
	 * @return string HTML content for the discontinued products section, formatted for display.
	 */
	public function display_tax_discontinued_product_shortcode( $atts ) {
		ob_start();

		$discontinued_term = get_queried_object();
		$category_param = isset( $_GET['category'] ) ? sanitize_text_field( wp_unslash( $_GET['category'] ) ) : false;

		if ( $category_param && get_term_by( 'slug', $category_param, 'product-category' ) ) {

			$term = get_term_by( 'slug', $category_param, 'product-category' );

			$term_id = $term->term_id;

			$using_params = true;

			$args = array(
				'post_type' => 'products',
				'post_status' => 'publish',
				'posts_per_page' => '-1',
				'order' => 'ASC',
				'orderby' => 'title',
				'tax_query' => array(
					array(
						'taxonomy' => 'product-category',
						'field' => 'id',
						'terms' => array( $term_id, $discontinued_term->term_id ),
						'include_children' => false,
						'operator' => 'AND',
					),
				),
			);
		} else {

			$term = get_queried_object();

			$term_id = $term->term_id;

			$using_params = false;

			$args = array(
				'post_type' => 'products',
				'post_status' => 'publish',
				'posts_per_page' => '-1',
				'order' => 'ASC',
				'orderby' => 'title',
				'tax_query' => array(
					array(
						'taxonomy' => 'product-category',
						'field'    => 'id',
						'terms'    => $term_id,
					),
				),
			);
		}

		$acf_termid = 'product-category_' . $term_id;

		// Display Child Categories
		$children = get_terms(
			array(
				'taxonomy' => 'product-category',
				'hide_empty' => false,
				'parent' => $discontinued_term->term_id,
			)
		);

		// Get any additional categories selected
		if ( have_rows( 'additional_categories', $acf_termid ) ) {
			$category_slugs = array();
			while ( have_rows( 'additional_categories', $acf_termid ) ) : the_row();
				$category_slug = get_sub_field( 'category' );
				array_push( $category_slugs, $category_slug );
			endwhile;

			foreach ( $category_slugs as $category_slug ) {
				$category = get_term_by( 'slug', $category_slug, 'product-category' );
				array_push( $children, $category );
			}

			// Sort categories by title ASC
			Utility\array_sort( $children, 'title', SORT_ASC );
		}

		// Display additional and sub categories
		if ( ! empty( $children ) && ! is_wp_error( $children ) ) {
			foreach ( $children as $child ) {
				$child_acf_termid = 'product-category_' . $child->term_id;
				if ( have_rows( 'discontinued_relationship', $child_acf_termid ) ) {

					$category_slugs = array();
					while ( have_rows( 'discontinued_relationship', $child_acf_termid ) ) : the_row();
						$category_slug = get_sub_field( 'relationship' );
						array_push( $category_slugs, $category_slug );
					endwhile;

					$disc_items = array();
					foreach ( $category_slugs as $category_slug ) {
						$disc_item = get_term_by( 'slug', $category_slug, 'product-category' );
						array_push( $disc_items, $disc_item );
					}

					foreach ( $disc_items as $disc_item ) :
						if ( $disc_item->term_id === $term_id && $using_params ) {
							?>

							<div class="tax-item elementor-text-editor elementor-clearfix">
								<div class="one_sixth">
									<?php
									if ( get_field( 'featured_image', $child_acf_termid ) ) {
										$image_url = get_field( 'featured_image', $child_acf_termid );
										?>
										<img src="https://commonframework.us/app/uploads/products/categories/<?php echo esc_attr( $image_url ); ?>" alt="<?php echo esc_attr( $this->get_fallback_alt( $image_url ) ); ?>" />
									<?php } ?>
								</div>
								<div class="five_sixth last">
									<h2><a href="<?php echo esc_url( get_term_link( $child ) ); ?>"><?php echo esc_html( $child->name ); ?></a></h2>
									<?php echo wp_kses_post( get_field( 'excerpt', $child_acf_termid ) ); ?>
								</div>
							</div>
							<?php
						}
					endforeach;
				}
			}
		}

		// Show Products when no more categories can be shown
		$query = new WP_Query( $args );

		if ( $query->have_posts() ) {

			while ( $query->have_posts() ) {

				$query->the_post();
				?>
				<div class="tax-item elementor-text-editor elementor-clearfix">
					<div class="one_sixth">
						<?php
						if ( get_field( 'product_id' ) && get_field( 'product_images' ) ) {
							$product_images = get_field( 'product_images' );
							$image = array_shift( $product_images );
							$alt_tag = get_bloginfo( 'name' ) . ' ' . get_the_title();
							if ( ! empty( $image ) ) {
								?>
								<img src="https://commonframework.us/app/uploads/products/<?php echo esc_attr( $image['image'] ); ?>" alt="<?php echo esc_attr( $alt_tag ); ?>" title="<?php echo esc_attr( $alt_tag ); ?>" />
								<?php
							}
						}
						?>
					</div>
					<div class="five_sixth last">
						<h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
						<?php the_content(); ?>
					</div>
				</div>
				<?php
			}
			wp_reset_postdata();
		}

		wp_reset_postdata();

		$products_disc_tax = ob_get_contents();
		ob_end_clean();
		return $products_disc_tax;
	}

	/**
	 * Shortcode function to display links to child product categories based on a parent category slug.
	 * It outputs an unordered list of links to the child categories of a specified parent category in the 'product-category' taxonomy.
	 * The parent category slug is provided via shortcode attributes, and additional categories can be included if specified in the ACF fields.
	 *
	 * @param array $atts Shortcode attributes, including:
	 *                    - 'slug': The slug of the parent product category.
	 * @return string The formatted HTML content containing links to the child product categories.
	 */
	public function product_links_shortcode( $atts ) {
		ob_start();
		$atts = shortcode_atts(
			array(
				'slug' => '',
			),
			$atts
		);

		$parent_slug = $atts['slug'];
		$parent_term = get_term_by( 'slug', $parent_slug, 'product-category' );
		$term_id = $parent_term->term_id;
		$acf_termid = 'product-category_' . $term_id;
		echo wp_kses_post( get_field( 'excerpt', $acf_termid ) );
		wp_reset_postdata();

		$children = array();
		$children = get_terms(
			array(
				'taxonomy' => 'product-category',
				'hide_empty' => false,
				'parent' => $term_id,
			)
		);

		if ( have_rows( 'additional_categories', $acf_termid ) ) {

			$category_slugs = array();
			while ( have_rows( 'additional_categories', $acf_termid ) ) : the_row();
				$category_slug = get_sub_field( 'category' );
				array_push( $category_slugs, $category_slug );
			endwhile;

			foreach ( $category_slugs as $category_slug ) {
				$category = get_term_by( 'slug', $category_slug, 'product-category' );
				array_push( $children, $category );
			}

			// Sort categories by title ASC
			Utility\array_sort( $children, 'title', SORT_ASC );
		}

		if ( ! empty( $children ) && ! is_wp_error( $children ) ) {
			?>
			<ul>
			<?php
			foreach ( $children as $child ) {
				if ( is_object( $child ) ) {
					?>
					<li><a href="<?php echo esc_url( get_term_link( $child ) ); ?>"><?php echo esc_html( $child->name ); ?></a> <i aria-hidden="true" class="fas fa-caret-right"></i></li>
					<?php
				}
			}
			?>
			</ul>
			<?php
		}
		$content = ob_get_contents();
		ob_end_clean();
		return $content;
	}

	/**
	 * Returns fallback alt text for a given image URL.
	 *
	 * This method extracts the filename from the provided URL and checks it
	 * against the alt text lookup map. If a match is found, the mapped alt text
	 * is returned. If no match exists, an empty string is returned so default
	 * WordPress alt behavior can take over.
	 *
	 * @param string $image_url The full URL or path to the image file.
	 * @return string Fallback alt text if available, otherwise an empty string.
	 */
	private function get_fallback_alt( $image_url ) {
		$filename = basename( $image_url );

		if ( isset( $this->alt_text_map[ $filename ] ) ) {
			return $this->alt_text_map[ $filename ];
		}

		// If no exact match, return empty so WP uses the existing alt or title
		return '';
	}
}
