| 1 |
<?php |
| 2 |
if (!defined('ABSPATH')) { exit; } |
| 3 |
if (!current_user_can('manage_options')) { wp_die(__('You do not have sufficient permissions.')); } |
| 4 |
|
| 5 |
$api_key = get_option('importify_api_key'); |
| 6 |
$ic = get_option('importify_check'); |
| 7 |
if (!is_array($ic)) $ic = array(); |
| 8 |
|
| 9 |
/** |
| 10 |
* Material Symbols icons used (rendered via Google Fonts icon font). |
| 11 |
* The admin view hides all .material-symbols-outlined via `visibility: hidden` |
| 12 |
* until the font finishes loading and the `fonts-ready` class is added to <html>. |
| 13 |
* This avoids the "flash of raw ligature text" before the font has downloaded. |
| 14 |
* |
| 15 |
* check_circle / verified_user / shopping_cart / link / code |
| 16 |
* security / cloud_done / api / task_alt / arrow_forward / refresh |
| 17 |
* dangerous / link_off / shield / timer_off / warning |
| 18 |
*/ |
| 19 |
|
| 20 |
// Build checks array |
| 21 |
$checks = array(); |
| 22 |
$ssl_ok = isset($ic['ssl_active']) && $ic['ssl_active'] === "true"; |
| 23 |
$checks[] = array('name'=>'SSL Certificate','desc'=>'Secure connection for API product importing','icon_pass'=>'verified_user','icon_fail'=>'dangerous','ok'=>$ssl_ok,'value'=>$ssl_ok?'Active':'Missing','type'=>$ssl_ok?'pass':'fail', |
| 24 |
'steps'=>array('Contact your hosting provider to install an SSL certificate.','Ensure your site loads with <code>https://</code>.','Update WordPress URL in Settings → General to use https://.'),'url'=>'https://help.importify.com/article/526/importify-woocommerce-store-connection-troubleshooting-guide'); |
| 25 |
|
| 26 |
$woo_ok = !empty($ic['woocomerce_installed']); |
| 27 |
$wv = isset($ic['woo_version']) && $ic['woo_version'] ? 'v'.esc_html($ic['woo_version']) : ($woo_ok ? 'Installed' : ''); |
| 28 |
$checks[] = array('name'=>'WooCommerce','desc'=>'Core compatibility verified for dropshipping','icon_pass'=>'shopping_cart','icon_fail'=>'dangerous','ok'=>$woo_ok,'value'=>$woo_ok?$wv:'Not Installed','type'=>$woo_ok?'pass':'fail', |
| 29 |
'steps'=>array('Go to WordPress → Plugins → Add New.','Search for "WooCommerce" and click Install.','Activate the plugin and complete the setup wizard.'),'url'=>'https://help.importify.com/article/532/how-to-install-the-woocommerce-plugin'); |
| 30 |
|
| 31 |
$p = isset($ic['permalinks']) ? $ic['permalinks'] : ''; |
| 32 |
$p_ok = is_string($p) && strlen($p) > 0; |
| 33 |
$checks[] = array('name'=>'Permalinks','desc'=>'Post name structure required for REST API','icon_pass'=>'link','icon_fail'=>'link_off','ok'=>$p_ok,'value'=>$p_ok?'Post name':'Plain','type'=>$p_ok?'pass':'fail', |
| 34 |
'steps'=>array('Go to WordPress → Settings → Permalinks.','Select "Post name" (recommended).','Click "Save Changes".'),'url'=>'https://help.importify.com/article/533/how-do-i-set-up-the-correct-permalink-structure-for-woocommerce-in-wordpress'); |
| 35 |
|
| 36 |
$php_ok = isset($ic['php_ok']) ? $ic['php_ok'] : version_compare(PHP_VERSION,'7.2','>='); |
| 37 |
$checks[] = array('name'=>'PHP Version','desc'=>'Runtime environment compatibility','icon_pass'=>'code','icon_fail'=>'dangerous','ok'=>$php_ok,'value'=>esc_html(phpversion()),'type'=>$php_ok?'pass':'fail', |
| 38 |
'steps'=>array('Contact your hosting provider to upgrade PHP to 7.4+.','Most hosting dashboards allow PHP version switching.','PHP 8.0+ is recommended.'),'url'=>''); |
| 39 |
|
| 40 |
$fw = !empty($ic['firewall_active']); |
| 41 |
$fn = isset($ic['firewall_name']) ? esc_html($ic['firewall_name']) : 'Detected'; |
| 42 |
$checks[] = array('name'=>'Security Firewall','desc'=>'External import requests may be throttled','icon_pass'=>'security','icon_fail'=>'shield','ok'=>!$fw,'value'=>$fw?$fn:'No blocking plugins','type'=>$fw?'warn':'pass', |
| 43 |
'steps'=>array('Your security plugin may block Importify\'s API requests.','Add this IP to your firewall allowlist: <code>162.243.171.163</code>','If using Wordfence: Firewall → Manage → Allowlisted IPs.','After adding the IP, refresh this page.'),'url'=>'https://help.importify.com/article/526/importify-woocommerce-store-connection-troubleshooting-guide'); |
| 44 |
|
| 45 |
$cf = !empty($ic['cloudflare_active']); |
| 46 |
$checks[] = array('name'=>'Cloudflare','desc'=>'CDN and security proxy detection','icon_pass'=>'cloud_done','icon_fail'=>'shield','ok'=>!$cf,'value'=>$cf?'Detected':'Not detected','type'=>$cf?'warn':'pass', |
| 47 |
'steps'=>array('Cloudflare may block Importify\'s API calls.','Go to Cloudflare → Security → WAF.','Allow IP: <code>162.243.171.163</code>','Or create a Page Rule to bypass security for your API URL.'),'url'=>'https://help.importify.com/article/562/how-to-fix-woocommerce-api-issues-caused-by-cloudflare'); |
| 48 |
|
| 49 |
$le = get_option('importify_last_error'); |
| 50 |
$api_ok = empty($le); |
| 51 |
$checks[] = array('name'=>'API Connection','desc'=>'Server communication with Importify','icon_pass'=>'api','icon_fail'=>'timer_off','ok'=>$api_ok,'value'=>$api_ok?'Connected':'Timeout','type'=>$api_ok?'pass':'fail', |
| 52 |
'steps'=>array_filter(array('Ensure your site is accessible from the internet.','Check WooCommerce REST API is enabled.','Add IP <code>162.243.171.163</code> to firewall allowlist.','Try deactivating and reactivating Importify.',$le?'Last error: <em>'.esc_html(substr($le,0,100)).'</em>':'')),'url'=>'https://help.importify.com/article/526/importify-woocommerce-store-connection-troubleshooting-guide'); |
| 53 |
|
| 54 |
// ───────────────────────────────────────────────────────────────────── |
| 55 |
// Preview overrides (debug helper, admin-gated by the manage_options |
| 56 |
// check above). Lets support / designers see the error-state UI without |
| 57 |
// actually triggering the underlying issue on the site. |
| 58 |
// |
| 59 |
// Append any combination to the plugin URL: |
| 60 |
// ?error1=preview → SSL Certificate fails ("Missing") |
| 61 |
// ?error2=preview → WooCommerce not installed |
| 62 |
// ?error3=preview → Permalinks set to Plain |
| 63 |
// ?error4=preview → PHP Version unsupported |
| 64 |
// ?error5=preview → Security Firewall detected (warn) |
| 65 |
// ?error6=preview → Cloudflare detected (warn) |
| 66 |
// ?error7=preview → API Connection timeout |
| 67 |
// ?preview=all → every check above at once |
| 68 |
// ?preview=mixed → a curated realistic mix (SSL fail + Cloudflare warn) |
| 69 |
// ───────────────────────────────────────────────────────────────────── |
| 70 |
$importify_preview_map = array( |
| 71 |
0 => array('type' => 'fail', 'value' => 'Missing'), // SSL |
| 72 |
1 => array('type' => 'fail', 'value' => 'Not Installed'), // WooCommerce |
| 73 |
2 => array('type' => 'fail', 'value' => 'Plain'), // Permalinks |
| 74 |
3 => array('type' => 'fail', 'value' => '5.6.40 (unsupported)'), // PHP Version |
| 75 |
4 => array('type' => 'warn', 'value' => 'Wordfence Security'), // Firewall |
| 76 |
5 => array('type' => 'warn', 'value' => 'Detected'), // Cloudflare |
| 77 |
6 => array('type' => 'fail', 'value' => 'Timeout'), // API Connection |
| 78 |
); |
| 79 |
$importify_preview_all = (isset($_GET['preview']) && $_GET['preview'] === 'all'); |
| 80 |
$importify_preview_mixed = (isset($_GET['preview']) && $_GET['preview'] === 'mixed'); |
| 81 |
$importify_mixed_indexes = array(0, 5); // SSL + Cloudflare |
| 82 |
$importify_any_preview = $importify_preview_all || $importify_preview_mixed; |
| 83 |
|
| 84 |
for ($idx = 0; $idx < count($checks); $idx++) { |
| 85 |
$force = false; |
| 86 |
if ($importify_preview_all) { |
| 87 |
$force = true; |
| 88 |
} elseif ($importify_preview_mixed && in_array($idx, $importify_mixed_indexes, true)) { |
| 89 |
$force = true; |
| 90 |
} elseif (isset($_GET['error' . ($idx + 1)]) && $_GET['error' . ($idx + 1)] === 'preview') { |
| 91 |
$force = true; |
| 92 |
$importify_any_preview = true; |
| 93 |
} |
| 94 |
if ($force && isset($importify_preview_map[$idx])) { |
| 95 |
$checks[$idx]['type'] = $importify_preview_map[$idx]['type']; |
| 96 |
$checks[$idx]['value'] = $importify_preview_map[$idx]['value']; |
| 97 |
$checks[$idx]['ok'] = false; |
| 98 |
} |
| 99 |
} |
| 100 |
|
| 101 |
$has_issues = false; $issue_count = 0; |
| 102 |
foreach ($checks as $c) { if ($c['type'] !== 'pass') { $has_issues = true; $issue_count++; } } |
| 103 |
$btn = esc_attr(IMPORTIFY_API_URL.'/woocomerce/login-by-token?token='.$api_key); |
| 104 |
|
| 105 |
/** |
| 106 |
* Choose the right pill class for a row's value. |
| 107 |
* - fail/warn → coloured pill matching severity |
| 108 |
* - pass with meaningful value like "Active"/"Connected"/"Post name"/"No blocking plugins" → success-tinted pill |
| 109 |
* - pass with neutral value (version numbers) → neutral grey pill |
| 110 |
* - "Not detected" (Cloudflare passed state) → muted grey |
| 111 |
*/ |
| 112 |
function importify_pill_class_for($c) { |
| 113 |
if ($c['type'] === 'fail') return 'importify-pill--fail'; |
| 114 |
if ($c['type'] === 'warn') return 'importify-pill--warn'; |
| 115 |
$strong_pass_values = array('Active', 'Connected', 'Post name', 'No blocking plugins'); |
| 116 |
if (in_array($c['value'], $strong_pass_values, true)) return 'importify-pill--success'; |
| 117 |
if ($c['value'] === 'Not detected') return 'importify-pill--muted'; |
| 118 |
return 'importify-pill--neutral'; |
| 119 |
} |
| 120 |
?> |
| 121 |
<!-- Fonts: Manrope (headline) + Inter (body) + Material Symbols (icons, display=block for FOIT control) --> |
| 122 |
<link href="https://fonts.googleapis.com" rel="preconnect"> |
| 123 |
<link crossorigin href="https://fonts.gstatic.com" rel="preconnect"> |
| 124 |
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;700;800&family=Inter:wght@400;500;600&display=swap" rel="stylesheet"> |
| 125 |
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=block" rel="stylesheet"> |
| 126 |
|
| 127 |
<script> |
| 128 |
/* Reveal icons the instant the Material Symbols font is ready. |
| 129 |
Keeps ligature text invisible until the font loads → no "flash of check_circle text". */ |
| 130 |
(function () { |
| 131 |
if (document.fonts && document.fonts.load) { |
| 132 |
document.fonts.load('24px "Material Symbols Outlined"').then(function () { |
| 133 |
document.documentElement.classList.add('fonts-ready'); |
| 134 |
}).catch(function () { |
| 135 |
document.documentElement.classList.add('fonts-ready'); |
| 136 |
}); |
| 137 |
} else { |
| 138 |
document.documentElement.classList.add('fonts-ready'); |
| 139 |
} |
| 140 |
// Safety net: reveal anyway after 3s so icons never stay permanently hidden. |
| 141 |
setTimeout(function () { document.documentElement.classList.add('fonts-ready'); }, 3000); |
| 142 |
})(); |
| 143 |
</script> |
| 144 |
|
| 145 |
<div id="importify-setup-wrap"> |
| 146 |
<div class="importify-container"> |
| 147 |
|
| 148 |
<?php if ($importify_any_preview): ?> |
| 149 |
<div class="importify-preview-banner" role="note"> |
| 150 |
<span class="material-symbols-outlined material-symbols-outlined--filled">science</span> |
| 151 |
<span>Preview mode — showing simulated data. <a href="<?php echo esc_url(remove_query_arg(array('preview','error1','error2','error3','error4','error5','error6','error7'))); ?>">Exit preview</a></span> |
| 152 |
</div> |
| 153 |
<?php endif; ?> |
| 154 |
|
| 155 |
<?php if (!$has_issues): ?> |
| 156 |
<!-- ═══ STATE: ALL PASSED ═══ --> |
| 157 |
|
| 158 |
<!-- Header --> |
| 159 |
<div class="importify-header"> |
| 160 |
<div class="importify-status-badge importify-status-badge--success"> |
| 161 |
<span class="material-symbols-outlined material-symbols-outlined--filled">check_circle</span> |
| 162 |
Importify plugin activated |
| 163 |
</div> |
| 164 |
<h1>You’re all set.</h1> |
| 165 |
<p>Your site passed every check. Head to the dashboard to <a href="<?php echo $btn; ?>" target="_blank" rel="noopener noreferrer">start importing products</a>.</p> |
| 166 |
</div> |
| 167 |
|
| 168 |
<!-- Main card --> |
| 169 |
<div class="importify-card"> |
| 170 |
<div class="importify-card__stripe"></div> |
| 171 |
<div class="importify-card__body"> |
| 172 |
|
| 173 |
<div class="importify-check-list"> |
| 174 |
<?php foreach ($checks as $c): $pill_cls = importify_pill_class_for($c); ?> |
| 175 |
<div class="importify-check-row importify-check-row--pass"> |
| 176 |
<div class="importify-check-row__main"> |
| 177 |
<div class="importify-check-left"> |
| 178 |
<div class="importify-check-icon importify-check-icon--pass"> |
| 179 |
<span class="material-symbols-outlined material-symbols-outlined--filled"><?php echo esc_attr($c['icon_pass']); ?></span> |
| 180 |
</div> |
| 181 |
<div class="importify-check-text"> |
| 182 |
<h3 class="importify-check-text__name"><?php echo esc_html($c['name']); ?></h3> |
| 183 |
<p class="importify-check-text__desc"><?php echo esc_html($c['desc']); ?></p> |
| 184 |
</div> |
| 185 |
</div> |
| 186 |
<div class="importify-check-right"> |
| 187 |
<span class="importify-pill <?php echo $pill_cls; ?>"><?php echo esc_html($c['value']); ?></span> |
| 188 |
</div> |
| 189 |
</div> |
| 190 |
</div> |
| 191 |
<?php endforeach; ?> |
| 192 |
</div> |
| 193 |
|
| 194 |
<div class="importify-card__footer"> |
| 195 |
<div class="importify-card__footer-note"> |
| 196 |
<span class="material-symbols-outlined material-symbols-outlined--filled">task_alt</span> |
| 197 |
<span>All systems ready. You can start importing now.</span> |
| 198 |
</div> |
| 199 |
<a href="<?php echo $btn; ?>" target="_blank" rel="noopener noreferrer" class="importify-btn importify-btn--primary"> |
| 200 |
Proceed to Importify Dashboard |
| 201 |
<span class="material-symbols-outlined">arrow_forward</span> |
| 202 |
</a> |
| 203 |
</div> |
| 204 |
|
| 205 |
</div> |
| 206 |
</div> |
| 207 |
|
| 208 |
<?php else: ?> |
| 209 |
<!-- ═══ STATE: ISSUES FOUND ═══ --> |
| 210 |
|
| 211 |
<!-- Header --> |
| 212 |
<div class="importify-header"> |
| 213 |
<div class="importify-status-badge importify-status-badge--warning"> |
| 214 |
<span class="material-symbols-outlined material-symbols-outlined--filled">warning</span> |
| 215 |
Setup requires attention |
| 216 |
</div> |
| 217 |
<h1>A few things to sort out.</h1> |
| 218 |
<p><?php echo $issue_count; ?> issue<?php echo $issue_count > 1 ? 's' : ''; ?> preventing full automation. Each one has a fix — follow the steps below.</p> |
| 219 |
</div> |
| 220 |
|
| 221 |
<!-- Main card --> |
| 222 |
<div class="importify-card"> |
| 223 |
<div class="importify-card__stripe importify-card__stripe--warning"></div> |
| 224 |
<div class="importify-card__body"> |
| 225 |
|
| 226 |
<div class="importify-check-list"> |
| 227 |
<?php |
| 228 |
$first_non_pass_index = null; |
| 229 |
foreach ($checks as $i => $c) { if ($c['type'] !== 'pass') { $first_non_pass_index = $i; break; } } |
| 230 |
foreach ($checks as $i => $c): |
| 231 |
$is_pass = $c['type'] === 'pass'; |
| 232 |
$is_fail = $c['type'] === 'fail'; |
| 233 |
$is_warn = $c['type'] === 'warn'; |
| 234 |
$icon_name = $is_pass ? $c['icon_pass'] : $c['icon_fail']; |
| 235 |
$icon_cls = $is_pass ? 'importify-check-icon--pass' : ($is_fail ? 'importify-check-icon--fail' : 'importify-check-icon--warn'); |
| 236 |
$row_cls = $is_fail ? ' importify-check-row--fail' : ($is_warn ? ' importify-check-row--warn' : ' importify-check-row--pass'); |
| 237 |
$pill_cls = importify_pill_class_for($c); |
| 238 |
?> |
| 239 |
<div class="importify-check-row<?php echo $row_cls; ?>"> |
| 240 |
<div class="importify-check-row__main"> |
| 241 |
<div class="importify-check-left"> |
| 242 |
<div class="importify-check-icon <?php echo $icon_cls; ?>"> |
| 243 |
<span class="material-symbols-outlined material-symbols-outlined--filled"><?php echo esc_attr($icon_name); ?></span> |
| 244 |
</div> |
| 245 |
<div class="importify-check-text"> |
| 246 |
<h3 class="importify-check-text__name"><?php echo esc_html($c['name']); ?></h3> |
| 247 |
<p class="importify-check-text__desc"><?php echo esc_html($c['desc']); ?></p> |
| 248 |
</div> |
| 249 |
</div> |
| 250 |
<div class="importify-check-right"> |
| 251 |
<span class="importify-pill <?php echo $pill_cls; ?>"><?php echo esc_html($c['value']); ?></span> |
| 252 |
<?php if (!$is_pass): ?> |
| 253 |
<button type="button" class="importify-btn--link" data-fix-toggle="fix-<?php echo $i; ?>">How to fix</button> |
| 254 |
<?php endif; ?> |
| 255 |
</div> |
| 256 |
</div> |
| 257 |
|
| 258 |
<?php if (!$is_pass && !empty($c['steps'])): |
| 259 |
$is_first_open = ($i === $first_non_pass_index); |
| 260 |
?> |
| 261 |
<div class="importify-fix-panel<?php echo $is_first_open ? ' importify-fix-panel--open' : ''; ?>" id="fix-<?php echo $i; ?>"> |
| 262 |
<h3>Fixing your <?php echo esc_html($c['name']); ?></h3> |
| 263 |
<div class="importify-fix-steps"> |
| 264 |
<?php $n = 1; foreach ($c['steps'] as $step): if (empty($step)) continue; ?> |
| 265 |
<div class="importify-fix-step"> |
| 266 |
<span class="importify-fix-step__num"><?php echo $n++; ?></span> |
| 267 |
<p><?php echo wp_kses($step, array('code'=>array(),'em'=>array(),'strong'=>array())); ?></p> |
| 268 |
</div> |
| 269 |
<?php endforeach; ?> |
| 270 |
<?php if (!empty($c['url'])): ?> |
| 271 |
<a class="importify-fix-link" href="<?php echo esc_url($c['url']); ?>" target="_blank" rel="noopener noreferrer"> |
| 272 |
View full guide |
| 273 |
<span class="material-symbols-outlined">arrow_forward</span> |
| 274 |
</a> |
| 275 |
<?php endif; ?> |
| 276 |
</div> |
| 277 |
</div> |
| 278 |
<?php endif; ?> |
| 279 |
</div> |
| 280 |
<?php endforeach; ?> |
| 281 |
</div> |
| 282 |
|
| 283 |
<div class="importify-footer-actions"> |
| 284 |
<a href="<?php echo $btn; ?>" target="_blank" rel="noopener noreferrer" class="importify-btn importify-btn--secondary"> |
| 285 |
Skip and Proceed to Dashboard |
| 286 |
</a> |
| 287 |
<a href="#" onclick="window.location.reload();return false;" class="importify-btn importify-btn--primary"> |
| 288 |
<span class="material-symbols-outlined">refresh</span> |
| 289 |
Re-run System Checks |
| 290 |
</a> |
| 291 |
</div> |
| 292 |
|
| 293 |
</div> |
| 294 |
</div> |
| 295 |
|
| 296 |
<?php endif; ?> |
| 297 |
|
| 298 |
<p class="importify-version">Importify Plugin v<?php echo esc_html(IMPORTIFY_VERSION); ?></p> |
| 299 |
|
| 300 |
</div><!-- /.importify-container --> |
| 301 |
</div><!-- /#importify-setup-wrap --> |
| 302 |
|
| 303 |
<script> |
| 304 |
/* How-to-fix toggle — delegated so it survives any DOM re-render. */ |
| 305 |
(function () { |
| 306 |
document.addEventListener('click', function (e) { |
| 307 |
var trigger = e.target.closest('[data-fix-toggle]'); |
| 308 |
if (!trigger) return; |
| 309 |
var panel = document.getElementById(trigger.getAttribute('data-fix-toggle')); |
| 310 |
if (!panel) return; |
| 311 |
var isOpen = panel.classList.toggle('importify-fix-panel--open'); |
| 312 |
trigger.textContent = isOpen ? 'Hide' : 'How to fix'; |
| 313 |
}); |
| 314 |
})(); |
| 315 |
</script> |
| 316 |
|