renderer = $renderer; } public function register(): void { (new SearchController())->register(); (new LottieUploads())->register(); add_action('wp_login_failed', [self::class, 'login_failed'], 10, 1); add_filter('zadex/editor/config', [self::class, 'editor_config'], 10, 2); } public function renderer(): Renderer { return $this->renderer; } /** * URL of the current request without the given query args: the site's own origin (from home_url(), never * the client-supplied Host header) plus the sanitized request URI. Used for "back to this page" redirects * and share links; every consumer escapes it (esc_url / esc_attr) and WordPress validates redirects * (wp_safe_redirect / wp_validate_redirect). * * @param string[] $remove query args to drop */ public static function current_url(array $remove = []): string { $uri = self::request_uri(); $origin = self::site_origin(); if ($uri === '' || $origin === '' || (defined('REST_REQUEST') && REST_REQUEST)) { $url = function_exists('get_permalink') && get_permalink() ? (string) get_permalink() : (function_exists('home_url') ? (string) home_url('/') : '/'); } else { $url = $origin . $uri; } if ($remove && function_exists('remove_query_arg')) { $url = (string) remove_query_arg($remove, $url); } return (string) esc_url_raw($url); } /** Path + query of the current request ('/…'), unslashed and sanitized with esc_url_raw(); '' when unknown. */ public static function request_uri(): string { $uri = isset($_SERVER['REQUEST_URI']) ? esc_url_raw(wp_unslash($_SERVER['REQUEST_URI'])) : ''; if ($uri === '') { return ''; } // Only the path and query are kept (a proxy may send an absolute URI); control characters are dropped. $path = (string) wp_parse_url($uri, PHP_URL_PATH); $query = (string) wp_parse_url($uri, PHP_URL_QUERY); $path = '/' . ltrim((string) preg_replace('/[\x00-\x20"<>\\\\^`{|}]/', '', $path), '/'); return $path . ($query !== '' ? '?' . $query : ''); } /** scheme://host[:port] of home_url() ('' when unavailable). */ public static function site_origin(): string { $home = function_exists('home_url') ? (string) home_url('/') : ''; $parts = $home !== '' ? wp_parse_url($home) : false; if (!is_array($parts) || empty($parts['host'])) { return ''; } return ($parts['scheme'] ?? 'https') . '://' . $parts['host'] . (isset($parts['port']) ? ':' . (int) $parts['port'] : ''); } /** * Login widget: WordPress would show its own login page with the error. When the form came from the widget, * go back to that page instead (only same-site referers, wp_validate_redirect) with `?zx-login=failed`. */ public static function login_failed($username = ''): void { // The widget's form carries its own nonce (LOGIN_NONCE). Without a valid one (a normal wp-login.php form, // or a page cached for more than a day) WordPress shows its own login error page as usual. $nonce = isset($_POST['zx_login_widget']) ? sanitize_text_field(wp_unslash($_POST['zx_login_widget'])) : ''; if ($nonce === '' || !wp_verify_nonce($nonce, self::LOGIN_NONCE)) { return; } $referer = function_exists('wp_get_referer') ? (string) wp_get_referer() : ''; $referer = $referer !== '' && function_exists('wp_validate_redirect') ? (string) wp_validate_redirect($referer, '') : ''; if ($referer === '' || str_contains($referer, 'wp-login.php')) { return; } $target = (string) add_query_arg(['zx-login' => 'failed'], remove_query_arg(['zx-login', 'loggedout'], $referer)); wp_safe_redirect($target); if (self::$exit_after_redirect) { exit; } } /** Editor option list of the Template widget. */ public static function editor_config(array $config, int $post_id = 0): array { $data = is_array($config['data'] ?? null) ? $config['data'] : []; $data['proTemplates'] = TemplateEmbed::options($post_id); $config['data'] = $data; return $config; } }