| 1 |
<?php |
| 2 |
|
| 3 |
if (!defined('ABSPATH')) { |
| 4 |
exit; |
| 5 |
} |
| 6 |
|
| 7 |
/** |
| 8 |
* Presents advanced and general settings section templates. |
| 9 |
*/ |
| 10 |
class ABJ_404_Solution_View_SettingsSections extends ABJ_404_Solution_ViewComponent { |
| 11 |
|
| 12 |
/** @param array<string,string> $vars */ |
| 13 |
private function fillSettingsTemplate(string $templateName, array $vars): string { |
| 14 |
$html = ABJ_404_Solution_FileSystemService::readFileContents(dirname(__DIR__) . '/html/' . $templateName); |
| 15 |
foreach ($vars as $key => $value) { |
| 16 |
$html = $this->f->str_replace('{' . $key . '}', $value, $html); |
| 17 |
} |
| 18 |
return (string)$html; |
| 19 |
} |
| 20 |
|
| 21 |
/** @param array<string, mixed> $options */ |
| 22 |
function getAdminOptionsPageAutoRedirects(array $options): string { |
| 23 |
$options = $this->optionsPresenter->normalizeOptionsForView($options); |
| 24 |
|
| 25 |
$spaces = esc_html(" "); |
| 26 |
$content = ABJ_404_Solution_FileSystemService::readFileContents(dirname(__DIR__) . "/html/adminOptionsDefault404Destination.html"); |
| 27 |
$content = $this->f->str_replace( |
| 28 |
array('{default_404_destination_label}', '{behavior_tiles_html}'), |
| 29 |
array(esc_html__('Default 404 destination', '404-solution'), $this->optionsPresenter->getBehaviorTilesHTML($options)), |
| 30 |
$content |
| 31 |
); |
| 32 |
|
| 33 |
$selectedAutoRedirects = $this->optionsPresenter->getCheckedAttr($options, 'auto_redirects'); |
| 34 |
$selectedAutoSlugs = $this->optionsPresenter->getCheckedAttr($options, 'auto_slugs'); |
| 35 |
$selectedAutoCats = $this->optionsPresenter->getCheckedAttr($options, 'auto_cats'); |
| 36 |
$selectedAutoTags = $this->optionsPresenter->getCheckedAttr($options, 'auto_tags'); |
| 37 |
$selectedAutoTrashRedirect = $this->optionsPresenter->getCheckedAttr($options, 'auto_trash_redirect'); |
| 38 |
|
| 39 |
$html = ABJ_404_Solution_FileSystemService::readFileContents(dirname(__DIR__) . "/html/adminOptionsAutoRedirects.html"); |
| 40 |
$html = $this->f->str_replace('{selectedAutoRedirects}', $selectedAutoRedirects, $html); |
| 41 |
$html = $this->f->str_replace('{selectedAutoSlugs}', $selectedAutoSlugs, $html); |
| 42 |
$html = $this->f->str_replace('{selectedAutoCats}', $selectedAutoCats, $html); |
| 43 |
$html = $this->f->str_replace('{selectedAutoTags}', $selectedAutoTags, $html); |
| 44 |
$html = $this->f->str_replace('{selectedAutoTrashRedirect}', $selectedAutoTrashRedirect, $html); |
| 45 |
$html = $this->f->str_replace('{auto_deletion}', esc_attr($this->optionsPresenter->optStr($options, 'auto_deletion')), $html); |
| 46 |
$html = $this->f->str_replace('{auto_302_expiration_days}', esc_attr($this->optionsPresenter->optStr($options, 'auto_302_expiration_days')), $html); |
| 47 |
$html = $this->f->str_replace('{spaces}', $spaces, $html); |
| 48 |
$html = $this->f->doNormalReplacements($html); |
| 49 |
$content .= $html; |
| 50 |
|
| 51 |
return $content; |
| 52 |
} |
| 53 |
|
| 54 |
/** @param array<string, mixed> $options */ |
| 55 |
function getAdminOptionsPageAdvancedContent(array $options): string { |
| 56 |
$options = $this->optionsPresenter->normalizeOptionsForView($options); |
| 57 |
$allPostTypesTemp = $this->viewReadService->getAllPostTypes(); |
| 58 |
$allPostTypes = esc_html(implode(', ', $allPostTypesTemp)); |
| 59 |
|
| 60 |
$html = ABJ_404_Solution_FileSystemService::readFileContents(dirname(__DIR__) . "/html/settingsAdvancedContent.html"); |
| 61 |
|
| 62 |
$html = $this->f->str_replace('{recognized_post_types}', |
| 63 |
str_replace('\\n', "\n", wp_kses_post($this->optionsPresenter->optStr($options, 'recognized_post_types'))), $html); |
| 64 |
$html = $this->f->str_replace('{all_post_types}', $allPostTypes, $html); |
| 65 |
$html = $this->f->str_replace('{recognized_categories}', |
| 66 |
str_replace('\\n', "\n", wp_kses_post($this->optionsPresenter->optStr($options, 'recognized_categories'))), $html); |
| 67 |
$html = $this->f->str_replace('{folders_files_ignore}', |
| 68 |
str_replace('\\n', "\n", wp_kses_post($this->optionsPresenter->optStr($options, 'folders_files_ignore'))), $html); |
| 69 |
$html = $this->f->str_replace('{suggest_regex_exclusions}', |
| 70 |
str_replace('\\n', "\n", esc_textarea($this->optionsPresenter->optStr($options, 'suggest_regex_exclusions'))), $html); |
| 71 |
|
| 72 |
$html = $this->f->str_replace('{add-exclude-page-data-url}', |
| 73 |
"admin-ajax.php?action=echoRedirectToPages&includeDefault404Page=false&includeSpecial=false&nonce=" . wp_create_nonce('abj404_ajax'), $html); |
| 74 |
$html = $this->f->str_replace('{TOOLTIP_POPUP_EXPLANATION_EMPTY}', |
| 75 |
__('(Type a page name)', '404-solution'), $html); |
| 76 |
$html = $this->f->str_replace('{TOOLTIP_POPUP_EXPLANATION_PAGE}', |
| 77 |
__('(A page has been selected.)', '404-solution'), $html); |
| 78 |
$html = $this->f->str_replace('{TOOLTIP_POPUP_EXPLANATION_CUSTOM_STRING}', |
| 79 |
__('(A custom string has been entered.)', '404-solution'), $html); |
| 80 |
$html = $this->f->str_replace('{TOOLTIP_POPUP_EXPLANATION_URL}', |
| 81 |
__('(An external URL will be used.)', '404-solution'), $html); |
| 82 |
$html = $this->f->str_replace('{loaded-excluded-pages}', |
| 83 |
urlencode($this->optionsPresenter->optStr($options, 'excludePages[]')), $html); |
| 84 |
$html = $this->f->doNormalReplacements($html); |
| 85 |
|
| 86 |
return $html; |
| 87 |
} |
| 88 |
|
| 89 |
/** @param array<string, mixed> $options */ |
| 90 |
function getAdminOptionsPageAdvancedLogging(array $options): string { |
| 91 |
$options = $this->optionsPresenter->normalizeOptionsForView($options); |
| 92 |
$selectedLogRawIPs = $this->optionsPresenter->getCheckedAttr($options, 'log_raw_ips'); |
| 93 |
$selectedDebugLogging = $this->optionsPresenter->getCheckedAttr($options, 'debug_mode'); |
| 94 |
|
| 95 |
$debugExplanation = __('<a>View</a> the debug file.', '404-solution'); |
| 96 |
$debugLogLink = '?page=' . ABJ404_PP . '&subpage=abj404_debugfile'; |
| 97 |
$debugExplanation = $this->f->str_replace('<a>', '<a href="' . $debugLogLink . '" target="_blank" >', $debugExplanation); |
| 98 |
|
| 99 |
$kbFileSize = $this->logger->getDebugFileSize() / 1024; |
| 100 |
$kbFileSizePretty = number_format($kbFileSize, 2, ".", ","); |
| 101 |
$mbFileSize = $this->logger->getDebugFileSize() / 1024 / 1000; |
| 102 |
$mbFileSizePretty = number_format($mbFileSize, 2, ".", ","); |
| 103 |
$debugFileSize = sprintf(__('Debug file size: %1$s KB (%2$s MB).', '404-solution'), |
| 104 |
$kbFileSizePretty, $mbFileSizePretty); |
| 105 |
|
| 106 |
$html = ABJ_404_Solution_FileSystemService::readFileContents(dirname(__DIR__) . "/html/settingsAdvancedLogging.html"); |
| 107 |
$html = $this->f->str_replace('checked="log_raw_ips"', $selectedLogRawIPs, $html); |
| 108 |
$html = $this->f->str_replace('checked="debug_mode"', $selectedDebugLogging, $html); |
| 109 |
$html = $this->f->str_replace('{<a>View</a> the debug file.}', $debugExplanation, $html); |
| 110 |
$html = $this->f->str_replace('{Debug file size: %s KB.}', $debugFileSize, $html); |
| 111 |
$html = $this->f->str_replace('{ignore_dontprocess}', |
| 112 |
str_replace('\\n', "\n", wp_kses_post($this->optionsPresenter->optStr($options, 'ignore_dontprocess'))), $html); |
| 113 |
$html = $this->f->str_replace('{ignore_doprocess}', |
| 114 |
str_replace('\\n', "\n", wp_kses_post($this->optionsPresenter->optStr($options, 'ignore_doprocess'))), $html); |
| 115 |
$html = $this->f->doNormalReplacements($html); |
| 116 |
|
| 117 |
return $html; |
| 118 |
} |
| 119 |
|
| 120 |
/** @param array<string, mixed> $options */ |
| 121 |
function getAdminOptionsPageAdvancedSystem(array $options): string { |
| 122 |
$options = $this->optionsPresenter->normalizeOptionsForView($options); |
| 123 |
$selectedRedirectAllRequests = $this->optionsPresenter->getCheckedAttr($options, 'redirect_all_requests'); |
| 124 |
|
| 125 |
$hideRedirectAllRequests = "false"; |
| 126 |
if (array_key_exists('disallow-redirect-all-requests', $options) |
| 127 |
&& $options['disallow-redirect-all-requests'] == '1') { |
| 128 |
$hideRedirectAllRequests = "true"; |
| 129 |
} |
| 130 |
|
| 131 |
$html = ABJ_404_Solution_FileSystemService::readFileContents(dirname(__DIR__) . "/html/settingsAdvancedSystem.html"); |
| 132 |
$html = $this->f->str_replace('{DATABASE_VERSION}', esc_html($this->optionsPresenter->optStr($options, 'DB_VERSION')), $html); |
| 133 |
$html = $this->f->str_replace('checked="redirect_all_requests"', $selectedRedirectAllRequests, $html); |
| 134 |
$html = $this->f->str_replace('{disallow-redirect-all-requests}', $hideRedirectAllRequests, $html); |
| 135 |
$html = $this->f->str_replace('{OPTION_MIN_AUTO_SCORE}', esc_attr($this->optionsPresenter->optStr($options, 'auto_score')), $html); |
| 136 |
$html = $this->f->str_replace('{OPTION_AUTO_SCORE_TITLE}', esc_attr($this->optionsPresenter->optStr($options, 'auto_score_title')), $html); |
| 137 |
$html = $this->f->str_replace('{OPTION_AUTO_SCORE_CATEGORY_TAG}', esc_attr($this->optionsPresenter->optStr($options, 'auto_score_category_tag')), $html); |
| 138 |
$html = $this->f->str_replace('{OPTION_AUTO_SCORE_CONTENT}', esc_attr($this->optionsPresenter->optStr($options, 'auto_score_content')), $html); |
| 139 |
$html = $this->f->str_replace('{OPTION_TEMPLATE_REDIRECT_PRIORITY}', esc_attr($this->optionsPresenter->optStr($options, 'template_redirect_priority')), $html); |
| 140 |
$html = $this->f->str_replace('{days_wait_before_major_update}', esc_attr($this->optionsPresenter->optStr($options, 'days_wait_before_major_update')), $html); |
| 141 |
|
| 142 |
$pluginAdminUsersRaw2 = $options['plugin_admin_users']; |
| 143 |
if (is_array($pluginAdminUsersRaw2)) { |
| 144 |
$pluginAdminUsers = implode("\n", $pluginAdminUsersRaw2); |
| 145 |
} else { |
| 146 |
$pluginAdminUsers = is_string($pluginAdminUsersRaw2) ? $pluginAdminUsersRaw2 : ''; |
| 147 |
} |
| 148 |
$pluginAdminUsers = str_replace('\\n', "\n", wp_kses_post($pluginAdminUsers)); |
| 149 |
$html = $this->f->str_replace('{plugin_admin_users}', wp_kses_post($pluginAdminUsers), $html); |
| 150 |
$html = $this->f->doNormalReplacements($html); |
| 151 |
|
| 152 |
return $html; |
| 153 |
} |
| 154 |
|
| 155 |
/** @param array<string, mixed> $options */ |
| 156 |
function getAdminOptionsPageGeneralSettings(array $options): string { |
| 157 |
$options = $this->optionsPresenter->normalizeOptionsForView($options); |
| 158 |
|
| 159 |
$viewData = array_merge( |
| 160 |
$this->generalSettingsFieldState($options), |
| 161 |
$this->generalSettingsRuntimeDisplayData(), |
| 162 |
array( |
| 163 |
'admin_notification' => esc_attr($this->optionsPresenter->optStr($options, 'admin_notification')), |
| 164 |
'capture_deletion' => esc_attr($this->optionsPresenter->optStr($options, 'capture_deletion')), |
| 165 |
'manual_deletion' => esc_attr($this->optionsPresenter->optStr($options, 'manual_deletion')), |
| 166 |
'maximum_log_disk_usage' => esc_attr($this->optionsPresenter->optStr($options, 'maximum_log_disk_usage')), |
| 167 |
'admin_notification_email' => esc_attr($this->optionsPresenter->optStr($options, 'admin_notification_email')), |
| 168 |
'PHP_VERSION' => PHP_VERSION, |
| 169 |
) |
| 170 |
); |
| 171 |
|
| 172 |
$html = $this->fillSettingsTemplate('adminOptionsGeneral.html', $viewData); |
| 173 |
$html = $this->f->doNormalReplacements($html); |
| 174 |
|
| 175 |
return $html; |
| 176 |
} |
| 177 |
|
| 178 |
/** |
| 179 |
* Build selected and checked attributes for the general settings template. |
| 180 |
* |
| 181 |
* @param array<string, mixed> $options |
| 182 |
* @return array<string, string> |
| 183 |
*/ |
| 184 |
private function generalSettingsFieldState(array $options): array { |
| 185 |
$viewData = array( |
| 186 |
'selectedDefaultRedirect301' => ($options['default_redirect'] == '301') ? ' selected' : '', |
| 187 |
'selectedDefaultRedirect302' => ($options['default_redirect'] == '302') ? ' selected' : '', |
| 188 |
'selectedDefaultRedirect307' => ($options['default_redirect'] == '307') ? ' selected' : '', |
| 189 |
'selectedDefaultRedirect308' => ($options['default_redirect'] == '308') ? ' selected' : '', |
| 190 |
'selectedCapture404' => $this->optionsPresenter->getCheckedAttr($options, 'capture_404'), |
| 191 |
'selectedSendErrorLogs' => $this->optionsPresenter->getCheckedAttr($options, 'send_error_logs'), |
| 192 |
'selectedRemoveMatches' => $this->optionsPresenter->getCheckedAttr($options, 'remove_matches'), |
| 193 |
'selectedAutoTrashJunk' => $this->optionsPresenter->getCheckedAttr($options, 'auto_trash_junk_urls'), |
| 194 |
'selectedUnderSettings' => ($options['menuLocation'] == 'settingsLevel') ? '' : ' selected', |
| 195 |
'selecteSsettingsLevel' => ($options['menuLocation'] == 'settingsLevel') ? ' selected' : '', |
| 196 |
'theme_default' => __('Default', '404-solution'), |
| 197 |
'disableAutoDarkModeChecked' => isset($options['disable_auto_dark_mode']) && $options['disable_auto_dark_mode'] == '1' |
| 198 |
? ' checked' |
| 199 |
: '', |
| 200 |
); |
| 201 |
|
| 202 |
$adminTheme = isset($options['admin_theme']) ? $options['admin_theme'] : 'default'; |
| 203 |
foreach (array( |
| 204 |
'selectedThemeDefault' => 'default', |
| 205 |
'selectedThemeCalm' => 'calm', |
| 206 |
'selectedThemeMono' => 'mono', |
| 207 |
'selectedThemeNeon' => 'neon', |
| 208 |
'selectedThemeObsidian' => 'obsidian', |
| 209 |
) as $placeholder => $theme) { |
| 210 |
$viewData[$placeholder] = ($adminTheme == $theme) ? ' selected' : ''; |
| 211 |
} |
| 212 |
|
| 213 |
$pluginLanguage = isset($options['plugin_language_override']) ? $options['plugin_language_override'] : ''; |
| 214 |
foreach (array( |
| 215 |
'selectedLanguageDefault' => '', |
| 216 |
'selectedLanguageEnUS' => 'en_US', |
| 217 |
'selectedLanguageDeDE' => 'de_DE', |
| 218 |
'selectedLanguageEsES' => 'es_ES', |
| 219 |
'selectedLanguageFrFR' => 'fr_FR', |
| 220 |
'selectedLanguageItIT' => 'it_IT', |
| 221 |
'selectedLanguagePtBR' => 'pt_BR', |
| 222 |
'selectedLanguageNlNL' => 'nl_NL', |
| 223 |
'selectedLanguageRuRU' => 'ru_RU', |
| 224 |
'selectedLanguageJa' => 'ja', |
| 225 |
'selectedLanguageZhCN' => 'zh_CN', |
| 226 |
'selectedLanguageIdID' => 'id_ID', |
| 227 |
'selectedLanguageSvSE' => 'sv_SE', |
| 228 |
) as $placeholder => $language) { |
| 229 |
$viewData[$placeholder] = ($pluginLanguage == $language) ? ' selected' : ''; |
| 230 |
} |
| 231 |
|
| 232 |
$notifyFrequencyRaw = $options['admin_notification_frequency'] ?? 'instant'; |
| 233 |
$notifyFrequency = is_scalar($notifyFrequencyRaw) ? (string)$notifyFrequencyRaw : 'instant'; |
| 234 |
foreach (array( |
| 235 |
'selectedNotifyInstant' => 'instant', |
| 236 |
'selectedNotifyDaily' => 'daily', |
| 237 |
'selectedNotifyWeekly' => 'weekly', |
| 238 |
'selectedNotifyNever' => 'never', |
| 239 |
) as $placeholder => $frequency) { |
| 240 |
$viewData[$placeholder] = ($notifyFrequency === $frequency) ? ' selected' : ''; |
| 241 |
} |
| 242 |
|
| 243 |
return $viewData; |
| 244 |
} |
| 245 |
|
| 246 |
/** @return array<string, string> */ |
| 247 |
private function generalSettingsRuntimeDisplayData(): array { |
| 248 |
$timeToDisplay = $this->statsRepository->getEarliestLogTimestamp(); |
| 249 |
$earliestLogDate = $timeToDisplay >= 0 |
| 250 |
? date('Y/m/d', $timeToDisplay) . ' ' . date('h:i:s', $timeToDisplay) . ' ' . date('A', $timeToDisplay) |
| 251 |
: 'N/A'; |
| 252 |
$adminEmail = get_option('admin_email'); |
| 253 |
|
| 254 |
return array( |
| 255 |
'logCurrentSizeDiskUsage' => (string)round($this->viewReadService->getLogDiskUsage() / (1024 * 1000), 2), |
| 256 |
'logCurrentRowCount' => (string)$this->viewReadService->getLogsCount(0), |
| 257 |
'earliestLogDate' => $earliestLogDate, |
| 258 |
'default_wordpress_admin_email' => is_string($adminEmail) ? $adminEmail : '', |
| 259 |
); |
| 260 |
} |
| 261 |
|
| 262 |
/** @param array<string, mixed> $options */ |
| 263 |
function getAdminOptionsPageDiagnosticData(array $options): string { |
| 264 |
if (!class_exists('ABJ_404_Solution_FeedbackSiteTokenStore')) { |
| 265 |
require_once dirname(__DIR__) . '/feedback/FeedbackSiteTokenStore.php'; |
| 266 |
} |
| 267 |
if (!class_exists('ABJ_404_Solution_Ajax_PrivacyExport')) { |
| 268 |
require_once dirname(__DIR__) . '/ajax/Ajax_PrivacyExport.php'; |
| 269 |
} |
| 270 |
if (!class_exists('ABJ_404_Solution_Ajax_PrivacyDelete')) { |
| 271 |
require_once dirname(__DIR__) . '/ajax/Ajax_PrivacyDelete.php'; |
| 272 |
} |
| 273 |
|
| 274 |
$rawToken = get_option(ABJ_404_Solution_FeedbackSiteTokenStore::TOKEN_OPTION, ''); |
| 275 |
$hasToken = is_string($rawToken) && $rawToken !== ''; |
| 276 |
$exportNonce = wp_create_nonce(ABJ_404_Solution_Ajax_PrivacyExport::NONCE_ACTION); |
| 277 |
$deleteNonce = wp_create_nonce(ABJ_404_Solution_Ajax_PrivacyDelete::NONCE_ACTION); |
| 278 |
|
| 279 |
if (!$hasToken) { |
| 280 |
$body = $this->fillSettingsTemplate('viewSettingsDiagnosticDataNoToken.html', array( |
| 281 |
'emptyDescription' => esc_html__('Diagnostic reporting has never been enabled for this site, so there is nothing stored on the developer\'s server for you to download or delete.', '404-solution'), |
| 282 |
)); |
| 283 |
} else { |
| 284 |
$sendErrorLogs = $options['send_error_logs'] ?? '0'; |
| 285 |
$enabled = $sendErrorLogs === '1' || $sendErrorLogs === 1 || $sendErrorLogs === true; |
| 286 |
$state = $enabled ? esc_html__('enabled', '404-solution') : esc_html__('disabled', '404-solution'); |
| 287 |
$description = sprintf( |
| 288 |
esc_html__('This site has diagnostic reporting %s. You can download everything stored on the developer\'s server for this site, or permanently delete it.', '404-solution'), |
| 289 |
$state |
| 290 |
); |
| 291 |
$body = $this->fillSettingsTemplate('viewSettingsDiagnosticDataActions.html', array( |
| 292 |
'description' => $description, |
| 293 |
'exportNonce' => esc_attr($exportNonce), |
| 294 |
'deleteNonce' => esc_attr($deleteNonce), |
| 295 |
'downloadLabel' => esc_html__('Download my data', '404-solution'), |
| 296 |
'deleteLabel' => esc_html__('Delete my data', '404-solution'), |
| 297 |
'emptyAfterDelete' => esc_html__('Nothing currently stored.', '404-solution'), |
| 298 |
'modalTitle' => esc_html__('Delete your diagnostic data?', '404-solution'), |
| 299 |
'modalBody' => esc_html__('This permanently deletes every diagnostic report this site has ever sent. This cannot be undone. Your redirects and settings are not affected -- only diagnostic/telemetry history is removed.', '404-solution'), |
| 300 |
'cancelLabel' => esc_html__('Cancel', '404-solution'), |
| 301 |
'confirmLabel' => esc_html__('Yes, delete permanently', '404-solution'), |
| 302 |
)); |
| 303 |
} |
| 304 |
|
| 305 |
return $this->fillSettingsTemplate('viewSettingsDiagnosticDataSection.html', array( |
| 306 |
'downloadDate' => esc_attr(gmdate('Y-m-d', abj_clock()->now())), |
| 307 |
'exportNonce' => esc_attr($exportNonce), |
| 308 |
'deleteNonce' => esc_attr($deleteNonce), |
| 309 |
'hasToken' => $hasToken ? '1' : '0', |
| 310 |
'body' => $body, |
| 311 |
)); |
| 312 |
} |
| 313 |
} |
| 314 |
|