resolve = $resolve ?? [Resolver::class, 'for_location']; } public function register(): void { add_filter('template_include', [$this, 'template_include'], 999); add_filter('zadex/theme/location_candidates', [$this, 'front_page_candidates'], 5, 2); } /** Adds cross-location fallback on front page so a front-targeted template applies regardless of whether the front is single or archive. */ public function front_page_candidates(array $candidates, string $location): array { if (function_exists('is_front_page') && is_front_page()) { if ($location === 'archive' && !in_array('single', $candidates, true)) { $candidates[] = 'single'; } elseif ($location === 'single' && !in_array('archive', $candidates, true)) { $candidates[] = 'archive'; } } return $candidates; } /** Location of the current request: 404 | search | single | archive | ''. */ public static function location(): string { if (is_404()) { return '404'; } if (is_search()) { return 'search'; } if (is_singular()) { return 'single'; } if (is_archive() || is_home()) { return 'archive'; } return ''; } /** * Template types tried for a location, most specific first. Filter `zadex/theme/location_candidates` * (string[] $types, string $location): WooCommerce puts `product` before `single` on product pages and * `product_archive` before `archive` on the shop / product taxonomy archives. * * @return string[] */ public static function candidates(string $location): array { if ($location === '') { return []; } $list = apply_filters('zadex/theme/location_candidates', [$location], $location); return is_array($list) ? array_values(array_unique(array_filter($list, static fn($t): bool => is_string($t) && $t !== ''))) : [$location]; } public function template_include($template) { if (EditorLoader::mode() !== '' || is_singular(TemplatePost::POST_TYPE)) { return $template; } $location = self::location(); if ($location === '') { return $template; } if ($location === 'single' && Templates::get((int) get_queried_object_id()) !== '') { return $template; } $id = 0; foreach (self::candidates($location) as $candidate) { $found = ($this->resolve)($candidate); if (is_int($found) && $found > 0) { $id = $found; break; } } if ($id <= 0) { return $template; } $this->current = $id; return __DIR__ . '/views/page.php'; } /** Template chosen for this request by template_include (0 when the theme's template is used). */ public function current(): int { return $this->current; } }