";
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 '
' . wp_kses($message, $allowed_tags) . "
\n";
}
echo '
';
// Page Redirects tab
$class = ($sub == 'abj404_redirects') ? "active" : "";
echo '';
echo ' ';
echo '' . esc_html__('Page Redirects', '404-solution') . ' ';
echo ' ';
// Captured 404 URLs tab
$class = ($sub == 'abj404_captured') ? "active" : "";
echo '';
echo ' ';
echo '' . esc_html__('Captured 404s', '404-solution') . ' ';
echo ' ';
// Logs tab
$class = ($sub == 'abj404_logs') ? "active" : "";
echo '';
echo ' ';
echo '' . esc_html__('Logs', '404-solution') . ' ';
echo ' ';
// Stats tab
$class = ($sub == 'abj404_stats') ? "active" : "";
echo '';
echo ' ';
echo '' . esc_html__('Stats', '404-solution') . ' ';
echo ' ';
// Tools tab
$class = ($sub == 'abj404_tools') ? "active" : "";
echo '';
echo ' ';
echo '' . esc_html__('Tools', '404-solution') . ' ';
echo ' ';
// Options tab
$class = ($sub == "abj404_options") ? "active" : "";
echo '';
echo ' ';
echo '' . esc_html__('Options', '404-solution') . ' ';
echo ' ';
// Plugin branding - right side of tabs
echo '' . esc_html(PLUGIN_NAME) . ' ';
echo ' ';
}
/** This outputs a box with a title and some content in it.
* It's used on the Stats, Options and Tools page (for example).
* @param int|string $id
* @param string $title
* @param string $content
* @return void
*/
function echoPostBox($id, $title, $content) {
echo "
";
echo "
" . esc_html($title) . " ";
echo "
" . $content /* Can't escape here, as contains forms */ . "
";
echo "
";
}
/**
* Echo an accordion section using card-based layout
* @param string $sectionId The section identifier
* @param string $postboxId The ID for the postbox
* @param string $title The title of the section
* @param string $content The content to display
* @param bool $initiallyVisible Whether the card starts expanded (default: false)
* @param string $icon The SVG icon for the card header (optional)
* @param string $badge Optional info badge text
* @return void
*/
function echoOptionsSection($sectionId, $postboxId, $title, $content, $initiallyVisible = false, $icon = '', $badge = '') {
$expandedClass = $initiallyVisible ? ' expanded' : '';
echo "
";
echo "";
echo "
";
echo $content; /* Can't escape here, as contains forms */
echo "
";
echo "
";
}
/**
* Get SVG icon for a section
* @param string $iconName The icon name
* @return string The SVG icon markup
*/
function getCardIcon($iconName) {
$icons = array(
'lightning' => '
',
'gear' => '
',
'filter' => '
',
'document' => '
',
'sliders' => '
',
'lightbulb' => '
',
// Stats page icons
'chart' => '
',
'warning' => '
',
'clock' => '
',
// Tools page icons
'download' => '
',
'upload' => '
',
'trash' => '
',
'database' => '
',
'cog' => '
'
);
return isset($icons[$iconName]) ? $icons[$iconName] : '';
}
/**
* Echo the sticky save bar
* @return void
*/
function echoStickySaveBar() {
$version = ABJ404_VERSION;
echo '
';
echo '
';
/* translators: %s: plugin version number */
echo esc_html(sprintf(__('Plugin v%s', '404-solution'), $version));
echo '
';
echo '
';
echo ' ';
echo '
';
echo '
';
}
/**
* Echo the success toast notification container
* @return void
*/
function echoToastNotification() {
echo '
';
echo '✓ ';
echo '' . esc_html__('Settings saved successfully!', '404-solution') . ' ';
echo '
';
}
/**
* Echo the expand/collapse all button and save button
* @param bool $showSuggestions Not used (kept for compatibility)
* @return void
*/
function echoExpandCollapseButton($showSuggestions = true) {
?>
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;
}
/**
* Echo an inline (compact) mode toggle for the header row.
* This is a smaller version without the description text.
* @return void
*/
function echoInlineModeToggle() {
$currentMode = $this->logic->getSettingsMode();
$simpleActive = ($currentMode === 'simple') ? 'active' : '';
$advancedActive = ($currentMode === 'advanced') ? 'active' : '';
$simplePressedState = ($currentMode === 'simple') ? 'true' : 'false';
$advancedPressedState = ($currentMode === 'advanced') ? 'true' : 'false';
echo '
';
echo '
';
echo '';
echo '' . esc_html__('Simple', '404-solution') . ' ';
echo ' ';
echo '';
echo '' . esc_html__('Advanced', '404-solution') . ' ';
echo ' ';
echo '
';
echo '
';
}
/**
* Echo the Simple Mode options page.
* @param array
$options The plugin options
* @return void
*/
function echoSimpleModeOptions($options) {
// Build behavior tiles HTML (replaces old dropdown)
$behaviorTilesHtml = $this->getBehaviorTilesHTML($options);
// Build selected states for checkboxes and dropdowns
$selectedAutoRedirects = $this->getCheckedAttr($options, 'auto_redirects');
$selectedCapture404 = $this->getCheckedAttr($options, 'capture_404');
$selectedDefaultRedirect301 = ($options['default_redirect'] == '301') ? 'selected' : '';
$selectedDefaultRedirect302 = ($options['default_redirect'] == '302') ? 'selected' : '';
$selectedDefaultRedirect307 = ($options['default_redirect'] == '307') ? 'selected' : '';
$selectedDefaultRedirect308 = ($options['default_redirect'] == '308') ? 'selected' : '';
// Theme selections
$selectedThemeDefault = ($options['admin_theme'] == 'default') ? 'selected' : '';
$selectedThemeCalm = ($options['admin_theme'] == 'calm') ? 'selected' : '';
$selectedThemeMono = ($options['admin_theme'] == 'mono') ? 'selected' : '';
$selectedThemeNeon = ($options['admin_theme'] == 'neon') ? 'selected' : '';
$selectedThemeObsidian = ($options['admin_theme'] == 'obsidian') ? 'selected' : '';
// Notification frequency selections
$notifyFrequency = isset($options['admin_notification_frequency']) ? (string)(is_scalar($options['admin_notification_frequency']) ? $options['admin_notification_frequency'] : 'instant') : 'instant';
$selectedNotifyInstant = ($notifyFrequency === 'instant') ? 'selected' : '';
$selectedNotifyDaily = ($notifyFrequency === 'daily') ? 'selected' : '';
$selectedNotifyWeekly = ($notifyFrequency === 'weekly') ? 'selected' : '';
// Read and build the simple options template
$html = ABJ_404_Solution_Functions::readFileContents(__DIR__ . "/html/adminOptionsSimple.html");
// Replace dest404page tiles
$html = $this->f->str_replace('{behaviorTiles}', $behaviorTilesHtml, $html);
// Replace checkbox states
$html = $this->f->str_replace('{selectedAutoRedirects}', $selectedAutoRedirects, $html);
$html = $this->f->str_replace('{selectedCapture404}', $selectedCapture404, $html);
$html = $this->f->str_replace('{selectedDefaultRedirect301}', $selectedDefaultRedirect301, $html);
$html = $this->f->str_replace('{selectedDefaultRedirect302}', $selectedDefaultRedirect302, $html);
$html = $this->f->str_replace('{selectedDefaultRedirect307}', $selectedDefaultRedirect307, $html);
$html = $this->f->str_replace('{selectedDefaultRedirect308}', $selectedDefaultRedirect308, $html);
// Replace values
$html = $this->f->str_replace('{capture_deletion}', esc_attr($this->optStr($options, 'capture_deletion')), $html);
$html = $this->f->str_replace('{admin_notification}', esc_attr($this->optStr($options, 'admin_notification')), $html);
$html = $this->f->str_replace('{maximum_log_disk_usage}', esc_attr($this->optStr($options, 'maximum_log_disk_usage')), $html);
// Theme selections
$html = $this->f->str_replace('{selectedThemeDefault}', $selectedThemeDefault, $html);
$html = $this->f->str_replace('{selectedThemeCalm}', $selectedThemeCalm, $html);
$html = $this->f->str_replace('{selectedThemeMono}', $selectedThemeMono, $html);
$html = $this->f->str_replace('{selectedThemeNeon}', $selectedThemeNeon, $html);
$html = $this->f->str_replace('{selectedThemeObsidian}', $selectedThemeObsidian, $html);
$html = $this->f->str_replace('{theme_default}', __('Default (Follows WordPress)', '404-solution'), $html);
// Translate labels
$html = $this->f->str_replace('{Core Settings}', __('Core Settings', '404-solution'), $html);
$html = $this->f->str_replace('{404 Capture}', __('404 Capture', '404-solution'), $html);
$html = $this->f->str_replace('{Maintenance}', __('Maintenance', '404-solution'), $html);
$html = $this->f->str_replace('{Default 404 destination}', __('Default 404 destination', '404-solution'), $html);
$html = $this->f->str_replace('{Where to send visitors when a 404 error occurs}', __('Where to send visitors when a 404 error occurs', '404-solution'), $html);
$html = $this->f->str_replace('{Create automatic redirects}', __('Create automatic redirects', '404-solution'), $html);
$html = $this->f->str_replace('{Automatically redirect 404s to similar pages when a good match is found}', __('Automatically redirect 404s to similar pages when a good match is found', '404-solution'), $html);
$html = $this->f->str_replace('{Redirect type}', __('Redirect type', '404-solution'), $html);
$html = $this->f->str_replace('{Permanent 301}', __('Permanent 301', '404-solution'), $html);
$html = $this->f->str_replace('{Temporary 302}', __('Temporary 302', '404-solution'), $html);
$html = $this->f->str_replace('{301 for SEO, 302 for temporary changes}', __('301 for SEO, 302 for temporary changes', '404-solution'), $html);
$html = $this->f->str_replace('{Collect incoming 404 URLs}', __('Collect incoming 404 URLs', '404-solution'), $html);
$html = $this->f->str_replace('{Log 404 errors so you can review and fix them}', __('Log 404 errors so you can review and fix them', '404-solution'), $html);
$html = $this->f->str_replace('{Delete captured URLs after}', __('Delete captured URLs after', '404-solution'), $html);
$html = $this->f->str_replace('{days}', __('days', '404-solution'), $html);
$html = $this->f->str_replace('{Auto-remove old 404 records (0 to keep forever)}', __('Auto-remove old 404 records (0 to keep forever)', '404-solution'), $html);
$html = $this->f->str_replace('{Notify me when captured URLs exceed}', __('Notify me when captured URLs exceed', '404-solution'), $html);
$html = $this->f->str_replace('{URLs}', __('URLs', '404-solution'), $html);
$html = $this->f->str_replace('{Show admin notice when 404 count gets high (0 to disable)}', __('Show admin notice when 404 count gets high (0 to disable)', '404-solution'), $html);
$html = $this->f->str_replace('{Maximum log storage}', __('Maximum log storage', '404-solution'), $html);
$html = $this->f->str_replace('{Oldest logs are deleted when this limit is reached}', __('Oldest logs are deleted when this limit is reached', '404-solution'), $html);
$html = $this->f->str_replace('{Admin theme}', __('Admin theme', '404-solution'), $html);
$html = $this->f->str_replace('{Calm Ops (Light)}', __('Calm Ops (Light)', '404-solution'), $html);
$html = $this->f->str_replace('{Monochrome Minimal (Light)}', __('Monochrome Minimal (Light)', '404-solution'), $html);
$html = $this->f->str_replace('{Neon Slate (Dark)}', __('Neon Slate (Dark)', '404-solution'), $html);
$html = $this->f->str_replace('{Obsidian Blue (Dark)}', __('Obsidian Blue (Dark)', '404-solution'), $html);
$html = $this->f->str_replace('{Save Settings}', __('Save Settings', '404-solution'), $html);
$html = $this->f->str_replace('{Need more control?}', __('Need more control?', '404-solution'), $html);
$html = $this->f->str_replace('{Switch to Advanced Mode}', __('Switch to Advanced Mode', '404-solution'), $html);
$html = $this->f->str_replace('{for 30+ additional options.}', __('for 30+ additional options.', '404-solution'), $html);
// Frequency dropdown selections and labels
$html = $this->f->str_replace('{selectedNotifyInstant}', $selectedNotifyInstant, $html);
$html = $this->f->str_replace('{selectedNotifyDaily}', $selectedNotifyDaily, $html);
$html = $this->f->str_replace('{selectedNotifyWeekly}', $selectedNotifyWeekly, $html);
$html = $this->f->str_replace('{Email notification frequency}', __('Email notification frequency', '404-solution'), $html);
$html = $this->f->str_replace('{Instant (when threshold exceeded)}', __('Instant (when threshold exceeded)', '404-solution'), $html);
$html = $this->f->str_replace('{Daily digest}', __('Daily digest', '404-solution'), $html);
$html = $this->f->str_replace('{Weekly digest}', __('Weekly digest', '404-solution'), $html);
$html = $this->f->str_replace('{Choose how often to receive email notifications about captured 404s.}', __('Choose how often to receive email notifications about captured 404s.', '404-solution'), $html);
// Also handle the Temporary 307/308 options (present in simple mode too)
$html = $this->f->str_replace('{Temporary 307 (preserve method)}', __('Temporary 307 (preserve method)', '404-solution'), $html);
$html = $this->f->str_replace('{Permanent 308 (preserve method)}', __('Permanent 308 (preserve method)', '404-solution'), $html);
echo $html;
}
}