$vars */ private function fillTpl(string $name, array $vars): string { $tpl = $this->tpl($name); $search = array(); $replace = array(); foreach ($vars as $k => $v) { $search[] = '{' . $k . '}'; $replace[] = $v; } if (is_object($this->f)) { return (string)$this->f->str_replace($search, $replace, $tpl); } return (string)str_replace($search, $replace, $tpl); } /** @return void */ function echoAdminFooter(): void { $html = ABJ_404_Solution_FileSystemService::readFileContents(dirname(__DIR__) . "/html/adminFooter.html"); echo $this->f->renderTemplate($html, array('{JAPANESE_FLASHCARDS_URL}' => ABJ404_FC_URL)); } function outputAdminHeaderTabs(string $sub = 'list', string $message = ''): void { ABJ_404_Solution_WPNotices::echoAdminNotices(); echo $this->tpl('adminHeaderWrapOpen.html'); if (isset($_GET['setup_complete']) && $_GET['setup_complete'] === '1') { $options = abj_service('options_repository')->getOptions(); $auto = !empty($options['auto_redirects']) && $options['auto_redirects'] !== '0'; $notify = !empty($options['admin_notification']) && $options['admin_notification'] !== '0'; if ($auto && $notify) { $body = esc_html__('404 Solution is now monitoring your site. When visitors hit broken links, they will be automatically redirected. We will email you if something needs attention.', '404-solution'); } elseif ($auto) { $body = esc_html__('404 Solution is now monitoring your site. When visitors hit broken links, they will be automatically redirected.', '404-solution'); } elseif ($notify) { $body = esc_html__('404 Solution is now monitoring your site. We will email you if captured 404 URLs need attention.', '404-solution'); } else { $body = esc_html__('404 Solution is now monitoring your site. You can create manual redirects anytime from the Page Redirects tab.', '404-solution'); } echo $this->fillTpl('setupCompleteWelcomeBanner.html', array( 'heading' => esc_html__("You're all set!", '404-solution'), 'body' => $body, )) . "\n"; } if ($message != "") { $allowed_tags = array( 'br' => array(), 'em' => array(), 'strong' => array(), ); if (($this->f->strlen($message) >= 6) && ($this->f->substr($this->f->strtolower($message), 0, 6) == 'error:')) { $cssClasses = 'notice notice-error'; } else { $cssClasses = 'notice notice-success'; } echo $this->fillTpl('adminHeaderMessageNotice.html', array( 'cssClasses' => $cssClasses, 'message' => (string)wp_kses($message, $allowed_tags), )) . "\n"; } if (class_exists('ABJ_404_Solution_RegexAutoPromote')) { $regexNotice = ABJ_404_Solution_RegexAutoPromote::readNotice(); if (is_array($regexNotice) && $regexNotice['redirect_id'] > 0) { $this->renderRegexAutoPromoteNotice($regexNotice); } } $isSimpleMode = abj_service('settings_mode_preference')->getMode() === 'simple'; $tabs = array( array('abj404_redirects', __('Page Redirects', '404-solution')), array('abj404_captured', __('Captured 404s', '404-solution')), ); if (!$isSimpleMode) { $tabs[] = array('abj404_logs', __('Logs', '404-solution')); $tabs[] = array('abj404_stats', __('Stats', '404-solution')); } $tabs[] = array('abj404_tools', __('Tools', '404-solution')); $tabs[] = array('abj404_options', __('Options', '404-solution')); $itemTpl = ABJ_404_Solution_FileSystemService::readFileContents(dirname(__DIR__) . '/html/adminHeaderTab.html'); $tabsHtml = ''; foreach ($tabs as $pair) { list($subKey, $label) = $pair; $isActive = ($sub == $subKey); $row = $itemTpl; $row = str_replace('{url}', esc_url('?page=' . ABJ404_PP . '&subpage=' . $subKey), $row); $row = str_replace('{activeClass}', $isActive ? ' nav-tab-active active' : '', $row); $row = str_replace('{ariaSelected}', $isActive ? ' aria-selected="true"' : '', $row); $row = str_replace('{label}', esc_html($label), $row); $tabsHtml .= $row; } $outer = ABJ_404_Solution_FileSystemService::readFileContents(dirname(__DIR__) . '/html/adminHeaderTabs.html'); echo str_replace('{tabs}', $tabsHtml, $outer); } /** * @param array{redirect_id: int, original_url: string, new_url: string, url_rewritten: bool, created_at: int} $notice * @return void */ public function renderRegexAutoPromoteNotice(array $notice): void { $redirectId = (int)$notice['redirect_id']; $originalUrl = (string)$notice['original_url']; $newUrl = (string)$notice['new_url']; $urlRewritten = !empty($notice['url_rewritten']); $editUrl = admin_url('admin.php?page=' . ABJ404_PP . '&subpage=abj404_edit&id=' . $redirectId); $undoBase = admin_url('admin.php?page=' . ABJ404_PP . '&subpage=abj404_redirects&action=undoRegexAutoPromote'); $undoUrl = wp_nonce_url($undoBase, 'abj404undoRegexAutoPromote'); if ($urlRewritten) { $message = sprintf( __('Detected as a regex pattern. Stored "%1$s" as "%2$s".', '404-solution'), $originalUrl, $newUrl ); } else { $message = sprintf( __('Detected as a regex pattern. Stored "%s" with Regex status.', '404-solution'), $originalUrl ); } echo $this->fillTpl('regexAutoPromoteNotice.html', array( 'label' => esc_html__('404 Solution:', '404-solution'), 'message' => esc_html($message), 'editUrl' => esc_url($editUrl), 'editLabel' => esc_html__('Edit', '404-solution'), 'undoUrl' => esc_url($undoUrl), 'confirm' => esc_js(__('Undo regex auto-promotion and restore Manual status?', '404-solution')), 'undoLabel' => esc_html__('Undo', '404-solution'), )) . "\n"; } /** * @param string|int $id * @param mixed $content */ function echoPostBox($id, string $title, $content): void { echo $this->fillTpl('postBox.html', array( 'id' => esc_attr((string)$id), 'title' => esc_html($title), 'content' => (string)$content, )); } function echoOptionsSection(ABJ_404_Solution_OptionsSectionView $section): void { $expandedClass = $section->initiallyVisible ? ' expanded' : ''; $badgeHtml = ''; if ($section->badge) { $badgeHtml = $this->fillTpl('optionsSectionBadge.html', array( 'badge' => esc_html($section->badge), )); } echo $this->fillTpl('optionsSection.html', array( 'expandedClass' => esc_attr($expandedClass), 'sectionId' => esc_attr($section->sectionId), 'postboxId' => esc_attr($section->postboxId), 'ariaExpanded' => $section->initiallyVisible ? 'true' : 'false', 'icon' => (string)$section->icon, 'title' => esc_html($section->title), 'badge' => $badgeHtml, 'content' => (string)$section->content, )); } function getCardIcon(string $iconName): string { $icons = array( 'lightning' => '', 'gear' => '', 'filter' => '', 'document' => '', 'sliders' => '', 'lightbulb' => '', 'chart' => '', 'warning' => '', 'clock' => '', 'download' => '', 'upload' => '', 'trash' => '', 'database' => '', 'cog' => '' ); return isset($icons[$iconName]) ? $icons[$iconName] : ''; } function echoStickySaveBar(): void { $version = ABJ404_VERSION; $restoreNonce = wp_create_nonce('abj404_restore_defaults'); $versionLabel = esc_html(sprintf(__('Plugin v%s', '404-solution'), $version)); echo $this->fillTpl('stickySaveBar.html', array( 'versionLabel' => $versionLabel, 'restoreNonce' => esc_attr($restoreNonce), 'restoreLabel' => esc_html__('Restore Defaults', '404-solution'), 'saveLabel' => esc_attr__('Save Settings', '404-solution'), )); $this->echoRestoreDefaultsModal(); } function echoRestoreDefaultsModal(): void { echo "\n" . $this->fillTpl('restoreDefaultsModal.html', array( 'title' => esc_html__('Restore Default Settings?', '404-solution'), 'closeLabel' => esc_attr__('Close', '404-solution'), 'body' => esc_html__('This will reset all plugin settings to their default values. This cannot be undone. Your redirect rules and 404 logs will not be affected.', '404-solution'), 'cancelLabel' => esc_html__('Cancel', '404-solution'), 'confirmLabel' => esc_html__('Restore Defaults', '404-solution'), )) . "\n "; } function echoToastNotification(): void { echo $this->fillTpl('toastNotification.html', array( 'icon' => '✓', 'message' => esc_html__('Settings saved successfully!', '404-solution'), )); } function echoExpandCollapseButton(bool $showSuggestions = true): void { echo "\n" . $this->fillTpl('expandCollapseButton.html', array( 'expandAllLabel' => esc_html__('Expand All', '404-solution'), 'saveLabel' => esc_attr__('Save Settings', '404-solution'), )) . "\n "; } function echoSettingsModeToggle(string $currentMode): void { $simpleActive = ($currentMode === 'simple') ? 'active' : ''; $advancedActive = ($currentMode === 'advanced') ? 'active' : ''; $simplePressedState = ($currentMode === 'simple') ? 'true' : 'false'; $advancedPressedState = ($currentMode === 'advanced') ? 'true' : 'false'; if ($currentMode === 'simple') { $modeDescription = __('Simple Mode shows essential options only. Switch to Advanced Mode for full configuration.', '404-solution'); } else { $modeDescription = __('Advanced Mode shows all options. Switch to Simple Mode for a streamlined view.', '404-solution'); } $html = ABJ_404_Solution_FileSystemService::readFileContents(dirname(__DIR__) . "/html/settingsModeToggle.html"); $html = $this->f->str_replace('{nonce}', wp_create_nonce('abj404_mode_toggle'), $html); $html = $this->f->str_replace('{simpleActive}', $simpleActive, $html); $html = $this->f->str_replace('{advancedActive}', $advancedActive, $html); $html = $this->f->str_replace('{simplePressedState}', $simplePressedState, $html); $html = $this->f->str_replace('{advancedPressedState}', $advancedPressedState, $html); $html = $this->f->str_replace('{Simple Mode}', __('Simple Mode', '404-solution'), $html); $html = $this->f->str_replace('{Advanced Mode}', __('Advanced Mode', '404-solution'), $html); $html = $this->f->str_replace('{mode_description}', $modeDescription, $html); echo $html; } function echoInlineModeToggle(): void { $currentMode = abj_service('settings_mode_preference')->getMode(); $simpleActive = ($currentMode === 'simple') ? 'active' : ''; $advancedActive = ($currentMode === 'advanced') ? 'active' : ''; $simplePressedState = ($currentMode === 'simple') ? 'true' : 'false'; $advancedPressedState = ($currentMode === 'advanced') ? 'true' : 'false'; echo $this->fillTpl('inlineModeToggle.html', array( 'nonce' => esc_attr(wp_create_nonce('abj404_mode_toggle')), 'simpleActive' => esc_attr($simpleActive), 'advancedActive' => esc_attr($advancedActive), 'simplePressedState' => esc_attr($simplePressedState), 'advancedPressedState' => esc_attr($advancedPressedState), 'simpleLabel' => esc_html__('Simple', '404-solution'), 'advancedLabel' => esc_html__('Advanced', '404-solution'), )); } }