| 1 |
<?php |
| 2 |
defined('ABSPATH') or die('Unauthorized Access'); |
| 3 |
|
| 4 |
$is_pro = Phpinfo_WP_License::is_valid(); |
| 5 |
$is_unlimited = Phpinfo_WP_License::is_unlimited(); |
| 6 |
$is_free_preview = !$is_pro; |
| 7 |
|
| 8 |
// Handle branding form save before building report |
| 9 |
if (isset($_POST['phpinfowp_report_branding']) && check_admin_referer('phpinfowp_report_branding')) { |
| 10 |
Phpinfo_WP_Report::save_branding([ |
| 11 |
'enabled' => isset($_POST['branding_enabled']), |
| 12 |
'company' => $_POST['branding_company'] ?? '', |
| 13 |
'tagline' => $_POST['branding_tagline'] ?? '', |
| 14 |
'footer_note' => $_POST['branding_footer_note'] ?? '', |
| 15 |
'accent' => $_POST['branding_accent'] ?? '#777BB3', |
| 16 |
'logo_id' => (int) ($_POST['branding_logo_id'] ?? 0), |
| 17 |
'logo_url' => $_POST['branding_logo_url'] ?? '', |
| 18 |
]); |
| 19 |
echo '<div class="notice notice-success inline" style="margin:0 0 20px"><p>Report branding saved.</p></div>'; |
| 20 |
} |
| 21 |
|
| 22 |
// Media library is needed for the logo picker. Only loaded on this view. |
| 23 |
wp_enqueue_media(); |
| 24 |
|
| 25 |
$r = Phpinfo_WP_Report::build(); |
| 26 |
|
| 27 |
$b = $r['branding']; |
| 28 |
$is_unlimited = Phpinfo_WP_License::is_unlimited(); |
| 29 |
$accent = $is_unlimited && $b['enabled'] && $b['accent'] ? esc_attr($b['accent']) : '#777BB3'; |
| 30 |
$brand_name = $is_unlimited && $b['enabled'] && $b['company'] ? esc_html($b['company']) : 'phpinfo() WP'; |
| 31 |
$brand_tag = $is_unlimited && $b['enabled'] && $b['tagline'] ? esc_html($b['tagline']) : 'Server Health Audit'; |
| 32 |
?> |
| 33 |
|
| 34 |
<style>.phpinfowp-report .phpinfowp-report-brand,.phpinfowp-report .phpinfowp-report-h{color:<?php echo $accent; ?> !important}.phpinfowp-report .phpinfowp-report-cover{border-bottom-color:<?php echo $accent; ?> !important}</style> |
| 35 |
|
| 36 |
<div class="phpinfowp-pro-page"> |
| 37 |
|
| 38 |
<?php if (isset($_GET['trial_activated']) && $_GET['trial_activated'] == 1): ?> |
| 39 |
<div class="notice notice-success inline is-dismissible" style="margin:0 0 20px"> |
| 40 |
<p><strong><?php _e('Success!', 'phpinfo-wp'); ?></strong> <?php _e('Your 7-day Pro Trial is now active. All Pro features are unlocked.', 'phpinfo-wp'); ?></p> |
| 41 |
</div> |
| 42 |
<?php endif; ?> |
| 43 |
|
| 44 |
<?php if ($is_free_preview): ?> |
| 45 |
<div class="phpinfowp-price-alert-banner" style="position:relative; background:#fff3cd; border-left:4px solid #ffc107; padding:12px 40px 12px 16px; margin: 0 0 24px; border-radius: 0 4px 4px 0; font-size:13.5px; color:#664d03; display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:12px; box-shadow:0 1px 2px rgba(0,0,0,0.02);"> |
| 46 |
<button type="button" onclick="try{localStorage.setItem('phpinfowp_price_alert_dismissed','1')}catch(e){} this.closest('.phpinfowp-price-alert-banner').style.display='none';" aria-label="<?php esc_attr_e('Dismiss', 'phpinfo-wp'); ?>" style="position:absolute; top:6px; right:8px; background:none; border:none; cursor:pointer; color:#664d03; opacity:0.5; font-size:20px; line-height:1; padding:2px 4px;" onmouseover="this.style.opacity='1'" onmouseout="this.style.opacity='0.5'">×</button> |
| 47 |
<span> |
| 48 |
<strong>⏰ <?php _e('Price Increase Alert:', 'phpinfo-wp'); ?></strong> |
| 49 |
<?php _e('On August 31st, the Single Site Pro license increases from $29 to $39/year. Upgrade today to secure the current $29/year rate before the price goes up.', 'phpinfo-wp'); ?> |
| 50 |
</span> |
| 51 |
<a href="https://exeebit.com/phpinfo-wp#pricing" target="_blank" rel="noopener" style="background:#777BB3; color:#fff; padding:6px 14px; border-radius:4px; font-size:12.5px; font-weight:600; text-decoration:none; display:inline-block;"> |
| 52 |
<?php _e('Lock in $29 Now →', 'phpinfo-wp'); ?> |
| 53 |
</a> |
| 54 |
</div> |
| 55 |
<script>if(localStorage.getItem('phpinfowp_price_alert_dismissed')==='1'){document.querySelectorAll('.phpinfowp-price-alert-banner').forEach(function(e){e.style.display='none';});}</script> |
| 56 |
<?php endif; ?> |
| 57 |
|
| 58 |
<div class="phpinfowp-page-header no-print"> |
| 59 |
<div> |
| 60 |
<h1>Audit Report <span class="phpinfowp-pro-badge"><?php _e('PRO', 'phpinfo-wp'); ?></span></h1> |
| 61 |
<p class="phpinfowp-page-subtitle"><?php _e('A single-page server health report — print to PDF or share with clients', 'phpinfo-wp'); ?></p> |
| 62 |
</div> |
| 63 |
<div> |
| 64 |
<?php if ($is_free_preview): ?> |
| 65 |
<button type="button" class="button" disabled style="opacity: 0.6; cursor: not-allowed;"> |
| 66 |
<span class="dashicons dashicons-lock" style="vertical-align:middle"></span> <?php _e('White-label', 'phpinfo-wp'); ?> |
| 67 |
</button> |
| 68 |
<button type="button" class="button button-primary" disabled style="opacity: 0.6; cursor: not-allowed;"> |
| 69 |
<span class="dashicons dashicons-lock" style="vertical-align:middle"></span> <?php _e('Print / Save as PDF', 'phpinfo-wp'); ?> |
| 70 |
</button> |
| 71 |
<?php else: ?> |
| 72 |
<button type="button" class="button" onclick="document.getElementById('phpinfowp-report-branding').style.display='block';return false;"> |
| 73 |
<span class="dashicons dashicons-admin-customizer" style="vertical-align:middle"></span> <?php _e('White-label', 'phpinfo-wp'); ?> |
| 74 |
</button> |
| 75 |
<button type="button" class="button button-primary" onclick="window.print()"> |
| 76 |
<span class="dashicons dashicons-printer" style="vertical-align:middle"></span> <?php _e('Print / Save as PDF', 'phpinfo-wp'); ?> |
| 77 |
</button> |
| 78 |
<?php endif; ?> |
| 79 |
</div> |
| 80 |
</div> |
| 81 |
|
| 82 |
<!-- White-label branding form. Always hidden on initial render; the |
| 83 |
"White-label" button in the page header toggles it open. The form |
| 84 |
stays hidden after save so it doesn't crowd the report — the |
| 85 |
success notice above confirms the change was applied. --> |
| 86 |
<div id="phpinfowp-report-branding" class="phpinfowp-report-branding-form no-print" style="display:none"> |
| 87 |
<?php if (!Phpinfo_WP_License::is_unlimited()): ?> |
| 88 |
<div class="phpinfowp-upgrade-banner" style="background:#fcfaff;border:1px solid #e2d9f3;border-radius:8px;padding:24px;text-align:center;margin-bottom:12px"> |
| 89 |
<span class="dashicons dashicons-lock" style="font-size:36px;width:36px;height:36px;color:#7c3aed;margin-bottom:12px"></span> |
| 90 |
<h3 style="margin:0 0 8px;font-size:18px;color:#2c3338"><?php _e('White-Label Branding is an Unlimited Tier Feature', 'phpinfo-wp'); ?></h3> |
| 91 |
<p style="margin:0 0 16px;color:#646970;font-size:14px"><?php _e('Upload your own company logo, set a custom accent color, and hide the "phpinfo() WP" branding from client PDF reports.', 'phpinfo-wp'); ?></p> |
| 92 |
<a href="https://exeebit.com/phpinfo-wp#pricing" target="_blank" class="button button-primary button-large" style="background:#7c3aed;border-color:#7c3aed"><?php _e('Upgrade License →', 'phpinfo-wp'); ?></a> |
| 93 |
</div> |
| 94 |
<?php else: ?> |
| 95 |
<form method="post"> |
| 96 |
<?php wp_nonce_field('phpinfowp_report_branding'); ?> |
| 97 |
<input type="hidden" name="phpinfowp_report_branding" value="1"> |
| 98 |
<h3><?php _e('Report Branding', 'phpinfo-wp'); ?></h3> |
| 99 |
<p class="description"><?php _e('Customize the report cover and footer with your own brand. Toggle off to restore the default look.', 'phpinfo-wp'); ?></p> |
| 100 |
<table class="form-table"> |
| 101 |
<tr> |
| 102 |
<th><label for="branding_enabled"><?php _e('Enable white-label', 'phpinfo-wp'); ?></label></th> |
| 103 |
<td><label><input type="checkbox" id="branding_enabled" name="branding_enabled" value="1" <?php checked($b['enabled']); ?>> Use my branding instead of "phpinfo() WP"</label></td> |
| 104 |
</tr> |
| 105 |
<tr> |
| 106 |
<th><label for="branding_company"><?php _e('Company name', 'phpinfo-wp'); ?></label></th> |
| 107 |
<td><input type="text" id="branding_company" name="branding_company" class="regular-text" value="<?php echo esc_attr($b['company']); ?>" placeholder="<?php echo esc_attr__('Acme Digital Studio', 'phpinfo-wp'); ?>"></td> |
| 108 |
</tr> |
| 109 |
<tr> |
| 110 |
<th><label for="branding_tagline"><?php _e('Report title', 'phpinfo-wp'); ?></label></th> |
| 111 |
<td><input type="text" id="branding_tagline" name="branding_tagline" class="regular-text" value="<?php echo esc_attr($b['tagline']); ?>" placeholder="<?php echo esc_attr__('Quarterly Site Health Audit', 'phpinfo-wp'); ?>"></td> |
| 112 |
</tr> |
| 113 |
<tr> |
| 114 |
<th><label for="branding_footer_note"><?php _e('Footer note', 'phpinfo-wp'); ?></label></th> |
| 115 |
<td><textarea id="branding_footer_note" name="branding_footer_note" class="regular-text" rows="2" placeholder="<?php echo esc_attr__('Prepared by Acme Digital Studio · support@acme.com', 'phpinfo-wp'); ?>"><?php echo esc_textarea($b['footer_note']); ?></textarea></td> |
| 116 |
</tr> |
| 117 |
<tr> |
| 118 |
<th><label><?php _e('Company logo', 'phpinfo-wp'); ?></label></th> |
| 119 |
<td> |
| 120 |
<div class="phpinfowp-logo-picker" id="phpinfowp-logo-picker"> |
| 121 |
<div class="phpinfowp-logo-preview" id="phpinfowp-logo-preview"> |
| 122 |
<?php if (!empty($b['logo_url'])): ?> |
| 123 |
<img src="<?php echo esc_url($b['logo_url']); ?>" alt="Company logo"> |
| 124 |
<?php else: ?> |
| 125 |
<span class="phpinfowp-logo-empty"><?php _e('No logo set', 'phpinfo-wp'); ?></span> |
| 126 |
<?php endif; ?> |
| 127 |
</div> |
| 128 |
<div class="phpinfowp-logo-actions"> |
| 129 |
<button type="button" class="button" id="phpinfowp-logo-choose"> |
| 130 |
<?php echo !empty($b['logo_url']) ? 'Change logo' : 'Upload logo'; ?> |
| 131 |
</button> |
| 132 |
<button type="button" class="button button-link-delete" id="phpinfowp-logo-remove" <?php echo empty($b['logo_url']) ? 'style="display:none"' : ''; ?>> |
| 133 |
Remove |
| 134 |
</button> |
| 135 |
<p class="description" style="margin-top:6px"> |
| 136 |
PNG or SVG with a transparent background works best. Renders on the report cover at about 60×60. |
| 137 |
</p> |
| 138 |
</div> |
| 139 |
</div> |
| 140 |
<input type="hidden" id="branding_logo_id" name="branding_logo_id" value="<?php echo (int) ($b['logo_id'] ?? 0); ?>"> |
| 141 |
<input type="hidden" id="branding_logo_url" name="branding_logo_url" value="<?php echo esc_attr($b['logo_url']); ?>"> |
| 142 |
</td> |
| 143 |
</tr> |
| 144 |
<tr> |
| 145 |
<th><label for="branding_accent"><?php _e('Accent color', 'phpinfo-wp'); ?></label></th> |
| 146 |
<td><input type="color" id="branding_accent" name="branding_accent" value="<?php echo esc_attr($b['accent']); ?>"></td> |
| 147 |
</tr> |
| 148 |
</table> |
| 149 |
<p><button type="submit" class="button button-primary"><?php _e('Save branding', 'phpinfo-wp'); ?></button></p> |
| 150 |
</form> |
| 151 |
<?php endif; ?> |
| 152 |
</div> |
| 153 |
|
| 154 |
<script> |
| 155 |
/* Logo picker wiring. |
| 156 |
Previous version bailed out at script-parse time if `wp.media` wasn't |
| 157 |
defined yet — but wp_enqueue_media() prints its JS in the admin footer, |
| 158 |
so wp.media is undefined while this script is being parsed and the |
| 159 |
guard silently disabled the entire feature. Fix: always attach the |
| 160 |
click handler; check wp.media at click time (footer has loaded by then). */ |
| 161 |
(function () { |
| 162 |
var idField = document.getElementById('branding_logo_id'); |
| 163 |
var urlField = document.getElementById('branding_logo_url'); |
| 164 |
var preview = document.getElementById('phpinfowp-logo-preview'); |
| 165 |
var chooseBtn = document.getElementById('phpinfowp-logo-choose'); |
| 166 |
var removeBtn = document.getElementById('phpinfowp-logo-remove'); |
| 167 |
if (!chooseBtn || !idField || !urlField || !preview) return; |
| 168 |
var frame; |
| 169 |
|
| 170 |
function setLogo(id, url) { |
| 171 |
idField.value = id; |
| 172 |
urlField.value = url; |
| 173 |
preview.innerHTML = url |
| 174 |
? '<img src="' + url + '" alt="Company logo">' |
| 175 |
: '<span class="phpinfowp-logo-empty"><?php _e('No logo set', 'phpinfo-wp'); ?></span>'; |
| 176 |
chooseBtn.textContent = url ? 'Change logo' : 'Upload logo'; |
| 177 |
if (removeBtn) removeBtn.style.display = url ? '' : 'none'; |
| 178 |
} |
| 179 |
|
| 180 |
chooseBtn.addEventListener('click', function (e) { |
| 181 |
e.preventDefault(); |
| 182 |
if (!window.wp || !wp.media) { |
| 183 |
window.alert('The WordPress media library is still loading. Wait one second and try again.'); |
| 184 |
return; |
| 185 |
} |
| 186 |
if (frame) { frame.open(); return; } |
| 187 |
frame = wp.media({ |
| 188 |
title: 'Choose company logo', |
| 189 |
button: { text: 'Use this logo' }, |
| 190 |
library: { type: ['image'] }, |
| 191 |
multiple: false |
| 192 |
}); |
| 193 |
frame.on('select', function () { |
| 194 |
var att = frame.state().get('selection').first().toJSON(); |
| 195 |
var url = (att.sizes && att.sizes.medium && att.sizes.medium.url) || att.url; |
| 196 |
setLogo(att.id, url); |
| 197 |
}); |
| 198 |
frame.open(); |
| 199 |
}); |
| 200 |
|
| 201 |
if (removeBtn) { |
| 202 |
removeBtn.addEventListener('click', function (e) { |
| 203 |
e.preventDefault(); |
| 204 |
setLogo(0, ''); |
| 205 |
}); |
| 206 |
} |
| 207 |
}()); |
| 208 |
</script> |
| 209 |
|
| 210 |
<div class="phpinfowp-report"> |
| 211 |
|
| 212 |
<?php |
| 213 |
$overall = $r['overall']; |
| 214 |
$crit_n = count($r['criticals']); |
| 215 |
$warn_n = count($r['warnings']); |
| 216 |
|
| 217 |
// Helper to render a verdict pill inline anywhere. |
| 218 |
$verdict_pill = static function (string $v, string $text = '') { |
| 219 |
$svg_ok = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" style="width:12px;height:12px;display:inline-block;vertical-align:-1px"><path fill-rule="evenodd" d="M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z" clip-rule="evenodd"/></svg>'; |
| 220 |
$svg_warn = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" style="width:12px;height:12px;display:inline-block;vertical-align:-1px"><path fill-rule="evenodd" d="M8.485 2.495c.673-1.167 2.357-1.167 3.03 0l6.28 10.875c.673 1.167-.17 2.625-1.516 2.625H3.72c-1.347 0-2.189-1.458-1.515-2.625L8.485 2.495zM10 5a.75.75 0 01.75.75v3.5a.75.75 0 01-1.5 0v-3.5A.75.75 0 0110 5zm0 9a.75.75 0 100-1.5.75.75 0 000 1.5z" clip-rule="evenodd"/></svg>'; |
| 221 |
$svg_critical = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" style="width:12px;height:12px;display:inline-block;vertical-align:-1px"><path fill-rule="evenodd" d="M4.22 4.22a.75.75 0 011.06 0L10 8.94l4.72-4.72a.75.75 0 111.06 1.06L11.06 10l4.72 4.72a.75.75 0 11-1.06 1.06L10 11.06l-4.72 4.72a.75.75 0 01-1.06-1.06L8.94 10 4.22 5.28a.75.75 0 010-1.06z" clip-rule="evenodd"/></svg>'; |
| 222 |
|
| 223 |
$map = [ |
| 224 |
'ok' => ['ok', '#0a7d2e', '#e8f6ec', '#a7d8b3', $svg_ok], |
| 225 |
'warn' => ['warn', '#8a6500', '#fff5d6', '#e9c977', $svg_warn], |
| 226 |
'critical' => ['critical', '#8e1414', '#fbe7e8', '#ecb4b5', $svg_critical], |
| 227 |
]; |
| 228 |
[$cls, $fg, $bg, $br, $ic] = $map[$v] ?? $map['ok']; |
| 229 |
$label = $text ?: ($v === 'ok' ? 'OK' : ($v === 'warn' ? 'Warning' : 'Critical')); |
| 230 |
return sprintf( |
| 231 |
'<span class="phpinfowp-rv phpinfowp-rv-%s" style="color:%s;background:%s;border-color:%s"><span class="phpinfowp-rv-ic">%s</span>%s</span>', |
| 232 |
$cls, $fg, $bg, $br, $ic, esc_html($label) |
| 233 |
); |
| 234 |
}; |
| 235 |
|
| 236 |
// Small helpers to classify a value into a verdict. |
| 237 |
$verdict_eol = static function (array $eol) { |
| 238 |
if (($eol['status'] ?? '') === 'eol') return 'critical'; |
| 239 |
if (($eol['status'] ?? '') === 'warning' && (int) ($eol['days'] ?? 0) < 90) return 'critical'; |
| 240 |
if (($eol['status'] ?? '') === 'warning') return 'warn'; |
| 241 |
return 'ok'; |
| 242 |
}; |
| 243 |
$verdict_score = static function (?int $s) { |
| 244 |
if ($s === null) return 'ok'; |
| 245 |
if ($s < 50) return 'critical'; |
| 246 |
if ($s < 80) return 'warn'; |
| 247 |
return 'ok'; |
| 248 |
}; |
| 249 |
$verdict_hit = static function ($rate) { |
| 250 |
$rate = (float) $rate; |
| 251 |
if ($rate < 50) return 'critical'; |
| 252 |
if ($rate < 90) return 'warn'; |
| 253 |
return 'ok'; |
| 254 |
}; |
| 255 |
?> |
| 256 |
|
| 257 |
<!-- Cover --> |
| 258 |
<div class="phpinfowp-report-cover"> |
| 259 |
<?php if ($is_unlimited && $b['enabled'] && !empty($b['logo_url'])): ?> |
| 260 |
<img src="<?php echo esc_url($b['logo_url']); ?>" alt="<?php echo esc_attr($brand_name); ?> logo" |
| 261 |
class="phpinfowp-report-logo"> |
| 262 |
<?php endif; ?> |
| 263 |
<div class="phpinfowp-report-brand"><?php echo $brand_name; ?></div> |
| 264 |
<h2 class="phpinfowp-report-title"><?php echo $brand_tag; ?></h2> |
| 265 |
<div class="phpinfowp-report-site"><?php echo esc_html($r['site']); ?></div> |
| 266 |
<div class="phpinfowp-report-url"><?php echo esc_html($r['url']); ?></div> |
| 267 |
<div class="phpinfowp-report-date">Generated <?php echo esc_html(wp_date('F j, Y · H:i', $r['generated_at'])); ?></div> |
| 268 |
</div> |
| 269 |
|
| 270 |
<!-- Overall site health (one number, page-1 hero) --> |
| 271 |
<div class="phpinfowp-report-overall"> |
| 272 |
<div class="phpinfowp-report-overall-donut"> |
| 273 |
<?php echo Phpinfo_WP_Report::render_donut( |
| 274 |
$overall['score'], 180, $overall['verdict_color'], '#eef0f4', 14 |
| 275 |
); ?> |
| 276 |
<div class="phpinfowp-report-overall-num"> |
| 277 |
<div class="phpinfowp-report-overall-num-big" style="color:<?php echo esc_attr($overall['verdict_color']); ?>"><?php echo (int) $overall['score']; ?></div> |
| 278 |
<div class="phpinfowp-report-overall-num-sm">/ 100</div> |
| 279 |
</div> |
| 280 |
</div> |
| 281 |
<div class="phpinfowp-report-overall-info"> |
| 282 |
<div class="phpinfowp-report-overall-label"><?php _e('Overall Site Health', 'phpinfo-wp'); ?></div> |
| 283 |
<div class="phpinfowp-report-overall-verdict" style="color:<?php echo esc_attr($overall['verdict_color']); ?>"><?php echo esc_html($overall['verdict_label']); ?></div> |
| 284 |
<div class="phpinfowp-report-overall-grade">Grade <strong><?php echo esc_html($overall['grade']); ?></strong></div> |
| 285 |
<?php if ($crit_n || $warn_n): ?> |
| 286 |
<div class="phpinfowp-report-overall-counts"> |
| 287 |
<?php if ($crit_n): ?><span class="phpinfowp-rc phpinfowp-rc-crit"><?php echo $crit_n; ?> critical</span><?php endif; ?> |
| 288 |
<?php if ($warn_n): ?><span class="phpinfowp-rc phpinfowp-rc-warn"><?php echo $warn_n; ?> warning<?php echo $warn_n === 1 ? '' : 's'; ?></span><?php endif; ?> |
| 289 |
</div> |
| 290 |
<?php else: ?> |
| 291 |
<div class="phpinfowp-report-overall-counts"><span class="phpinfowp-rc phpinfowp-rc-ok"><?php _e('No critical issues', 'phpinfo-wp'); ?></span></div> |
| 292 |
<?php endif; ?> |
| 293 |
<p class="phpinfowp-report-overall-note"><?php _e('A weighted score across PHP config, security headers, OPcache, SSL, PHP support window, and database health. <strong>Aim for 85+.</strong>', 'phpinfo-wp'); ?></p> |
| 294 |
</div> |
| 295 |
</div> |
| 296 |
|
| 297 |
<!-- Category bar chart --> |
| 298 |
<?php if (!empty($r['bars'])): ?> |
| 299 |
<div class="phpinfowp-report-bars"> |
| 300 |
<h3 class="phpinfowp-report-h"><?php _e('Subscores', 'phpinfo-wp'); ?></h3> |
| 301 |
<div class="phpinfowp-report-bars-grid"> |
| 302 |
<?php foreach ($r['bars'] as $bar): |
| 303 |
[$bv, $bvl, $bvc] = Phpinfo_WP_Report::score_to_verdict((int) $bar['score']); ?> |
| 304 |
<div class="phpinfowp-report-bar"> |
| 305 |
<div class="phpinfowp-report-bar-top"> |
| 306 |
<span class="phpinfowp-report-bar-lbl"><?php echo esc_html($bar['label']); ?></span> |
| 307 |
<span class="phpinfowp-report-bar-num" style="color:<?php echo esc_attr($bvc); ?>"><?php echo (int) $bar['score']; ?></span> |
| 308 |
</div> |
| 309 |
<div class="phpinfowp-report-bar-track"> |
| 310 |
<div class="phpinfowp-report-bar-fill" style="width:<?php echo (int) max(2, $bar['score']); ?>%;background:<?php echo esc_attr($bvc); ?>"></div> |
| 311 |
</div> |
| 312 |
</div> |
| 313 |
<?php endforeach; ?> |
| 314 |
</div> |
| 315 |
</div> |
| 316 |
<?php endif; ?> |
| 317 |
|
| 318 |
<?php if ($is_free_preview): ?> |
| 319 |
<!-- Free preview: skeleton rows + gradient overlay — no real data sent to browser --> |
| 320 |
<div style="position:relative; margin-top:24px; overflow:hidden; border-radius:10px;"> |
| 321 |
|
| 322 |
<!-- Skeleton rows mimicking actual report content --> |
| 323 |
<div style="pointer-events:none; user-select:none;"> |
| 324 |
|
| 325 |
<!-- Skeleton: critical issues bar --> |
| 326 |
<div style="background:#fff5f5; border:1px solid #fecaca; border-radius:8px; padding:16px 20px; margin-bottom:16px; display:flex; align-items:center; gap:14px;"> |
| 327 |
<div style="width:32px; height:32px; border-radius:50%; background:#fee2e2; flex-shrink:0;"></div> |
| 328 |
<div style="flex:1;"> |
| 329 |
<div style="height:13px; width:55%; background:#fecaca; border-radius:4px; margin-bottom:8px;"></div> |
| 330 |
<div style="height:11px; width:80%; background:#fee2e2; border-radius:4px;"></div> |
| 331 |
</div> |
| 332 |
</div> |
| 333 |
|
| 334 |
<!-- Skeleton: section label --> |
| 335 |
<div style="height:11px; width:160px; background:#e2e8f0; border-radius:4px; margin:20px 0 12px; text-transform:uppercase;"></div> |
| 336 |
|
| 337 |
<!-- Skeleton: priority card 1 --> |
| 338 |
<div style="background:#fff; border:1px solid #e2e8f0; border-radius:8px; padding:18px 20px; margin-bottom:10px; display:flex; gap:16px; align-items:flex-start;"> |
| 339 |
<div style="width:28px; height:28px; border-radius:50%; background:#f1f5f9; flex-shrink:0;"></div> |
| 340 |
<div style="flex:1;"> |
| 341 |
<div style="display:flex; gap:8px; margin-bottom:10px; align-items:center;"> |
| 342 |
<div style="height:20px; width:68px; background:#fecaca; border-radius:20px;"></div> |
| 343 |
<div style="height:12px; width:90px; background:#e2e8f0; border-radius:4px;"></div> |
| 344 |
</div> |
| 345 |
<div style="height:13px; width:70%; background:#cbd5e1; border-radius:4px; margin-bottom:8px;"></div> |
| 346 |
<div style="height:11px; width:95%; background:#e2e8f0; border-radius:4px; margin-bottom:6px;"></div> |
| 347 |
<div style="height:11px; width:85%; background:#e2e8f0; border-radius:4px;"></div> |
| 348 |
</div> |
| 349 |
</div> |
| 350 |
|
| 351 |
<!-- Skeleton: priority card 2 --> |
| 352 |
<div style="background:#fff; border:1px solid #e2e8f0; border-radius:8px; padding:18px 20px; margin-bottom:10px; display:flex; gap:16px; align-items:flex-start;"> |
| 353 |
<div style="width:28px; height:28px; border-radius:50%; background:#f1f5f9; flex-shrink:0;"></div> |
| 354 |
<div style="flex:1;"> |
| 355 |
<div style="display:flex; gap:8px; margin-bottom:10px; align-items:center;"> |
| 356 |
<div style="height:20px; width:60px; background:#fef3c7; border-radius:20px;"></div> |
| 357 |
<div style="height:12px; width:110px; background:#e2e8f0; border-radius:4px;"></div> |
| 358 |
</div> |
| 359 |
<div style="height:13px; width:60%; background:#cbd5e1; border-radius:4px; margin-bottom:8px;"></div> |
| 360 |
<div style="height:11px; width:90%; background:#e2e8f0; border-radius:4px;"></div> |
| 361 |
</div> |
| 362 |
</div> |
| 363 |
|
| 364 |
<!-- Skeleton: priority card 3 --> |
| 365 |
<div style="background:#fff; border:1px solid #e2e8f0; border-radius:8px; padding:18px 20px; margin-bottom:10px; display:flex; gap:16px; align-items:flex-start;"> |
| 366 |
<div style="width:28px; height:28px; border-radius:50%; background:#f1f5f9; flex-shrink:0;"></div> |
| 367 |
<div style="flex:1;"> |
| 368 |
<div style="display:flex; gap:8px; margin-bottom:10px; align-items:center;"> |
| 369 |
<div style="height:20px; width:60px; background:#fef3c7; border-radius:20px;"></div> |
| 370 |
<div style="height:12px; width:80px; background:#e2e8f0; border-radius:4px;"></div> |
| 371 |
</div> |
| 372 |
<div style="height:13px; width:75%; background:#cbd5e1; border-radius:4px; margin-bottom:8px;"></div> |
| 373 |
<div style="height:11px; width:88%; background:#e2e8f0; border-radius:4px;"></div> |
| 374 |
</div> |
| 375 |
</div> |
| 376 |
|
| 377 |
<!-- Skeleton: section divider rows --> |
| 378 |
<div style="margin-top:20px; padding-top:16px; border-top:1px solid #e2e8f0;"> |
| 379 |
<div style="height:11px; width:140px; background:#e2e8f0; border-radius:4px; margin-bottom:14px;"></div> |
| 380 |
<div style="display:flex; gap:12px; margin-bottom:10px;"> |
| 381 |
<div style="height:40px; flex:1; background:#f8fafc; border:1px solid #e2e8f0; border-radius:6px;"></div> |
| 382 |
<div style="height:40px; flex:1; background:#f8fafc; border:1px solid #e2e8f0; border-radius:6px;"></div> |
| 383 |
<div style="height:40px; flex:1; background:#f8fafc; border:1px solid #e2e8f0; border-radius:6px;"></div> |
| 384 |
</div> |
| 385 |
<div style="height:11px; width:120px; background:#e2e8f0; border-radius:4px; margin-top:16px; margin-bottom:14px;"></div> |
| 386 |
<div style="height:38px; background:#f8fafc; border:1px solid #e2e8f0; border-radius:6px;"></div> |
| 387 |
</div> |
| 388 |
</div> |
| 389 |
|
| 390 |
<!-- Gradient fade-out overlay --> |
| 391 |
<div style="position:absolute; bottom:0; left:0; right:0; height:75%; background:linear-gradient(to bottom, rgba(246,249,252,0) 0%, rgba(246,249,252,0.92) 40%, #f6f9fc 100%); pointer-events:none;"></div> |
| 392 |
|
| 393 |
<!-- Upgrade card floating over skeleton --> |
| 394 |
<div style="position:absolute; bottom:24px; left:50%; transform:translateX(-50%); width:100%; max-width:520px; background:#fff; border:1px solid #e2e8f0; border-radius:10px; padding:32px 28px; box-shadow:0 8px 24px -6px rgba(0,0,0,0.08); text-align:center;"> |
| 395 |
<span class="dashicons dashicons-lock" style="font-size:36px; width:36px; height:36px; color:#777BB3; display:inline-block; margin-bottom:12px;"></span> |
| 396 |
<h3 style="margin:0 0 8px; font-size:20px; font-weight:600; color:#1d2327;">Full diagnostics locked</h3> |
| 397 |
<p style="margin:0 0 6px; font-size:13.5px; color:#475569; line-height:1.6; max-width:400px; margin-left:auto; margin-right:auto;">Unlock critical issues, security headers, SSL, OPcache, database health, and 1-click auto-fixes.</p> |
| 398 |
<p style="margin:0 0 22px; font-size:12.5px; color:#94a3b8;">Your overall score above is real - the details explain exactly what to fix.</p> |
| 399 |
<a href="https://exeebit.com/phpinfo-wp#pricing" target="_blank" rel="noopener" class="button button-primary button-large" style="background:#777BB3; border-color:#777BB3; height:42px; line-height:40px; font-size:14px; font-weight:600; padding:0 26px; border-radius:6px; text-decoration:none; display:inline-block;">Upgrade to Pro →</a> |
| 400 |
</div> |
| 401 |
|
| 402 |
<!-- Spacer so the floating card has room --> |
| 403 |
<div style="height:220px;"></div> |
| 404 |
</div> |
| 405 |
<?php else: // Pro users get the full detail HTML below ?> |
| 406 |
|
| 407 |
<!-- Critical issues banner --> |
| 408 |
<?php if ($crit_n): ?> |
| 409 |
<div class="phpinfowp-report-critbar"> |
| 410 |
<div class="phpinfowp-report-critbar-head"> |
| 411 |
<span class="phpinfowp-report-critbar-ic"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" style="width:16px;height:16px;display:block"><path fill-rule="evenodd" d="M4.22 4.22a.75.75 0 011.06 0L10 8.94l4.72-4.72a.75.75 0 111.06 1.06L11.06 10l4.72 4.72a.75.75 0 11-1.06 1.06L10 11.06l-4.72 4.72a.75.75 0 01-1.06-1.06L8.94 10 4.22 5.28a.75.75 0 010-1.06z" clip-rule="evenodd"/></svg></span> |
| 412 |
<div> |
| 413 |
<div class="phpinfowp-report-critbar-title"><?php echo $crit_n; ?> critical issue<?php echo $crit_n === 1 ? '' : 's'; ?> need immediate attention</div> |
| 414 |
<div class="phpinfowp-report-critbar-sub"><?php _e('Anything here is impacting security, performance, or breaks within the next 90 days.', 'phpinfo-wp'); ?></div> |
| 415 |
</div> |
| 416 |
</div> |
| 417 |
<ul class="phpinfowp-report-critbar-list"> |
| 418 |
<?php foreach ($r['criticals'] as $c): ?> |
| 419 |
<li> |
| 420 |
<strong><?php echo esc_html($c['title']); ?></strong> |
| 421 |
<span class="phpinfowp-report-critbar-cat"><?php echo esc_html($c['category']); ?></span> |
| 422 |
<div class="phpinfowp-report-critbar-reason"><?php echo esc_html($c['reason']); ?></div> |
| 423 |
</li> |
| 424 |
<?php endforeach; ?> |
| 425 |
</ul> |
| 426 |
</div> |
| 427 |
<?php endif; ?> |
| 428 |
|
| 429 |
<!-- Top 3 actions this week --> |
| 430 |
<?php if (!empty($r['priorities'])): ?> |
| 431 |
<h3 class="phpinfowp-report-h phpinfowp-report-h-page2">Top <?php echo count($r['priorities']); ?> action<?php echo count($r['priorities']) === 1 ? '' : 's'; ?> this week</h3> |
| 432 |
<p class="phpinfowp-report-h-sub"><?php _e('Tackle these in order. Each card explains why it matters and how to fix it.', 'phpinfo-wp'); ?></p> |
| 433 |
<ol class="phpinfowp-report-priorities"> |
| 434 |
<?php foreach ($r['priorities'] as $i => $p): ?> |
| 435 |
<li class="phpinfowp-report-priority phpinfowp-report-priority-<?php echo esc_attr($p['urgency']); ?>"> |
| 436 |
<div class="phpinfowp-report-priority-num"><?php echo $i + 1; ?></div> |
| 437 |
<div class="phpinfowp-report-priority-body"> |
| 438 |
<div class="phpinfowp-report-priority-head"> |
| 439 |
<?php echo $verdict_pill($p['urgency'], $p['urgency'] === 'critical' ? 'Critical' : 'High'); ?> |
| 440 |
<span class="phpinfowp-report-priority-cat"><?php echo esc_html($p['category']); ?></span> |
| 441 |
</div> |
| 442 |
<div class="phpinfowp-report-priority-title"><?php echo esc_html($p['title']); ?></div> |
| 443 |
<div class="phpinfowp-report-priority-why"> |
| 444 |
<strong><?php _e('Why it matters:', 'phpinfo-wp'); ?></strong> |
| 445 |
<?php echo esc_html($p['reason']); ?> |
| 446 |
</div> |
| 447 |
<div class="phpinfowp-report-priority-how"> |
| 448 |
<strong><?php _e('How to fix:', 'phpinfo-wp'); ?></strong> |
| 449 |
<?php echo wp_kses($p['how'], ['code' => [], 'strong' => [], 'em' => []]); ?> |
| 450 |
</div> |
| 451 |
</div> |
| 452 |
</li> |
| 453 |
<?php endforeach; ?> |
| 454 |
</ol> |
| 455 |
<?php else: ?> |
| 456 |
<h3 class="phpinfowp-report-h"><?php _e('No urgent actions', 'phpinfo-wp'); ?></h3> |
| 457 |
<p><?php _e('The site is in good shape. Keep an eye on the subscores above and review again next month.', 'phpinfo-wp'); ?></p> |
| 458 |
<?php endif; ?> |
| 459 |
|
| 460 |
<!-- Snapshot grid with verdict pills + plain-English captions --> |
| 461 |
<h3 class="phpinfowp-report-h"><?php _e('Snapshot', 'phpinfo-wp'); ?></h3> |
| 462 |
<div class="phpinfowp-report-grid"> |
| 463 |
<div class="phpinfowp-report-stat"> |
| 464 |
<div class="phpinfowp-report-stat-label">PHP version <?php echo $verdict_pill($verdict_eol($r['eol'])); ?></div> |
| 465 |
<div class="phpinfowp-report-stat-value"><?php echo esc_html($r['php']); ?></div> |
| 466 |
<div class="phpinfowp-report-stat-sub"> |
| 467 |
<?php if ($r['eol']['status'] === 'eol'): ?> |
| 468 |
End of life |
| 469 |
<?php elseif ($r['eol']['status'] === 'warning'): ?> |
| 470 |
EOL in <?php echo (int) $r['eol']['days']; ?> days (<?php echo esc_html($r['eol']['eol']); ?>) |
| 471 |
<?php else: ?> |
| 472 |
Supported until <?php echo esc_html($r['eol']['eol']); ?> |
| 473 |
<?php endif; ?> |
| 474 |
</div> |
| 475 |
<div class="phpinfowp-report-stat-cap"><?php echo esc_html(Phpinfo_WP_Report::plain_english('php_version')); ?></div> |
| 476 |
</div> |
| 477 |
<div class="phpinfowp-report-stat"> |
| 478 |
<div class="phpinfowp-report-stat-label">WordPress <?php echo $verdict_pill(($r['extras']['updates']['core'] ?? 0) > 0 ? 'warn' : 'ok'); ?></div> |
| 479 |
<div class="phpinfowp-report-stat-value"><?php echo esc_html($r['wp']); ?></div> |
| 480 |
<div class="phpinfowp-report-stat-sub"> |
| 481 |
<?php if (($r['extras']['updates']['core'] ?? 0) > 0): ?> |
| 482 |
Update available |
| 483 |
<?php else: ?> |
| 484 |
Up to date |
| 485 |
<?php endif; ?> |
| 486 |
</div> |
| 487 |
<div class="phpinfowp-report-stat-cap"><?php echo esc_html(Phpinfo_WP_Report::plain_english('wp_version')); ?></div> |
| 488 |
</div> |
| 489 |
<div class="phpinfowp-report-stat"> |
| 490 |
<div class="phpinfowp-report-stat-label">PHP Config <?php echo $verdict_pill($verdict_score((int) ($r['grader']['score'] ?? 0))); ?></div> |
| 491 |
<div class="phpinfowp-report-stat-value"><?php echo esc_html($r['grader']['grade']); ?> <span class="phpinfowp-report-stat-value-sub"><?php echo (int) $r['grader']['score']; ?>/100</span></div> |
| 492 |
<div class="phpinfowp-report-stat-cap"><?php echo esc_html(Phpinfo_WP_Report::plain_english('config_grade')); ?></div> |
| 493 |
</div> |
| 494 |
<?php if (!isset($r['headers']['error'])): ?> |
| 495 |
<div class="phpinfowp-report-stat"> |
| 496 |
<div class="phpinfowp-report-stat-label">Security Headers <?php echo $verdict_pill($verdict_score((int) ($r['headers']['score'] ?? 0))); ?></div> |
| 497 |
<div class="phpinfowp-report-stat-value"><?php echo esc_html($r['headers']['grade']); ?> <span class="phpinfowp-report-stat-value-sub"><?php echo (int) $r['headers']['score']; ?>/100</span></div> |
| 498 |
<div class="phpinfowp-report-stat-cap"><?php echo esc_html(Phpinfo_WP_Report::plain_english('headers')); ?></div> |
| 499 |
</div> |
| 500 |
<?php endif; ?> |
| 501 |
<?php if ($r['db']): |
| 502 |
$db_v = !empty($r['db']['eol']) && ($db_ts = strtotime($r['db']['eol'])) |
| 503 |
? (($db_ts - time()) / DAY_IN_SECONDS < 0 ? 'critical' : (($db_ts - time()) / DAY_IN_SECONDS < 90 ? 'critical' : (($db_ts - time()) / DAY_IN_SECONDS < 365 ? 'warn' : 'ok'))) |
| 504 |
: 'ok'; |
| 505 |
?> |
| 506 |
<div class="phpinfowp-report-stat"> |
| 507 |
<div class="phpinfowp-report-stat-label">Database <?php echo $verdict_pill($db_v); ?></div> |
| 508 |
<div class="phpinfowp-report-stat-value"><?php echo esc_html($r['db']['engine'] . ' ' . $r['db']['version']); ?></div> |
| 509 |
<div class="phpinfowp-report-stat-sub"> |
| 510 |
<?php if (!empty($r['db']['eol'])): ?> |
| 511 |
EOL <?php echo esc_html($r['db']['eol']); ?> |
| 512 |
<?php else: ?> |
| 513 |
<?php echo size_format($r['db_size']['total']); ?> total |
| 514 |
<?php endif; ?> |
| 515 |
</div> |
| 516 |
<div class="phpinfowp-report-stat-cap"><?php echo esc_html(Phpinfo_WP_Report::plain_english('db_engine')); ?></div> |
| 517 |
</div> |
| 518 |
<?php endif; ?> |
| 519 |
<?php if ($r['opcache']): ?> |
| 520 |
<div class="phpinfowp-report-stat"> |
| 521 |
<div class="phpinfowp-report-stat-label">OPcache hit rate <?php echo $verdict_pill($verdict_hit($r['opcache']['hit_rate'] ?? 0)); ?></div> |
| 522 |
<div class="phpinfowp-report-stat-value"><?php echo $r['opcache']['hit_rate'] !== null ? esc_html($r['opcache']['hit_rate']) . '%' : '—'; ?></div> |
| 523 |
<div class="phpinfowp-report-stat-sub"><?php _e('Target 95% +', 'phpinfo-wp'); ?></div> |
| 524 |
<div class="phpinfowp-report-stat-cap"><?php echo esc_html(Phpinfo_WP_Report::plain_english('opcache_hit')); ?></div> |
| 525 |
</div> |
| 526 |
<?php endif; ?> |
| 527 |
</div> |
| 528 |
|
| 529 |
<!-- Site configuration (new section) --> |
| 530 |
<?php $ex = $r['extras']; ?> |
| 531 |
<h3 class="phpinfowp-report-h"><?php _e('Site configuration', 'phpinfo-wp'); ?></h3> |
| 532 |
<table class="phpinfowp-report-table"> |
| 533 |
<tbody> |
| 534 |
<tr> |
| 535 |
<td style="width:40%"><?php _e('HTTPS', 'phpinfo-wp'); ?></td> |
| 536 |
<td><?php echo $ex['https']['is_https'] && !$ex['https']['mixed_risk'] |
| 537 |
? $verdict_pill('ok', 'Fully on HTTPS') |
| 538 |
: $verdict_pill('warn', $ex['https']['is_https'] ? 'Mixed-content risk' : 'Not on HTTPS'); ?></td> |
| 539 |
</tr> |
| 540 |
<tr> |
| 541 |
<td>WP_DEBUG_DISPLAY <span class="phpinfowp-report-inline-cap">(<?php echo esc_html(Phpinfo_WP_Report::plain_english('wp_debug_display')); ?>)</span></td> |
| 542 |
<td> |
| 543 |
<?php if ($ex['wp_debug']['debug_display']): ?> |
| 544 |
<?php echo $verdict_pill('critical', 'On — errors visible to visitors'); ?> |
| 545 |
<?php else: ?> |
| 546 |
<?php echo $verdict_pill('ok', 'Off (safe)'); ?> |
| 547 |
<?php endif; ?> |
| 548 |
</td> |
| 549 |
</tr> |
| 550 |
<tr> |
| 551 |
<td><?php _e('Pending updates', 'phpinfo-wp'); ?></td> |
| 552 |
<td> |
| 553 |
<?php |
| 554 |
$u = $ex['updates']; |
| 555 |
$tot = $u['core'] + $u['plugins'] + $u['themes']; |
| 556 |
if ($tot === 0) { |
| 557 |
echo $verdict_pill('ok', 'All up to date'); |
| 558 |
} else { |
| 559 |
$bits = []; |
| 560 |
if ($u['core']) $bits[] = 'WP core'; |
| 561 |
if ($u['plugins']) $bits[] = "{$u['plugins']} plugin" . ($u['plugins'] === 1 ? '' : 's'); |
| 562 |
if ($u['themes']) $bits[] = "{$u['themes']} theme" . ($u['themes'] === 1 ? '' : 's'); |
| 563 |
echo $verdict_pill($u['core'] ? 'warn' : 'warn', implode(' · ', $bits) . ' pending'); |
| 564 |
} |
| 565 |
?> |
| 566 |
</td> |
| 567 |
</tr> |
| 568 |
<tr> |
| 569 |
<td><?php _e('Backup plugin', 'phpinfo-wp'); ?></td> |
| 570 |
<td> |
| 571 |
<?php if ($ex['backup']['detected']): ?> |
| 572 |
<?php echo $verdict_pill('ok', esc_html($ex['backup']['plugin']) . ' detected'); ?> |
| 573 |
<?php else: ?> |
| 574 |
<?php echo $verdict_pill('warn', 'None detected'); ?> |
| 575 |
<?php endif; ?> |
| 576 |
</td> |
| 577 |
</tr> |
| 578 |
<?php foreach ($ex['permissions'] as $name => $info): |
| 579 |
if (empty($info['exists'])) continue; ?> |
| 580 |
<tr> |
| 581 |
<td><code><?php echo esc_html($name); ?></code> permissions</td> |
| 582 |
<td> |
| 583 |
<?php echo $verdict_pill($info['verdict'], $info['perms']); ?> |
| 584 |
<?php if ($info['verdict'] !== 'ok'): ?> |
| 585 |
<span class="phpinfowp-report-inline-cap">— consider <code>chmod <?php echo $name === 'wp-config.php' ? '600' : '644'; ?> <?php echo esc_html($name); ?></code></span> |
| 586 |
<?php endif; ?> |
| 587 |
</td> |
| 588 |
</tr> |
| 589 |
<?php endforeach; ?> |
| 590 |
</tbody> |
| 591 |
</table> |
| 592 |
|
| 593 |
<!-- Failing config checks --> |
| 594 |
<?php $failing = array_filter($r['grader']['checks'], function ($c) { |
| 595 |
return $c['status'] === 'fail'; |
| 596 |
}); ?> |
| 597 |
<?php if ($failing): ?> |
| 598 |
<h3 class="phpinfowp-report-h">Config issues (<?php echo count($failing); ?>)</h3> |
| 599 |
<table class="phpinfowp-report-table"> |
| 600 |
<thead><tr><th><?php _e('Directive', 'phpinfo-wp'); ?></th><th><?php _e('Current', 'phpinfo-wp'); ?></th><th><?php _e('Recommended', 'phpinfo-wp'); ?></th><th style="width:90px"><?php _e('Verdict', 'phpinfo-wp'); ?></th></tr></thead> |
| 601 |
<tbody> |
| 602 |
<?php foreach ($failing as $c): ?> |
| 603 |
<tr> |
| 604 |
<td><code><?php echo esc_html($c['key']); ?></code><?php if (!empty($c['why'])): ?><div class="phpinfowp-report-inline-cap"><?php echo esc_html($c['why']); ?></div><?php endif; ?></td> |
| 605 |
<td style="color:#8e1414"><?php echo esc_html($c['value']); ?></td> |
| 606 |
<td style="color:#0a7d2e"><?php echo esc_html($c['good']); ?></td> |
| 607 |
<td><?php echo $verdict_pill('critical', 'Fix'); ?></td> |
| 608 |
</tr> |
| 609 |
<?php endforeach; ?> |
| 610 |
</tbody> |
| 611 |
</table> |
| 612 |
<?php endif; ?> |
| 613 |
|
| 614 |
<!-- Missing security headers --> |
| 615 |
<?php if (!isset($r['headers']['error'])): |
| 616 |
$missing = array_filter($r['headers']['results'], function ($h) { |
| 617 |
return !$h['present']; |
| 618 |
}); |
| 619 |
?> |
| 620 |
<?php if ($missing): ?> |
| 621 |
<h3 class="phpinfowp-report-h">Missing security headers (<?php echo count($missing); ?>)</h3> |
| 622 |
<ul class="phpinfowp-report-list"> |
| 623 |
<?php foreach ($missing as $h): ?> |
| 624 |
<li> |
| 625 |
<?php echo $verdict_pill('warn', 'Missing'); ?> |
| 626 |
<strong><?php echo esc_html($h['label']); ?></strong> — <?php echo esc_html($h['desc']); ?> |
| 627 |
</li> |
| 628 |
<?php endforeach; ?> |
| 629 |
</ul> |
| 630 |
<?php endif; ?> |
| 631 |
<?php endif; ?> |
| 632 |
|
| 633 |
<!-- SSL summary --> |
| 634 |
<?php if ($r['ssl']): ?> |
| 635 |
<h3 class="phpinfowp-report-h"><?php _e('SSL certificates', 'phpinfo-wp'); ?></h3> |
| 636 |
<table class="phpinfowp-report-table"> |
| 637 |
<thead><tr><th><?php _e('Host', 'phpinfo-wp'); ?></th><th><?php _e('Issuer', 'phpinfo-wp'); ?></th><th><?php _e('Expires', 'phpinfo-wp'); ?></th><th><?php _e('Status', 'phpinfo-wp'); ?></th></tr></thead> |
| 638 |
<tbody> |
| 639 |
<?php foreach ($r['ssl'] as $c): |
| 640 |
if (!empty($c['error'])) continue; |
| 641 |
$sv = $c['days'] < 0 ? 'critical' : ($c['days'] < 14 ? 'critical' : ($c['days'] < 30 ? 'warn' : 'ok')); |
| 642 |
?> |
| 643 |
<tr> |
| 644 |
<td><?php echo esc_html($c['host']); ?></td> |
| 645 |
<td><?php echo esc_html($c['issuer']); ?></td> |
| 646 |
<td><?php echo esc_html($c['expiry']); ?></td> |
| 647 |
<td><?php echo $verdict_pill($sv, $c['days'] < 0 ? 'Expired' : $c['days'] . ' days'); ?></td> |
| 648 |
</tr> |
| 649 |
<?php endforeach; ?> |
| 650 |
</tbody> |
| 651 |
</table> |
| 652 |
<?php endif; ?> |
| 653 |
|
| 654 |
<!-- DB summary --> |
| 655 |
<?php if ($r['db']): ?> |
| 656 |
<h3 class="phpinfowp-report-h"><?php _e('Database', 'phpinfo-wp'); ?></h3> |
| 657 |
<table class="phpinfowp-report-table"> |
| 658 |
<tbody> |
| 659 |
<tr><td style="width:40%"><?php _e('Engine', 'phpinfo-wp'); ?></td><td><?php echo esc_html($r['db']['engine'] . ' ' . $r['db']['version']); ?></td></tr> |
| 660 |
<tr><td><?php _e('End-of-life', 'phpinfo-wp'); ?></td><td><?php echo esc_html($r['db']['eol'] ?? '—'); ?></td></tr> |
| 661 |
<tr><td><?php _e('Total size', 'phpinfo-wp'); ?></td><td><?php echo size_format($r['db_size']['total']); ?> across <?php echo (int) $r['db_size']['tables']; ?> tables</td></tr> |
| 662 |
<tr> |
| 663 |
<td><?php _e('Autoload data', 'phpinfo-wp'); ?></td> |
| 664 |
<td> |
| 665 |
<?php |
| 666 |
$al_bytes = (int) $r['autoload']['bytes']; |
| 667 |
$al_v = $al_bytes > 1048576 ? 'warn' : 'ok'; |
| 668 |
?> |
| 669 |
<?php echo size_format($al_bytes); ?> across <?php echo (int) $r['autoload']['count']; ?> options |
| 670 |
<?php echo $verdict_pill($al_v, $al_v === 'ok' ? 'Tiny (good)' : 'Large'); ?> |
| 671 |
<div class="phpinfowp-report-inline-cap"><?php echo esc_html(Phpinfo_WP_Report::plain_english('autoload')); ?></div> |
| 672 |
</td> |
| 673 |
</tr> |
| 674 |
</tbody> |
| 675 |
</table> |
| 676 |
<?php endif; ?> |
| 677 |
|
| 678 |
<!-- Cron --> |
| 679 |
<?php if ($r['cron'] && ($r['cron']['overdue'] || $r['cron']['orphan'])): ?> |
| 680 |
<h3 class="phpinfowp-report-h"><?php _e('Cron health', 'phpinfo-wp'); ?></h3> |
| 681 |
<ul class="phpinfowp-report-list"> |
| 682 |
<li><?php echo (int) $r['cron']['total']; ?> total scheduled events</li> |
| 683 |
<?php if ($r['cron']['overdue']): ?> |
| 684 |
<li><?php echo $verdict_pill('critical', 'Overdue'); ?> <?php echo (int) $r['cron']['overdue']; ?> event(s) <span class="phpinfowp-report-inline-cap">— <?php echo esc_html(Phpinfo_WP_Report::plain_english('overdue_cron')); ?></span></li> |
| 685 |
<?php endif; ?> |
| 686 |
<?php if ($r['cron']['orphan']): ?> |
| 687 |
<li><?php echo $verdict_pill('warn', 'Orphan'); ?> <?php echo (int) $r['cron']['orphan']; ?> hook(s) <span class="phpinfowp-report-inline-cap">— <?php echo esc_html(Phpinfo_WP_Report::plain_english('orphan_cron')); ?></span></li> |
| 688 |
<?php endif; ?> |
| 689 |
</ul> |
| 690 |
<?php endif; ?> |
| 691 |
|
| 692 |
<!-- Compat --> |
| 693 |
<?php if ($r['compat'] && !isset($r['compat']['error']) && !empty($r['compat']['total'])): ?> |
| 694 |
<h3 class="phpinfowp-report-h">PHP compatibility (target PHP <?php echo esc_html($r['compat']['target']); ?>)</h3> |
| 695 |
<p><?php echo $verdict_pill('warn', $r['compat']['total'] . ' issues'); ?> across <?php echo (int) $r['compat']['with_issues']; ?> plugins/themes. Open the <strong><?php _e('PHP Compatibility', 'phpinfo-wp'); ?></strong> page for the full file list.</p> |
| 696 |
<?php endif; ?> |
| 697 |
|
| 698 |
<?php endif; // end Pro-only detail block ?> |
| 699 |
|
| 700 |
|
| 701 |
<div class="phpinfowp-report-footer"> |
| 702 |
<?php if ($b['enabled'] && $b['footer_note']): ?> |
| 703 |
<?php echo nl2br(esc_html($b['footer_note'])); ?> |
| 704 |
<?php else: ?> |
| 705 |
Report generated by <strong><?php echo $brand_name; ?></strong> · <?php echo esc_html(get_site_url()); ?> |
| 706 |
<?php endif; ?> |
| 707 |
</div> |
| 708 |
|
| 709 |
</div> |
| 710 |
</div> |
| 711 |
|