| 映星教育/snippet-5-training.php | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| 添越智/产品详情页简码 | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
Ó³ÐǽÌÓý/snippet-5-training.php
@@ -19,7 +19,12 @@ ============================================================ */ add_action('template_redirect', function () { if (!empty($_GET['im_training_token'])) { if (!defined('DONOTCACHEPAGE')) { define('DONOTCACHEPAGE', true); } nocache_headers(); header('Cache-Control: private, no-store, no-cache, must-revalidate, max-age=0'); header('Pragma: no-cache'); } }, 1); @@ -98,6 +103,20 @@ .im-tr-btn-loading::after{content:"";position:absolute;width:20px;height:20px;top:50%;left:50%;margin:-10px 0 0 -10px;border:3px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:imTrSpin .6s linear infinite} </style>'; echo '<script>var imTrAjaxUrl="' . esc_url(admin_url('admin-ajax.php')) . '";</script>'; } /* ============================================================ AJAX: Fresh nonce (avoids stale nonce from full-page cache / long sessions) ============================================================ */ add_action('wp_ajax_im_training_refresh_nonce', 'im_ajax_training_refresh_nonce'); add_action('wp_ajax_nopriv_im_training_refresh_nonce', 'im_ajax_training_refresh_nonce'); function im_ajax_training_refresh_nonce() { $token = sanitize_text_field($_POST['im_training_token'] ?? ''); if (!$token || !IM_Candidate::get_by_training_token($token)) { wp_send_json_error(['message' => 'Invalid or expired training link.']); } wp_send_json_success(['nonce' => wp_create_nonce('im_training_' . $token)]); } /* ============================================================ @@ -193,7 +212,6 @@ endif; $name = esc_html($candidate->preferred_name ?: $candidate->first_name); $nonce = wp_create_nonce('im_training_' . $token_str); $total = count($training_posts); // Build training data for JS @@ -501,15 +519,30 @@ document.getElementById('im-tr-progress-text').textContent = 'Progress: ' + completed + ' / ' + TOTAL; } function submitTrainingComplete() { var fd = new FormData(); fd.append('action', 'im_training_complete'); fd.append('im_training_token', '<?= esc_js($token_str) ?>'); fd.append('im_nonce', '<?= esc_js($nonce) ?>'); var imTrToken = '<?= esc_js($token_str) ?>'; fetch(imTrAjaxUrl, { method: 'POST', body: fd }) function submitTrainingComplete() { var refresh = new FormData(); refresh.append('action', 'im_training_refresh_nonce'); refresh.append('im_training_token', imTrToken); fetch(imTrAjaxUrl, { method: 'POST', body: refresh, credentials: 'same-origin' }) .then(function (r) { return r.json(); }) .then(function (nr) { if (!nr.success || !nr.data || !nr.data.nonce) { alert((nr.data && nr.data.message) || 'Security check failed. Please refresh the page and try again.'); return; } var fd = new FormData(); fd.append('action', 'im_training_complete'); fd.append('im_training_token', imTrToken); fd.append('im_nonce', nr.data.nonce); return fetch(imTrAjaxUrl, { method: 'POST', body: fd, credentials: 'same-origin' }); }) .then(function (r) { return r ? r.json() : null; }) .then(function (res) { if (!res) return; if (res.success) { var page = document.getElementById('im-tr-page'); page.innerHTML = '<div class="im-tr-center im-tr-fade-in">' ÌíÔ½ÖÇ/²úÆ·ÏêÇéÒ³¼òÂë
New file @@ -0,0 +1,179 @@ // 产åè§æ ¼è¡¨æ ¼ç®ç function product_spec_table_shortcode() { $post_id = get_the_ID(); $tab_top_title = get_field( 'tab_top_title', $post_id ); $table_left_title = get_field( 'table_left_title', $post_id ); $specifications_table = get_field( 'specifications_table', $post_id ); if ( empty( $specifications_table ) ) { return ''; } $row_count = count( $specifications_table ); ob_start(); ?> <div class="pst-wrapper"> <table class="pst-table" cellspacing="0" cellpadding="0"> <colgroup> <col style="width: 90px;"> <col style="width: 210px;"> <col> </colgroup> <thead> <?php if ( $tab_top_title ) : ?> <tr> <th class="pst-top-title" colspan="3"> <?php echo esc_html( $tab_top_title ); ?> </th> </tr> <?php endif; ?> </thead> <tbody> <?php foreach ( $specifications_table as $index => $row ) : $cell_bg = '#ffffff'; $key_val = isset( $row['key'] ) ? esc_html( $row['key'] ) : ''; $val_val = isset( $row['value'] ) ? esc_html( $row['value'] ) : ''; ?> <tr> <?php if ( $index === 0 ) : ?> <td class="pst-left-title" rowspan="<?php echo esc_attr( $row_count ); ?>" > <span><?php echo esc_html( $table_left_title ); ?></span> </td> <?php endif; ?> <td class="pst-key" style="background-color: <?php echo esc_attr( $cell_bg ); ?>;" ><?php echo $key_val; ?></td> <td class="pst-value" style="background-color: <?php echo esc_attr( $cell_bg ); ?>;" ><?php echo nl2br( $val_val ); ?></td> </tr> <?php endforeach; ?> </tbody> </table> </div> <style> .pst-wrapper { width: 100%; overflow-x: auto; } .pst-table { width: 100%; border-collapse: collapse; table-layout: fixed; border: 1px solid #e6e6e6; } .pst-table .pst-top-title { background-color: #ffffff; color: #333333; text-align: center; font-size: 26px; font-weight: 600; padding: 15px 19px; border-bottom: 1px solid #eeeeee; } .pst-table .pst-left-title { background-color: #ffffff; color: #333333; text-align: center; vertical-align: middle; border-right: 1px solid #e6e6e6; border-bottom: 1px solid #eeeeee; padding: 0; } .pst-table .pst-left-title span { display: block; font-size: 20px; line-height: 1.5; writing-mode: vertical-rl; text-orientation: mixed; transform: rotate(180deg); white-space: nowrap; margin: auto; } .pst-table .pst-key { font-size: 15px; color: #333333; padding: 19px; vertical-align: middle; word-break: break-word; white-space: pre-wrap; border-right: 1px solid #e6e6e6; border-bottom: 1px solid #eeeeee; } .pst-table .pst-value { font-size: 15px; color: #333333; padding: 19px; vertical-align: middle; word-break: break-word; white-space: pre-wrap; border-bottom: 1px solid #eeeeee; } .pst-table tr:last-child .pst-key, .pst-table tr:last-child .pst-value { border-bottom: none; } @media (max-width: 768px) { .pst-table { min-width: 600px; } .pst-table .pst-top-title { font-size: 20px; padding: 12px 14px; } .pst-table .pst-left-title span { font-size: 16px; line-height: 1.4; } .pst-table .pst-key, .pst-table .pst-value { font-size: 14px; padding: 12px; line-height: 1.6; } } @media (max-width: 480px) { .pst-table { min-width: 520px; } .pst-table .pst-top-title { font-size: 18px; padding: 10px 12px; } .pst-table .pst-left-title span { font-size: 14px; } .pst-table .pst-key, .pst-table .pst-value { font-size: 13px; padding: 10px; } } </style> <?php return ob_get_clean(); } add_shortcode( 'product_spec_table', 'product_spec_table_shortcode' );