403Webshell
Server IP : 121.121.20.254  /  Your IP : 216.73.217.51
Web Server : Microsoft-IIS/10.0
System : Windows NT WEB-SERVER 10.0 build 20348 (Windows Server 2022) AMD64
User : IUSR ( 0)
PHP Version : 8.3.28
Disable Function : NONE
MySQL : ON  |  cURL : ON  |  WGET : OFF  |  Perl : OFF  |  Python : OFF  |  Sudo : OFF  |  Pkexec : OFF
Directory :  C:/Program Files/MariaDB 10.6/data/wmcert/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : C:/Program Files/MariaDB 10.6/data/wmcert/wp_snippets.ibd
����������ުDD@��������������������������&&������������������������ުD!%��������a�5�Da�5�Tl-����������ުD���������������������������������i������������������������������������������������������������������������������������������������������������������������������������������������������i�	
����
���������������������������������������������������������������������������������������������i������������������������������������������������������������������������������������������������������������������������������������������������������i���������������������������������������������������������������������������������������������������������������������������������������������������������i������������������������������������������������������������������������������������������������������������������������������������������������������i����������������������������������������������������������������������������������������������������������������������������������ު�����������…�E�D����D�D2infimumsupremum��	!�΀
pc�…�U������������…�E�D̀�	"�&�DrD�Zinfimumsupremum+global�	��front-end� )global�(��content�0global�86global�@�psite-footer-js�Hglobal�Pglobal�	Xglobal�
`global�hglobal�pglobal�
xglobal��global���Dsite-css�p�0�c�…�����������ÿ�E�DX�#a��D�D2`infimumsupremum���� ��(F��0���8���@p��H�ր�P��X��
`*��h��p�K��x�䁀
�����	�����p���cÿ����������e��n
D?�/**
 * FRONTEND PDF UPLOAD -> Create Post with PDF Viewer + QR + Store Record In Custom Table
 * Shortcode: [pdf_frontend_upload]
 *
 * Added:
 * - Custom "Download QR Image" button
 * - Downloads QR + Serial Number title as PNG
 * - Fixed duplicate serial display
 * - Added is_active column for soft delete support
 */

if (!defined('ABSPATH')) exit;

/** =========================
 * SETTINGS
 * ========================= */
if (!defined('KAYA_INV_SHOW_FILE_URL')) {
  define('KAYA_INV_SHOW_FILE_URL', true);
}
if (!defined('KAYA_INV_QR_FILENAME_PREFIX')) {
  define('KAYA_INV_QR_FILENAME_PREFIX', 'QR-');
}

/** =========================
 * CREATE / UPDATE CERTIFICATE TABLE
 * ========================= */
function kaya_create_certificates_table() {
  global $wpdb;

  $table_name = $wpdb->prefix . 'kaya_certificates';
  $charset_collate = $wpdb->get_charset_collate();

  require_once ABSPATH . 'wp-admin/includes/upgrade.php';

  $sql = "CREATE TABLE {$table_name} (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    post_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
    serial_number VARCHAR(255) NOT NULL DEFAULT '',
    category_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
    category_slug VARCHAR(200) NOT NULL DEFAULT '',
    pdf_url TEXT NOT NULL,
    today_date DATE DEFAULT NULL,
    expired_date DATE DEFAULT NULL,
    is_active CHAR(1) NOT NULL DEFAULT 'T',
    created_by BIGINT UNSIGNED NOT NULL DEFAULT 0,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (id),
    KEY post_id (post_id),
    KEY serial_number (serial_number),
    KEY category_id (category_id),
    KEY today_date (today_date),
    KEY expired_date (expired_date),
    KEY is_active (is_active),
    KEY created_by (created_by)
  ) {$charset_collate};";

  dbDelta($sql);

  // Backward compatibility: serial_number
  $serial_col = $wpdb->get_var($wpdb->prepare(
    "SHOW COLUMNS FROM {$table_name} LIKE %s",
    'serial_number'
  ));

  if (!$serial_col) {
    $wpdb->query("ALTER TABLE {$table_name} ADD COLUMN serial_number VARCHAR(255) NOT NULL DEFAULT '' AFTER post_id");
  }

  // Backward compatibility: is_active
  $active_col = $wpdb->get_var($wpdb->prepare(
    "SHOW COLUMNS FROM {$table_name} LIKE %s",
    'is_active'
  ));

  if (!$active_col) {
    $wpdb->query("ALTER TABLE {$table_name} ADD COLUMN is_active CHAR(1) NOT NULL DEFAULT 'T' AFTER expired_date");
  }

  // Update old existing rows to T
  $wpdb->query("UPDATE {$table_name} SET is_active = 'T' WHERE is_active IS NULL OR is_active = ''");

  // Ensure updated_at auto-updates where supported
  $wpdb->query("
    ALTER TABLE {$table_name}
    MODIFY updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
    ON UPDATE CURRENT_TIMESTAMP
  ");
}

/** Add a CSS class to generated certificate posts */
add_filter('post_class', function($classes, $class, $post_id){
  if (get_post_meta($post_id, '_kaya_invoice_post', true)) {
    $classes[] = 'kaya-invoice-post';
    $classes[] = 'kaya-invoice-post--v10';
  }
  return $classes;
}, 10, 3);

/** Shortcode */
function frontend_pdf_uploader_kaya_qr() {

  kaya_create_certificates_table();

  if (!is_user_logged_in()) {
    return '<div class="kaya-up-alert kaya-up-alert--warn">Please login to upload PDF.</div>';
  }

  $current_user = wp_get_current_user();

  if (!array_intersect(['administrator','editor'], (array) $current_user->roles)) {
    return '<div class="kaya-up-alert kaya-up-alert--err">Only administrators or editors can upload certificates.</div>';
  }

  $flash = '';
  $BASE_REL = 'FILES';
  $max_mb_text = '100 MB';

  if (
    isset($_POST['submit_pdf'], $_POST['kaya_pdf_upload_nonce']) &&
    wp_verify_nonce($_POST['kaya_pdf_upload_nonce'], 'kaya_pdf_upload_action')
  ) {
    if (empty($_FILES['pdf_file']['name'])) {
      $flash = '<div class="kaya-up-alert kaya-up-alert--err">Please select a PDF file.</div>';
    } else {
      $serial_number = sanitize_text_field(wp_unslash($_POST['serial_number'] ?? ''));
      $category_id   = absint($_POST['post_category'] ?? 0);
      $today_date    = sanitize_text_field(wp_unslash($_POST['today_date'] ?? ''));
      $expired_date  = sanitize_text_field(wp_unslash($_POST['expired_date'] ?? ''));
      $category      = get_term($category_id, 'category');

      if ($serial_number === '') {
        $flash = '<div class="kaya-up-alert kaya-up-alert--err">Please fill in Serial Number.</div>';
      } elseif (!$category || is_wp_error($category)) {
        $flash = '<div class="kaya-up-alert kaya-up-alert--err">Invalid category.</div>';
      } elseif ($today_date === '' || $expired_date === '') {
        $flash = '<div class="kaya-up-alert kaya-up-alert--err">Please fill in Today Date and Expired Date.</div>';
      } elseif (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $today_date) || !preg_match('/^\d{4}-\d{2}-\d{2}$/', $expired_date)) {
        $flash = '<div class="kaya-up-alert kaya-up-alert--err">Invalid date format.</div>';
      } else {
        $slug = sanitize_title($category->slug);

        if ($slug === '') {
          $flash = '<div class="kaya-up-alert kaya-up-alert--err">Category slug is empty.</div>';
        } else {
          $folder_name = strtoupper($slug);

          $target_dir = rtrim(ABSPATH, '/\\') . DIRECTORY_SEPARATOR
                      . trim($BASE_REL, '/\\') . DIRECTORY_SEPARATOR
                      . $folder_name . DIRECTORY_SEPARATOR;

          $base_url = home_url('/' . trim($BASE_REL, '/\\') . '/' . $folder_name . '/');

          if (!is_dir($target_dir)) {
            $flash = '<div class="kaya-up-alert kaya-up-alert--err"><b>Folder does not exist</b><div class="kaya-up-small">'
                   . esc_html($target_dir) . '</div></div>';
          } elseif (!is_writable($target_dir)) {
            $flash = '<div class="kaya-up-alert kaya-up-alert--err"><b>Folder not writable</b><div class="kaya-up-small">'
                   . esc_html($target_dir) . '</div></div>';
          } else {
            $file  = $_FILES['pdf_file'];
            $check = wp_check_filetype_and_ext($file['tmp_name'], $file['name']);
            $ext   = strtolower((string)($check['ext'] ?? ''));

            if ($ext !== 'pdf') {
              $flash = '<div class="kaya-up-alert kaya-up-alert--err">Only PDF allowed.</div>';
            } else {
              $random      = wp_generate_password(20, false, false);
              $filename    = strtolower($random) . '.pdf';
              $target_path = $target_dir . $filename;

              if (!@move_uploaded_file($file['tmp_name'], $target_path)) {
                $err = error_get_last();
                $flash  = '<div class="kaya-up-alert kaya-up-alert--err"><b>Upload failed while moving file</b>.</div>';
                $flash .= '<div class="kaya-up-debug"><b>Target:</b> ' . esc_html($target_path) . '<br><pre>'
                        . esc_html(print_r($err, true)) . '</pre></div>';
              } else {
                $pdf_url   = $base_url . rawurlencode($filename);
                $row_title = $serial_number;
                $qr_box_id = 'kaya-qr-box-' . wp_generate_password(8, false, false);

                $qepw = '[qepw_pdf_viewer file="' . esc_url($pdf_url) . '"]';

                $kaya_qr = '
                  <div class="kaya-qr-download-wrap" id="' . esc_attr($qr_box_id) . '">
                    <div class="kaya-qr-download-title">' . esc_html($serial_number) . '</div>
                    <div class="kaya-qr-download-inner">
                      [kaya_qrcode content="' . esc_url($pdf_url) . '" dynamic_content="0" download_button="0" download_align="aligncenter"]
                    </div>
                  </div>

                  <div class="kaya-qr-download-actions">
                    <button type="button"
                            class="kaya-up-btn kaya-up-btn--primary kaya-download-qr-btn"
                            data-target="' . esc_attr($qr_box_id) . '"
                            data-filename="' . esc_attr(sanitize_file_name($serial_number)) . '-qr.png">
                      Download QR Image
                    </button>
                  </div>
                ';

                $content = '<div class="kaya-inv-page kaya-inv-page--v10">' .
                  '<div class="kaya-inv-viewer kaya-inv-viewer--qepw">' .
                    $qepw .
                  '</div>' .
                  '<div class="kaya-inv-qr kaya-inv-qr--kaya">' .
                    '<div class="kaya-inv-qrbox">' .
                      $kaya_qr .
                    '</div>';

                $content .= '<div class="kaya-inv-meta kaya-inv-serial-number">' .
                              '<div class="kaya-inv-label">Serial Number</div>' .
                              '<div class="kaya-inv-text">' . esc_html($serial_number) . '</div>' .
                            '</div>';

                if (KAYA_INV_SHOW_FILE_URL) {
                  $content .= '<div class="kaya-inv-meta kaya-inv-urlwrap">' .
                                '<div class="kaya-inv-label">File URL</div>' .
                                '<div class="kaya-inv-url">' . esc_html($pdf_url) . '</div>' .
                              '</div>';
                }

                $content .= '<div class="kaya-inv-meta kaya-inv-cert-availability">' .
                              '<div class="kaya-inv-label">Certificate Availability</div>' .
                              '<div class="kaya-inv-text">' . esc_html($today_date) . ' - ' . esc_html($expired_date) . '</div>' .
                            '</div>';

                $content .= '<div class="kaya-inv-meta kaya-inv-cert-days">' .
                              '<div class="kaya-inv-label">Days Left Until Expired</div>' .
                              '<div class="kaya-inv-cert-row">' .
                                '<div class="kaya-inv-text">' .
                                  '<span class="kaya-cert-countdown" data-expire="' . esc_attr($expired_date) . '">Checking...</span>' .
                                '</div>' .
                                '<span class="kaya-cert-status">Checking...</span>' .
                              '</div>' .
                            '</div>';

                $content .= '</div></div>';

                $post_id = wp_insert_post(array(
                  'post_title'    => $row_title,
                  'post_content'  => $content,
                  'post_status'   => 'publish',
                  'post_type'     => 'post',
                  'post_category' => array($category_id),
                  'post_author'   => get_current_user_id()
                ), true);

                if (is_wp_error($post_id)) {
                  $flash = '<div class="kaya-up-alert kaya-up-alert--err">Post creation failed: '
                         . esc_html($post_id->get_error_message()) . '</div>';
                } else {
                  update_post_meta($post_id, '_kaya_invoice_post', 1);
                  update_post_meta($post_id, '_kaya_invoice_pdf_url', esc_url_raw($pdf_url));
                  update_post_meta($post_id, '_kaya_serial_number', $serial_number);
                  update_post_meta($post_id, '_kaya_today_date', $today_date);
                  update_post_meta($post_id, '_kaya_expired_date', $expired_date);

                  global $wpdb;
                  $table_name = $wpdb->prefix . 'kaya_certificates';

                  $inserted = $wpdb->insert(
                    $table_name,
                    array(
                      'post_id'       => $post_id,
                      'serial_number' => $serial_number,
                      'category_id'   => $category_id,
                      'category_slug' => $slug,
                      'pdf_url'       => esc_url_raw($pdf_url),
                      'today_date'    => $today_date,
                      'expired_date'  => $expired_date,
                      'is_active'     => 'T',
                      'created_by'    => get_current_user_id(),
                    ),
                    array(
                      '%d',
                      '%s',
                      '%d',
                      '%s',
                      '%s',
                      '%s',
                      '%s',
                      '%s',
                      '%d',
                    )
                  );

                  if ($inserted === false) {
                    $flash = '<div class="kaya-up-alert kaya-up-alert--err"><b>Upload succeeded but DB insert failed.</b><div class="kaya-up-small">'
                           . esc_html($wpdb->last_error) . '</div>'
                           . '<div class="kaya-up-actions">'
                           . '<a class="kaya-up-btn kaya-up-btn--primary" href="' . esc_url(get_permalink($post_id)) . '" target="_blank" rel="noopener">View Page</a>'
                           . '<a class="kaya-up-btn kaya-up-btn--ghost" href="' . esc_url($pdf_url) . '" target="_blank" rel="noopener">Open PDF</a>'
                           . '</div></div>';
                  } else {
                    $flash = '<div class="kaya-up-alert kaya-up-alert--ok">
                      <b>Upload Successful!</b>
                      <div class="kaya-up-actions">
                        <a class="kaya-up-btn kaya-up-btn--primary" href="' . esc_url(get_permalink($post_id)) . '" target="_blank" rel="noopener">View Page</a>
                        <a class="kaya-up-btn kaya-up-btn--ghost" href="' . esc_url($pdf_url) . '" target="_blank" rel="noopener">Open PDF</a>
                      </div>
                    </div>';
                  }
                }
              }
            }
          }
        }
      }
    }
  }

  $default_today = current_time('Y-m-d');

  ob_start();
  ?>
  <div class="kaya-up">
    <div class="kaya-up-shell">
      <?php echo $flash; ?>

      <div class="kaya-up-card">
        <form method="post" enctype="multipart/form-data">
          <?php wp_nonce_field('kaya_pdf_upload_action', 'kaya_pdf_upload_nonce'); ?>

          <div class="kaya-up-top">
            <div class="kaya-up-field">
              <label>Serial Number</label>
              <input type="text" name="serial_number" placeholder="e.g. WM-2026-000123" required>
            </div>

            <div class="kaya-up-field">
              <label>Category</label>
              <select name="post_category" required>
                <?php
                $categories = get_terms(array(
                  'taxonomy'   => 'category',
                  'hide_empty' => false
                ));
                if (!is_wp_error($categories) && $categories) {
                  foreach ($categories as $cat) {
                    echo '<option value="' . esc_attr($cat->term_id) . '">' . esc_html($cat->name) . '</option>';
                  }
                }
                ?>
              </select>
            </div>
          </div>

          <div class="kaya-up-top">
            <div class="kaya-up-field">
              <label>Today Date</label>
              <input type="date" name="today_date" value="<?php echo esc_attr($default_today); ?>" required>
            </div>

            <div class="kaya-up-field">
              <label>Expired Date</label>
              <input type="date" name="expired_date" required>
            </div>
          </div>

          <div class="kaya-up-drop" id="kayaDrop">
            <div class="kaya-up-illu" aria-hidden="true">
              <svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
                <path d="M14 2v6h6"/>
                <path d="M12 18v-6"/>
                <path d="M9.5 14.5 12 12l2.5 2.5"/>
              </svg>
            </div>

            <div class="kaya-up-title">Drag &amp; drop your file</div>
            <div class="kaya-up-or">or</div>

            <button type="button" class="kaya-up-btn kaya-up-btn--primary" id="kayaPickBtn">
              Upload PDF
            </button>

            <div class="kaya-up-note">PDF up to <?php echo esc_html($max_mb_text); ?></div>

            <div class="kaya-up-filehint" id="kayaFileHint" style="display:none;">
              <spae��n��l�����	��vE�D9]�
3_�!infimumsupremum
4��&��Make upload filenames lowercaseMakes sure that image and file uploads have lowercase filenames.

This is a sample snippet. Feel free to use it, edit it, or remove it.add_filter( 'sanitize_file_name', 'mb_strtolower' );sample, mediaglobal��
���TIڀ	s��c��Disable admin barTurns off the WordPress admin bar for everyone except administrators.

This is a sample snippet. Feel free to use it, edit it, or remove it.add_action( 'wp', function () {
	if ( ! current_user_can( 'manage_options' ) ) {
		show_admin_bar( false );
	}
} );sample, admin-barfront-end��
���t�����r
 ��Allow smiliesAllows smiley conversion in obscure places.

This is a sample snippet. Feel free to use it, edit it, or remove it.add_filter( 'widget_text', 'convert_smilies' );
add_filter( 'the_title', 'convert_smilies' );
add_filter( 'wp_title', 'convert_smilies' );
add_filter( 'get_bloginfo', 'convert_smilies' );sampleglobal��
���TIڀ
��(���Current yearShortcode for inserting the current year into a post or page..

This is a sample snippet. Feel free to use it, edit it, or remove it.<?php echo date( 'Y' ); ?>sample, datescontent��
���TIڀ�30���Frontend PDF Upload Shortcode For Categories FolderD&L�global��
���X��8s��Countdown Codedocument.addEventListener('DOMContentLoaded', function () {
  const items = document.querySelectorAll('.kaya-cert-countdown[data-expire]');
  if (!items.length) return;

  const MS_PER_DAY = 1000 * 60 * 60 * 24;

  items.forEach(function(el){
    const expireRaw = el.getAttribute('data-expire');
    if (!expireRaw) return;

    const expireDate = new Date(expireRaw + 'T00:00:00');
    const today = new Date();

    expireDate.setHours(0,0,0,0);
    today.setHours(0,0,0,0);

    const diff = expireDate.getTime() - today.getTime();
    const days = Math.floor(diff / MS_PER_DAY);

    el.classList.remove('is-active', 'is-soon', 'is-expired');

    const parentMeta = el.closest('.kaya-inv-meta');
    const statusEl = parentMeta ? parentMeta.querySelector('.kaya-cert-status') : null;

    if (statusEl) {
      statusEl.classList.remove('is-active', 'is-soon', 'is-expired');
    }

    if (days < 0) {
      el.textContent = 'Expired';
      el.classList.add('is-expired');

      if (statusEl) {
        statusEl.textContent = 'Expired';
        statusEl.classList.add('is-expired');
      }
    } else if (days === 0) {
      el.textContent = 'Expires Today';
      el.classList.add('is-soon');

      if (statusEl) {
        statusEl.textContent = 'Expires Today';
        statusEl.classList.add('is-soon');
      }
    } else if (days <= 30) {
      el.textContent = days + ' day' + (days === 1 ? '' : 's');
      el.classList.add('is-soon');

      if (statusEl) {
        statusEl.textContent = 'Expiring Soon';
        statusEl.classList.add('is-soon');
      }
    } else {
      el.textContent = days + ' day' + (days === 1 ? '' : 's');
      el.classList.add('is-active');

      if (statusEl) {
        statusEl.textContent = 'Active';
        statusEl.classList.add('is-active');
      }
    }
  });
});site-footer-js��
��TvG�F�@
���Recent Certificates Tablefunction weldmaster_recent_certificates() {

    $args = array(
        'post_type' => 'post', // 如果你是自定义 post type, 改成 'certificate'
        'posts_per_page' => 5,
        'meta_key' => '_kaya_serial_number',
        'meta_compare' => 'EXISTS'
    );

    $query = new WP_Query($args);

    ob_start();

    if ( $query->have_posts() ) :

        echo '<div class="recent-certificates" style="background-color:#222; padding:20px; border-radius:6px;">';
        echo '<h3 style="color:white; margin-bottom:15px;">Recent Certificates</h3>';

        echo '<table class="certificate-table" style="width:100%; border-collapse:collapse; border:1px solid white;">';
        echo '<thead>
                <tr>
                    <th style="border:1px solid white; padding:10px; color:white; text-align:left;">Serial Number</th>
                    <th style="border:1px solid white; padding:10px; color:white; text-align:left;">Category</th>
                    <th style="border:1px solid white; padding:10px; color:white; text-align:left;">Issue Date</th>
                    <th style="border:1px solid white; padding:10px; color:white; text-align:left;">Expired Date</th>
                    <th style="border:1px solid white; padding:10px; color:white; text-align:left;">Status</th>
                </tr>
              </thead>';
        echo '<tbody>';

        while ( $query->have_posts() ) : $query->the_post();

            $serial = get_post_meta(get_the_ID(), '_kaya_serial_number', true);
            $issue = get_post_meta(get_the_ID(), '_kaya_today_date', true);
            $expiry = get_post_meta(get_the_ID(), '_kaya_expired_date', true);

            $category = get_the_category();
            $cat_name = $category ? $category[0]->name : 'Uncategorized';

            // 默认 Active
            $status = "Active";
            $status_color = "#4CAF50"; // 绿色
            $row_bg = "#333";           // 深灰背景让文字可读
            $text_color = "#FFFFFF";    // 白色文字

            // 过期
            if ( $expiry && strtotime($expiry) && strtotime($expiry) < time() ) {
                $status = "Expired";
                $status_color = "#FF5252"; // 红色
                $row_bg = "#555";          // 浅灰背景
                $text_color = "#FFFFFF";   // 白色文字
            }

            echo '<tr style="background-color:' . $row_bg . '; color:' . $text_color . ';">';
            echo '<td style="border:1px solid white; padding:8px; color:' . $text_color . ';">' . esc_html($serial) . '</td>';
            echo '<td style="border:1px solid white; padding:8px; color:' . $text_color . ';">' . esc_html($cat_name) . '</td>';
            echo '<td style="border:1px solid white; padding:8px; color:' . $text_color . ';">' . esc_html($issue) . '</td>';
            echo '<td style="border:1px solid white; padding:8px; color:' . $text_color . ';">' . esc_html($expiry) . '</td>';
            echo '<td style="border:1px solid white; padding:8px; font-weight:bold; color:' . $status_color . ';">' . $status . '</td>';
            echo '</tr>';

        endwhile;

        echo '</tbody></table></div>';

    else :
        echo '<p style="color:white;">No certificates found.</p>';
    endif;

    wp_reset_postdata();

    return ob_get_clean();
}

add_shortcode('recent_certificates', 'weldmaster_recent_certificates');global��
���V%ÀK�H���Create Table inside Database/**
 * KAYA CERTIFICATES TABLE SETUP
 * Run once / only when version changes
 */

if (!defined('ABSPATH')) exit;

if (!defined('KAYA_CERT_TABLE_VERSION')) {
  define('KAYA_CERT_TABLE_VERSION', '1.1.0');
}

/**
 * Create or upgrade certificate table
 */
function kaya_create_certificates_table() {
  global $wpdb;

  $table_name = $wpdb->prefix . 'kaya_certificates';
  $charset_collate = $wpdb->get_charset_collate();

  require_once ABSPATH . 'wp-admin/includes/upgrade.php';

  $sql = "CREATE TABLE {$table_name} (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    post_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
    serial_number VARCHAR(255) NOT NULL DEFAULT '',
    category_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
    category_slug VARCHAR(200) NOT NULL DEFAULT '',
    pdf_url TEXT NOT NULL,
    today_date DATE DEFAULT NULL,
    expired_date DATE DEFAULT NULL,

    renewal_of_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
    replaced_by_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
    version_no INT UNSIGNED NOT NULL DEFAULT 1,
    is_current CHAR(1) NOT NULL DEFAULT 'T',
    cert_status VARCHAR(20) NOT NULL DEFAULT 'active',

    is_active CHAR(1) NOT NULL DEFAULT 'T',
    created_by BIGINT UNSIGNED NOT NULL DEFAULT 0,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,

    PRIMARY KEY (id),
    KEY post_id (post_id),
    KEY serial_number (serial_number),
    KEY category_id (category_id),
    KEY today_date (today_date),
    KEY expired_date (expired_date),
    KEY renewal_of_id (renewal_of_id),
    KEY replaced_by_id (replaced_by_id),
    KEY version_no (version_no),
    KEY is_current (is_current),
    KEY cert_status (cert_status),
    KEY is_active (is_active),
    KEY created_by (created_by),
    KEY serial_current (serial_number(191), is_current, is_active)
  ) {$charset_collate};";

  dbDelta($sql);

  /**
   * Backward compatibility columns
   */
  $columns_to_check = [
    'serial_number'  => "ALTER TABLE {$table_name} ADD COLUMN serial_number VARCHAR(255) NOT NULL DEFAULT '' AFTER post_id",
    'is_active'      => "ALTER TABLE {$table_name} ADD COLUMN is_active CHAR(1) NOT NULL DEFAULT 'T' AFTER expired_date",
    'renewal_of_id'  => "ALTER TABLE {$table_name} ADD COLUMN renewal_of_id BIGINT UNSIGNED NOT NULL DEFAULT 0 AFTER expired_date",
    'replaced_by_id' => "ALTER TABLE {$table_name} ADD COLUMN replaced_by_id BIGINT UNSIGNED NOT NULL DEFAULT 0 AFTER renewal_of_id",
    'version_no'     => "ALTER TABLE {$table_name} ADD COLUMN version_no INT UNSIGNED NOT NULL DEFAULT 1 AFTER replaced_by_id",
    'is_current'     => "ALTER TABLE {$table_name} ADD COLUMN is_current CHAR(1) NOT NULL DEFAULT 'T' AFTER version_no",
    'cert_status'    => "ALTER TABLE {$table_name} ADD COLUMN cert_status VARCHAR(20) NOT NULL DEFAULT 'active' AFTER is_current",
  ];

  foreach ($columns_to_check as $column_name => $alter_sql) {
    $exists = $wpdb->get_var($wpdb->prepare(
      "SHOW COLUMNS FROM {$table_name} LIKE %s",
      $column_name
    ));

    if (!$exists) {
      $wpdb->query($alter_sql);
    }
  }

  /**
   * Old rows default values
   */
  $wpdb->query("UPDATE {$table_name} SET is_active = 'T' WHERE is_active IS NULL OR is_active = ''");
  $wpdb->query("UPDATE {$table_name} SET is_current = 'T' WHERE is_current IS NULL OR is_current = ''");
  $wpdb->query("UPDATE {$table_name} SET cert_status = 'active' WHERE cert_status IS NULL OR cert_status = ''");
  $wpdb->query("UPDATE {$table_name} SET version_no = 1 WHERE version_no IS NULL OR version_no = 0");
  $wpdb->query("UPDATE {$table_name} SET renewal_of_id = 0 WHERE renewal_of_id IS NULL");
  $wpdb->query("UPDATE {$table_name} SET replaced_by_id = 0 WHERE replaced_by_id IS NULL");

  /**
   * Auto-update updated_at
   */
  $wpdb->query("
    ALTER TABLE {$table_name}
    MODIFY updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
    ON UPDATE CURRENT_TIMESTAMP
  ");

  /**
   * Rebuild certificate status based on dates for current active rows
   * - active    : current and not yet expired
   * - expired   : current but expired
   * - superseded: not current
   */
  $today = current_time('Y-m-d');

  $wpdb->query("
    UPDATE {$table_name}
    SET cert_status = 'superseded'
    WHERE is_current = 'F'
  ");

  $wpdb->query($wpdb->prepare("
    UPDATE {$table_name}
    SET cert_status = 'expired'
    WHERE is_current = 'T'
      AND expired_date IS NOT NULL
      AND expired_date < %s
  ", $today));

  $wpdb->query($wpdb->prepare("
    UPDATE {$table_name}
    SET cert_status = 'active'
    WHERE is_current = 'T'
      AND (
        expired_date IS NULL
        OR expired_date >= %s
      )
  ", $today));

  /**
   * Fix historical duplicates:
   * For the same serial_number, keep only latest row as current.
   * Older rows become superseded.
   */
  $serials = $wpdb->get_col("
    SELECT serial_number
    FROM {$table_name}
    WHERE serial_number <> ''
    GROUP BY serial_number
    HAVING COUNT(*) > 1
  ");

  if (!empty($serials)) {
    foreach ($serials as $serial_number) {
      $rows = $wpdb->get_results(
        $wpdb->prepare("
          SELECT id
          FROM {$table_name}
          WHERE serial_number = %s
          ORDER BY
            COALESCE(today_date, '1000-01-01') DESC,
            id DESC
        ", $serial_number)
      );

      if (!empty($rows)) {
        $latest_id = (int) $rows[0]->id;

        $wpdb->update(
          $table_name,
          [
            'is_current'  => 'T',
            'cert_status' => 'active',
          ],
          ['id' => $latest_id],
          ['%s', '%s'],
          ['%d']
        );

        for ($i = 1; $i < count($rows); $i++) {
          $old_id = (int) $rows[$i]->id;

          $wpdb->update(
            $table_name,
            [
              'is_current'  => 'F',
              'cert_status' => 'superseded',
            ],
            ['id' => $old_id],
            ['%s', '%s'],
            ['%d']
          );
        }
      }
    }
  }
}

/**
 * Run only when version changes
 */
function kaya_maybe_upgrade_certificates_table() {
  $saved_version = get_option('kaya_cert_table_version', '');

  if ($saved_version === KAYA_CERT_TABLE_VERSION) {
    return;
  }

  kaya_create_certificates_table();
  update_option('kaya_cert_table_version', KAYA_CERT_TABLE_VERSION);
}

/**
 * Run on init, but only does real work once per version
 */
add_action('init', 'kaya_maybe_upgrade_certificates_table');global��
���b���
P]�	�PDF UploadD
&g
global��
���b&���!X�
�Profile Builder Login Logout Menuadd_filter('wp_nav_menu_items', 'my_wppb_login_logout_menu_item', 10, 2);
function my_wppb_login_logout_menu_item($items, $args) {

    if ($args->theme_location !== 'primary') {
        return $items;
    }

    $login_page_url  = 'https://cert.weldmaster.my/?page_id=259';
    $logout_redirect = home_url('/');
    $logout_url      = wp_logout_url($logout_redirect);

    if (is_user_logged_in()) {
        $current_user = wp_get_current_user();
        $name = $current_user->display_name ? $current_user->display_name : $current_user->user_login;

        $items .= '<li class="menu-item menu-item-user-name">
            <a href="#">HI, ' . esc_html($name) . '</a>
        </li>';

        $items .= '<li class="menu-item menu-item-logout">
            <a href="' . esc_url($logout_url) . '">LOGOUT</a>
        </li>';
    } else {
        $items .= '<li class="menu-item menu-item-login">
            <a href="' . esc_url($login_page_url) . '">LOGIN</a>
        </li>';
    }

    return $items;
}global��
���`��p�c��v��h���������e��n
D����n>Selected:</span> <b id="kayaFileName"></b>
            </div>

            <input type="file" name="pdf_file" accept="application/pdf" required id="kayaFileInput">
          </div>

          <div style="margin-top:14px; display:flex; justify-content:center;">
            <button type="submit" name="submit_pdf" class="kaya-up-btn kaya-up-btn--primary" style="min-width:320px;">
              Submit Upload
            </button>
          </div>
        </form>
      </div>
    </div>
  </div>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>

  <script>
    (function(){
      const drop = document.getElementById('kayaDrop');
      const fileInput = document.getElementById('kayaFileInput');
      const pickBtn = document.getElementById('kayaPickBtn');
      const hint = document.getElementById('kayaFileHint');
      const nameEl = document.getElementById('kayaFileName');

      if (drop && fileInput) {
        function showFileName(){
          const f = fileInput.files && fileInput.files[0];
          if (!f) {
            if (hint) hint.style.display = 'none';
            return;
          }
          if (hint) hint.style.display = 'block';
          if (nameEl) nameEl.textContent = f.name;
        }

        if (pickBtn){
          pickBtn.addEventListener('click', function(e){
            e.preventDefault();
            fileInput.click();
          });
        }

        fileInput.addEventListener('change', showFileName);

        ['dragenter','dragover'].forEach(function(evt){
          drop.addEventListener(evt, function(e){
            e.preventDefault();
            e.stopPropagation();
            drop.classList.add('is-drag');
          });
        });

        ['dragleave','drop'].forEach(function(evt){
          drop.addEventListener(evt, function(e){
            e.preventDefault();
            e.stopPropagation();
            drop.classList.remove('is-drag');
          });
        });

        drop.addEventListener('drop', function(e){
          if (!e.dataTransfer || !e.dataTransfer.files || !e.dataTransfer.files.length) return;
          fileInput.files = e.dataTransfer.files;
          showFileName();
        });
      }

      document.addEventListener('click', function(e){
        const btn = e.target.closest('.kaya-download-qr-btn');
        if (!btn) return;

        const targetId = btn.getAttribute('data-target');
        const filename = btn.getAttribute('data-filename') || 'qr-image.png';
        const box = document.getElementById(targetId);

        if (!box || typeof html2canvas === 'undefined') {
          alert('QR image downloader is not ready.');
          return;
        }

        html2canvas(box, {
          backgroundColor: '#ffffff',
          scale: 2,
          useCORS: true
        }).then(function(canvas){
          const link = document.createElement('a');
          link.download = filename;
          link.href = canvas.toDataURL('image/png');
          link.click();
        }).catch(function(err){
          console.error(err);
          alert('Failed to download QR image.');
        });
      });
    })();
  </script>
  <?php

  return ob_get_clean();
}

add_shortcode('pdf_frontend_upload', 'frontend_pdf_uploader_kaya_qr');e��nq1�		
���E�D='�
8,�!infimumsupremum�s��Countdown Codedocument.addEventListener('DOMContentLoaded', function () {
  const items = document.querySelectorAll('.kaya-cert-countdown[data-expire]');
  if (!items.length) return;

  const MS_PER_DAY = 1000 * 60 * 60 * 24;

  items.forEach(function(el){
    const expireRaw = el.getAttribute('data-expire');
    if (!expireRaw) return;

    const expireDate = new Date(expireRaw + 'T00:00:00');
    const today = new Date();

    expireDate.setHours(0,0,0,0);
    today.setHours(0,0,0,0);

    const diff = expireDate.getTime() - today.getTime();
    const days = Math.floor(diff / MS_PER_DAY);

    el.classList.remove('is-active', 'is-soon', 'is-expired');

    const parentMeta = el.closest('.kaya-inv-meta');
    const statusEl = parentMeta ? parentMeta.querySelector('.kaya-cert-status') : null;

    if (statusEl) {
      statusEl.classList.remove('is-active', 'is-soon', 'is-expired');
    }

    if (days < 0) {
      el.textContent = 'Expired';
      el.classList.add('is-expired');

      if (statusEl) {
        statusEl.textContent = 'Expired';
        statusEl.classList.add('is-expired');
      }
    } else if (days === 0) {
      el.textContent = 'Expires Today';
      el.classList.add('is-soon');

      if (statusEl) {
        statusEl.textContent = 'Expires Today';
        statusEl.classList.add('is-soon');
      }
    } else if (days <= 30) {
      el.textContent = days + ' day' + (days === 1 ? '' : 's');
      el.classList.add('is-soon');

      if (statusEl) {
        statusEl.textContent = 'Expiring Soon';
        statusEl.classList.add('is-soon');
      }
    } else {
      el.textContent = days + ' day' + (days === 1 ? '' : 's');
      el.classList.add('is-active');

      if (statusEl) {
        statusEl.textContent = 'Active';
        statusEl.classList.add('is-active');
      }
    }
  });
});site-footer-js��
��TvG���
��Recent Certificates Tablefunction weldmaster_recent_certificates() {

	$args = array(
		'post_type'      => 'post', // kalau custom post type, tukar sini
		'posts_per_page' => 5,
		'meta_key'       => '_kaya_serial_number',
		'meta_compare'   => 'EXISTS',
		'meta_query'     => array(
			array(
				'key'     => '_kaya_cert_status',
				'value'   => 'active',
			),
		),
	);

    $query = new WP_Query($args);

    ob_start();

    if ( $query->have_posts() ) :

        echo '<div class="recent-certificates" style="background-color:#222; padding:20px; border-radius:6px;">';
        echo '<h3 style="color:white; margin-bottom:15px;">Recent Certificates</h3>';

        echo '<table class="certificate-table" style="width:100%; border-collapse:collapse; border:1px solid white;">';
        echo '<thead>
                <tr>
                    <th style="border:1px solid white; padding:10px; color:white; text-align:left;">Serial Number</th>
                    <th style="border:1px solid white; padding:10px; color:white; text-align:left;">Category</th>
                    <th style="border:1px solid white; padding:10px; color:white; text-align:left;">Issue Date</th>
                    <th style="border:1px solid white; padding:10px; color:white; text-align:left;">Expired Date</th>
                    <th style="border:1px solid white; padding:10px; color:white; text-align:left;">Status</th>
                </tr>
              </thead>';
        echo '<tbody>';

        while ( $query->have_posts() ) : $query->the_post();

            $serial = get_post_meta(get_the_ID(), '_kaya_serial_number', true);
            $issue = get_post_meta(get_the_ID(), '_kaya_today_date', true);
            $expiry = get_post_meta(get_the_ID(), '_kaya_expired_date', true);

            $category = get_the_category();
            $cat_name = $category ? $category[0]->name : 'Uncategorized';

            // 默认 Active
            $status = "Active";
            $status_color = "#4CAF50"; // 绿色
            $row_bg = "#333";           // 深灰背景让文字可读
            $text_color = "#FFFFFF";    // 白色文字

            // 过期
            if ( $expiry && strtotime($expiry) && strtotime($expiry) < time() ) {
                $status = "Expired";
                $status_color = "#FF5252"; // 红色
                $row_bg = "#555";          // 浅灰背景
                $text_color = "#FFFFFF";   // 白色文字
            }

            echo '<tr style="background-color:' . $row_bg . '; color:' . $text_color . ';">';
            echo '<td style="border:1px solid white; padding:8px; color:' . $text_color . ';">' . esc_html($serial) . '</td>';
            echo '<td style="border:1px solid white; padding:8px; color:' . $text_color . ';">' . esc_html($cat_name) . '</td>';
            echo '<td style="border:1px solid white; padding:8px; color:' . $text_color . ';">' . esc_html($issue) . '</td>';
            echo '<td style="border:1px solid white; padding:8px; color:' . $text_color . ';">' . esc_html($expiry) . '</td>';
            echo '<td style="border:1px solid white; padding:8px; font-weight:bold; color:' . $status_color . ';">' . $status . '</td>';
            echo '</tr>';

        endwhile;

        echo '</tbody></table></div>';

    else :
        echo '<p style="color:white;">No certificates found.</p>';
    endif;

    wp_reset_postdata();

    return ob_get_clean();
}

add_shortcode('recent_certificates', 'weldmaster_recent_certificates');global��
���b�2�K� ���Create Table inside Database/**
 * KAYA CERTIFICATES TABLE SETUP
 * Run once / only when version changes
 */

if (!defined('ABSPATH')) exit;

if (!defined('KAYA_CERT_TABLE_VERSION')) {
  define('KAYA_CERT_TABLE_VERSION', '1.1.0');
}

/**
 * Create or upgrade certificate table
 */
function kaya_create_certificates_table() {
  global $wpdb;

  $table_name = $wpdb->prefix . 'kaya_certificates';
  $charset_collate = $wpdb->get_charset_collate();

  require_once ABSPATH . 'wp-admin/includes/upgrade.php';

  $sql = "CREATE TABLE {$table_name} (
    id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
    post_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
    serial_number VARCHAR(255) NOT NULL DEFAULT '',
    category_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
    category_slug VARCHAR(200) NOT NULL DEFAULT '',
    pdf_url TEXT NOT NULL,
    today_date DATE DEFAULT NULL,
    expired_date DATE DEFAULT NULL,

    renewal_of_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
    replaced_by_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
    version_no INT UNSIGNED NOT NULL DEFAULT 1,
    is_current CHAR(1) NOT NULL DEFAULT 'T',
    cert_status VARCHAR(20) NOT NULL DEFAULT 'active',

    is_active CHAR(1) NOT NULL DEFAULT 'T',
    created_by BIGINT UNSIGNED NOT NULL DEFAULT 0,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,

    PRIMARY KEY (id),
    KEY post_id (post_id),
    KEY serial_number (serial_number),
    KEY category_id (category_id),
    KEY today_date (today_date),
    KEY expired_date (expired_date),
    KEY renewal_of_id (renewal_of_id),
    KEY replaced_by_id (replaced_by_id),
    KEY version_no (version_no),
    KEY is_current (is_current),
    KEY cert_status (cert_status),
    KEY is_active (is_active),
    KEY created_by (created_by),
    KEY serial_current (serial_number(191), is_current, is_active)
  ) {$charset_collate};";

  dbDelta($sql);

  /**
   * Backward compatibility columns
   */
  $columns_to_check = [
    'serial_number'  => "ALTER TABLE {$table_name} ADD COLUMN serial_number VARCHAR(255) NOT NULL DEFAULT '' AFTER post_id",
    'is_active'      => "ALTER TABLE {$table_name} ADD COLUMN is_active CHAR(1) NOT NULL DEFAULT 'T' AFTER expired_date",
    'renewal_of_id'  => "ALTER TABLE {$table_name} ADD COLUMN renewal_of_id BIGINT UNSIGNED NOT NULL DEFAULT 0 AFTER expired_date",
    'replaced_by_id' => "ALTER TABLE {$table_name} ADD COLUMN replaced_by_id BIGINT UNSIGNED NOT NULL DEFAULT 0 AFTER renewal_of_id",
    'version_no'     => "ALTER TABLE {$table_name} ADD COLUMN version_no INT UNSIGNED NOT NULL DEFAULT 1 AFTER replaced_by_id",
    'is_current'     => "ALTER TABLE {$table_name} ADD COLUMN is_current CHAR(1) NOT NULL DEFAULT 'T' AFTER version_no",
    'cert_status'    => "ALTER TABLE {$table_name} ADD COLUMN cert_status VARCHAR(20) NOT NULL DEFAULT 'active' AFTER is_current",
  ];

  foreach ($columns_to_check as $column_name => $alter_sql) {
    $exists = $wpdb->get_var($wpdb->prepare(
      "SHOW COLUMNS FROM {$table_name} LIKE %s",
      $column_name
    ));

    if (!$exists) {
      $wpdb->query($alter_sql);
    }
  }

  /**
   * Old rows default values
   */
  $wpdb->query("UPDATE {$table_name} SET is_active = 'T' WHERE is_active IS NULL OR is_active = ''");
  $wpdb->query("UPDATE {$table_name} SET is_current = 'T' WHERE is_current IS NULL OR is_current = ''");
  $wpdb->query("UPDATE {$table_name} SET cert_status = 'active' WHERE cert_status IS NULL OR cert_status = ''");
  $wpdb->query("UPDATE {$table_name} SET version_no = 1 WHERE version_no IS NULL OR version_no = 0");
  $wpdb->query("UPDATE {$table_name} SET renewal_of_id = 0 WHERE renewal_of_id IS NULL");
  $wpdb->query("UPDATE {$table_name} SET replaced_by_id = 0 WHERE replaced_by_id IS NULL");

  /**
   * Auto-update updated_at
   */
  $wpdb->query("
    ALTER TABLE {$table_name}
    MODIFY updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
    ON UPDATE CURRENT_TIMESTAMP
  ");

  /**
   * Rebuild certificate status based on dates for current active rows
   * - active    : current and not yet expired
   * - expired   : current but expired
   * - superseded: not current
   */
  $today = current_time('Y-m-d');

  $wpdb->query("
    UPDATE {$table_name}
    SET cert_status = 'superseded'
    WHERE is_current = 'F'
  ");

  $wpdb->query($wpdb->prepare("
    UPDATE {$table_name}
    SET cert_status = 'expired'
    WHERE is_current = 'T'
      AND expired_date IS NOT NULL
      AND expired_date < %s
  ", $today));

  $wpdb->query($wpdb->prepare("
    UPDATE {$table_name}
    SET cert_status = 'active'
    WHERE is_current = 'T'
      AND (
        expired_date IS NULL
        OR expired_date >= %s
      )
  ", $today));

  /**
   * Fix historical duplicates:
   * For the same serial_number, keep only latest row as current.
   * Older rows become superseded.
   */
  $serials = $wpdb->get_col("
    SELECT serial_number
    FROM {$table_name}
    WHERE serial_number <> ''
    GROUP BY serial_number
    HAVING COUNT(*) > 1
  ");

  if (!empty($serials)) {
    foreach ($serials as $serial_number) {
      $rows = $wpdb->get_results(
        $wpdb->prepare("
          SELECT id
          FROM {$table_name}
          WHERE serial_number = %s
          ORDER BY
            COALESCE(today_date, '1000-01-01') DESC,
            id DESC
        ", $serial_number)
      );

      if (!empty($rows)) {
        $latest_id = (int) $rows[0]->id;

        $wpdb->update(
          $table_name,
          [
            'is_current'  => 'T',
            'cert_status' => 'active',
          ],
          ['id' => $latest_id],
          ['%s', '%s'],
          ['%d']
        );

        for ($i = 1; $i < count($rows); $i++) {
          $old_id = (int) $rows[$i]->id;

          $wpdb->update(
            $table_name,
            [
              'is_current'  => 'F',
              'cert_status' => 'superseded',
            ],
            ['id' => $old_id],
            ['%s', '%s'],
            ['%d']
          );
        }
      }
    }
  }
}

/**
 * Run only when version changes
 */
function kaya_maybe_upgrade_certificates_table() {
  $saved_version = get_option('kaya_cert_table_version', '');

  if ($saved_version === KAYA_CERT_TABLE_VERSION) {
    return;
  }

  kaya_create_certificates_table();
  update_option('kaya_cert_table_version', KAYA_CERT_TABLE_VERSION);
}

/**
 * Run on init, but only does real work once per version
 */
add_action('init', 'kaya_maybe_upgrade_certificates_table');global��
���b���
(��	�PDF UploadD&��global��
���|F�>�0���PHP AJAX checker/**
 * AJAX: Check if certificate serial already exists
 * - Normalizes to uppercase
 * - Only considers active AND current certificates
 */
function kaya_check_existing_certificate_serial() {
  if (!is_user_logged_in()) {
    wp_send_json_error([
      'message' => 'Unauthorized.'
    ], 403);
  }

  $current_user = wp_get_current_user();
  if (!array_intersect(['administrator', 'editor'], (array) $current_user->roles)) {
    wp_send_json_error([
      'message' => 'Permission denied.'
    ], 403);
  }

  check_ajax_referer('kaya_check_serial_nonce', 'nonce');

  global $wpdb;
  $table_name = $wpdb->prefix . 'kaya_certificates';

  // Normalize: uppercase and trim
  $raw_serial = sanitize_text_field(wp_unslash($_POST['serial_number'] ?? ''));
  $serial_number = strtoupper(trim($raw_serial));

  if ($serial_number === '') {
    wp_send_json_error([
      'message' => 'Serial number is required.'
    ], 400);
  }

  // Look for an active AND current certificate with this serial
  $row = $wpdb->get_row(
    $wpdb->prepare("
      SELECT id, serial_number, today_date, expired_date, post_id, is_active
      FROM {$table_name}
      WHERE serial_number = %s
        AND is_active = 'T'
        AND is_current = 'T'
      ORDER BY id DESC
      LIMIT 1
    ", $serial_number),
    ARRAY_A
  );

  if ($row) {
    wp_send_json_success([
      'exists'       => true,
      'id'           => (int) $row['id'],
      'serial_number'=> (string) $row['serial_number'],
      'today_date'   => !empty($row['today_date']) ? $row['today_date'] : '',
      'expired_date' => !empty($row['expired_date']) ? $row['expired_date'] : '',
      'post_id'      => (int) $row['post_id'],
    ]);
  }

  wp_send_json_success([
    'exists' => false
  ]);
}
add_action('wp_ajax_kaya_check_existing_certificate_serial', 'kaya_check_existing_certificate_serial');global��
���b+р�8[��PDF EDITD
&��global��
���|GY��	@Ƞ�
�PDF RenewD&��global��
���|Hр��!H���
�Profile Builder Login Logout Menuadd_filter('wp_nav_menu_items', 'my_wppb_login_logout_menu_item', 10, 2);

function my_wppb_login_logout_menu_item($items, $args) {
    $login_page_url  = 'https://cert.weldmaster.my/?page_id=259';
    $logout_redirect = home_url('/');
    $logout_url      = wp_logout_url($logout_redirect);

    if (is_user_logged_in()) {
        $current_user = wp_get_current_user();
        $name = $current_user->display_name ? $current_user->display_name : $current_user->user_login;

        $items .= '<li class="menu-item menu-item-user-name">
            <a href="javascript:void(0)" class="elementor-item elementor-item-user-name" aria-disabled="true">
                HI, ' . esc_html($name) . '
            </a>
        </li>';

        $items .= '<li class="menu-item menu-item-logout">
            <a href="' . esc_url($logout_url) . '" class="elementor-item elementor-item-logout">
                LOGOUT
            </a>
        </li>';
    } else {
        $items .= '<li class="menu-item menu-item-login">
            <a href="' . esc_url($login_page_url) . '" class="elementor-item elementor-item-login">
                LOGIN
            </a>
        </li>';
    }

    return $items;
}global��
����.�p/�c�������
	����ÿ�E�D5:�u#p�!infimumsupremum<�"��New Category Snippet/**
 * Shortcode: [add_category_form]
 * Allows users with proper permissions to add categories from frontend
 */
add_shortcode('add_category_form', 'frontend_category_form_shortcode');

function frontend_category_form_shortcode($atts) {
    // Security: Check if user can manage categories (Editor/Admin capability)
    if (!current_user_can('manage_categories')) {
        return '<div class="alert alert-error">You do not have permission to add categories.</div>';
    }

    // Load SweetAlert2
    wp_enqueue_script(
        'sweetalert2',
        'https://cdn.jsdelivr.net/npm/sweetalert2@11',
        array(),
        null,
        true
    );

    ob_start();

    $message = '';
    $message_class = '';

    // Process form submission
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_category_nonce'])) {

        // Verify nonce
        if (!wp_verify_nonce($_POST['add_category_nonce'], 'add_category_action')) {
            $message = 'Security check failed. Please try again.';
            $message_class = 'error';
        } else {
            // Sanitize input
            $cat_name = sanitize_text_field($_POST['category_name'] ?? '');

            if (empty($cat_name)) {
                $message = 'Please enter a category name.';
                $message_class = 'error';
            } else {
                // Check if category already exists
                if (term_exists($cat_name, 'category')) {
                    $message = 'This category already exists.';
                    $message_class = 'error';
                } else {
                    // Insert category
                    $result = wp_insert_term($cat_name, 'category');

                    if (is_wp_error($result)) {
                        $message = 'Error: ' . $result->get_error_message();
                        $message_class = 'error';
                    } else {
                        $message = 'Category "' . $cat_name . '" created successfully!';
                        $message_class = 'success';

                        // Clear field after success
                        $cat_name = '';
                    }
                }
            }
        }
    }
    ?>

    <div class="category-form-container" style="max-width: 600px; margin: 20px 0;">
        <form method="post" action="" style="background: #f9f9f9; padding: 20px; border: 1px solid #ddd; border-radius: 5px;">
            <?php wp_nonce_field('add_category_action', 'add_category_nonce'); ?>

            <div style="margin-bottom: 15px;">
                <label for="cat_name" style="display: block; margin-bottom: 5px; font-weight: bold;">
                    Category Name <span style="color: red;">*</span>
                </label>
                <input type="text"
                       name="category_name"
                       id="cat_name"
                       required
                       style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 3px;"
                       value="<?php echo isset($cat_name) ? esc_attr($cat_name) : ''; ?>">
            </div>

            <div style="margin-top: 20px;">
                <button type="submit"
                        style="background: #0073aa; color: white; padding: 10px 20px; border: none; border-radius: 3px; cursor: pointer; font-size: 14px;">
                    Create Category
                </button>
            </div>
        </form>
    </div>

    <?php if (!empty($message)) : ?>
        <script>
        document.addEventListener('DOMContentLoaded', function () {
            if (typeof Swal !== 'undefined') {
                Swal.fire({
                    icon: '<?php echo $message_class === 'success' ? 'success' : 'error'; ?>',
                    title: '<?php echo $message_class === 'success' ? 'Success' : 'Oops...'; ?>',
                    text: <?php echo wp_json_encode($message); ?>,
                    confirmButtonText: 'OK'
                });
            } else {
                alert(<?php echo wp_json_encode($message); ?>);
            }
        });
        </script>
    <?php endif; ?>

    <?php
    return ob_get_clean();
}global��
���������� ���<style>
.category-form-container .cert-btn {
    background: #ff2d2d;
    color: #fff;
    border: none;
    border-radius: 30px;
    padding: 12px 24px;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    transition: all 0.3s ease;
}

.category-form-container .cert-btn:hover {
    background: #e60023;
    transform: scale(1.05);
}
</style>site-css��
�����ƀ{�(���New Category Snippet [LEONG]/**
 * Shortcode: [add_category_form]
 * Allows users with proper permissions to add categories from frontend
 */
add_shortcode('add_category_form', 'frontend_category_form_shortcode');

function frontend_category_form_shortcode($atts) {
    // Security: Check if user can manage categories (Editor/Admin capability)
    if (!current_user_can('manage_categories')) {
        return '<div class="alert alert-error">You do not have permission to add categories.</div>';
    }

    // Load SweetAlert2
    wp_enqueue_script(
        'sweetalert2',
        'https://cdn.jsdelivr.net/npm/sweetalert2@11',
        array(),
        null,
        true
    );

    ob_start();

    $message = '';
    $message_class = '';

    // Process form submission
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['add_category_nonce'])) {

        // Verify nonce
        if (!wp_verify_nonce($_POST['add_category_nonce'], 'add_category_action')) {
            $message = 'Security check failed. Please try again.';
            $message_class = 'error';
        } else {
            // Sanitize input
            $cat_name = sanitize_text_field($_POST['category_name'] ?? '');

            if (empty($cat_name)) {
                $message = 'Please enter a category name.';
                $message_class = 'error';
            } else {
                // Check if category already exists
                if (term_exists($cat_name, 'category')) {
                    $message = 'This category already exists.';
                    $message_class = 'error';
                } else {
                    // Insert category
                    $result = wp_insert_term($cat_name, 'category');

                    if (is_wp_error($result)) {
                        $message = 'Error: ' . $result->get_error_message();
                        $message_class = 'error';
                    } else {
                        $message = 'Category "' . $cat_name . '" created successfully!';
                        $message_class = 'success';

                        // Clear field after success
                        $cat_name = '';
                    }
                }
            }
        }
    }
    ?>

    <div class="category-form-container" style="max-width: 600px; margin: 20px 0;">
        <form method="post" action="" style="background: #f9f9f9; padding: 20px; border: 1px solid #ddd; border-radius: 5px;">
            <?php wp_nonce_field('add_category_action', 'add_category_nonce'); ?>

            <div style="margin-bottom: 15px;">
                <label for="cat_name" style="display: block; margin-bottom: 5px; font-weight: bold;">
                    Category Name <span style="color: red;">*</span>
                </label>
                <input type="text"
                       name="category_name"
                       id="cat_name"
                       required
                       style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 3px;"
                       value="<?php echo isset($cat_name) ? esc_attr($cat_name) : ''; ?>">
            </div>

            <div style="margin-top: 20px;">
              <button type="submit"
    style="
        background: #ff2d2d;
        color: #fff;
        border: none;
        border-radius: 30px;
        padding: 12px 24px;
        font-size: 16px;
        font-weight: 600;
        cursor: pointer;
        display: inline-flex;
        align-items: center;
        gap: 8px;
        transition: all 0.3s ease;
    "
    onmouseover="this.style.transform='scale(1.05)'; this.style.background='#e60023';"
    onmouseout="this.style.transform='scale(1)'; this.style.background='#ff2d2d';"
>
    + Create Category
</button>
            </div>
        </form>
    </div>

    <?php if (!empty($message)) : ?>
        <script>
        document.addEventListener('DOMContentLoaded', function () {
            if (typeof Swal !== 'undefined') {
                Swal.fire({
                    icon: '<?php echo $message_class === 'success' ? 'success' : 'error'; ?>',
                    title: '<?php echo $message_class === 'success' ? 'Success' : 'Oops...'; ?>',
                    text: <?php echo wp_json_encode($message); ?>,
                    confirmButtonText: 'OK'
                });
            } else {
                alert(<?php echo wp_json_encode($message); ?>);
            }
        });
        </script>
    <?php endif; ?>

    <?php
    return ob_get_clean();
}global��
����8��pcÿ�7�
��������l�@*
D?�                                   'post_category' => [$category_id],
                                ], true);
                            } else {
                                $post_result = wp_insert_post([
                                    'post_title'    => $row_title,
                                    'post_content'  => $content,
                                    'post_status'   => 'publish',
                                    'post_type'     => 'post',
                                    'post_category' => [$category_id],
                                    'post_author'   => get_current_user_id()
                                ], true);

                                if (!is_wp_error($post_result)) {
                                    $post_id_existing = (int) $post_result;
                                }
                            }

                            if (is_wp_error($post_result)) {
                                $flash = '<div class="kaya-up-alert kaya-up-alert--err">Post update failed: '
                                       . esc_html($post_result->get_error_message()) . '</div>';
                            } else {
                                $today_now   = current_time('Y-m-d');
                                $cert_status = ($expired_date < $today_now) ? 'expired' : 'active';

                                $updated = $wpdb->update(
                                    $table_name,
                                    [
                                        'post_id'       => $post_id_existing,
                                        'serial_number' => $serial_number,
                                        'category_id'   => $category_id,
                                        'category_slug' => $slug,
                                        'pdf_url'       => esc_url_raw($pdf_url),
                                        'today_date'    => $today_date,
                                        'expired_date'  => $expired_date,
                                        'cert_status'   => $cert_status,
                                    ],
                                    ['id' => $edit_id],
                                    ['%d','%s','%d','%s','%s','%s','%s','%s'],
                                    ['%d']
                                );

                                if ($updated === false) {
                                    $flash = '<div class="kaya-up-alert kaya-up-alert--err"><b>Post updated but DB update failed.</b><div class="kaya-up-small">'
                                           . esc_html($wpdb->last_error) . '</div></div>';
                                } else {
                                    update_post_meta($post_id_existing, '_kaya_invoice_post', 1);
                                    update_post_meta($post_id_existing, '_kaya_invoice_pdf_url', esc_url_raw($pdf_url));

                                    update_post_meta($post_id_existing, '_kaya_cert_row_id', $edit_id);
                                    update_post_meta($post_id_existing, '_kaya_serial_number', $serial_number);
                                    update_post_meta($post_id_existing, '_kaya_today_date', $today_date);
                                    update_post_meta($post_id_existing, '_kaya_expired_date', $expired_date);
                                    update_post_meta($post_id_existing, '_kaya_cert_status', $cert_status);

                                    $success_popup = [
                                        'title'    => 'Update Successful!',
                                        'text'     => 'Certificate has been updated successfully.',
                                        'view_url' => get_permalink($post_id_existing),
                                        'pdf_url'  => $pdf_url,
                                    ];

                                    // refresh data shown in form
                                    $existing = $wpdb->get_row(
                                        $wpdb->prepare("SELECT * FROM {$table_name} WHERE id = %d LIMIT 1", $edit_id),
                                        ARRAY_A
                                    );
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    $default_serial = isset($existing['serial_number']) ? (string) $existing['serial_number'] : '';
    $default_category_id = isset($existing['category_id']) ? absint($existing['category_id']) : 0;
    $default_today = !empty($existing['today_date']) ? (string) $existing['today_date'] : current_time('Y-m-d');
    $default_expired = !empty($existing['expired_date']) ? (string) $existing['expired_date'] : date('Y-m-d', strtotime($default_today . ' +1 year -1 day'));
    $current_pdf_url = isset($existing['pdf_url']) ? (string) $existing['pdf_url'] : '';
    $view_post_url = !empty($existing['post_id']) ? get_permalink((int)$existing['post_id']) : '';

    ob_start();
    ?>
    <div class="kaya-up">
        <div class="kaya-up-shell">
            <?php echo $flash; ?>

            <div class="kaya-up-card">
                <form method="post" enctype="multipart/form-data" id="kayaPdfEditForm">
                    <?php wp_nonce_field('kaya_pdf_edit_action', 'kaya_pdf_edit_nonce'); ?>
                    <input type="hidden" name="edit_id" id="edit_id" value="<?php echo esc_attr($edit_id); ?>">

                    <div class="kaya-up-top">
                        <div class="kaya-up-field">
                            <label>Serial Number</label>
                            <!-- ✅ Made read‑only to prevent QR code breakage -->
                            <input type="text" name="serial_number" id="serial_number"
                                   value="<?php echo esc_attr($default_serial); ?>"
                                   required readonly
                                   style="background:#f8fafc; color:#475569; cursor:not-allowed;">
                        </div>

                        <div class="kaya-up-field">
                            <label>Category</label>
                            <select name="post_category" required>
                                <?php
                                $categories = get_terms([
                                    'taxonomy'   => 'category',
                                    'hide_empty' => false
                                ]);
                                if (!is_wp_error($categories) && $categories) {
                                    foreach ($categories as $cat) {
                                        echo '<option value="' . esc_attr($cat->term_id) . '" ' . selected($default_category_id, $cat->term_id, false) . '>' . esc_html($cat->name) . '</option>';
                                    }
                                }
                                ?>
                            </select>
                        </div>
                    </div>

                    <div class="kaya-up-top">
                        <div class="kaya-up-field">
                            <label>Today Date</label>
                            <input type="date" name="today_date" id="kayaTodayDate" value="<?php echo esc_attr($default_today); ?>" required>
                        </div>

                        <div class="kaya-up-field">
                            <label>Expired Date</label>
                            <input type="date" name="expired_date" id="kayaExpiredDate" value="<?php echo esc_attr($default_expired); ?>" required>
                        </div>
                    </div>

                    <?php if ($current_pdf_url): ?>
                    <div class="kaya-up-alert kaya-up-alert--warn" style="margin-bottom:14px;">
                        Current PDF:
                        <a href="<?php echo esc_url($current_pdf_url); ?>" target="_blank" rel="noopener">Open current PDF</a>
                        <?php if ($view_post_url): ?>
                            | <a href="<?php echo esc_url($view_post_url); ?>" target="_blank" rel="noopener">View current page</a>
                        <?php endif; ?>
                    </div>
                    <?php endif; ?>

                    <div class="kaya-up-drop" id="kayaDrop">
                        <div class="kaya-up-illu" aria-hidden="true">
                            <svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                                <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
                                <path d="M14 2v6h6"/>
                                <path d="M12 18v-6"/>
                                <path d="M9.5 14.5 12 12l2.5 2.5"/>
                            </svg>
                        </div>

                        <div class="kaya-up-title">Replace PDF (optional)</div>
                        <div class="kaya-up-or">or keep current file</div>

                        <button type="button" class="kaya-up-btn kaya-up-btn--primary" id="kayaPickBtn">
                            Upload New PDF
                        </button>

                        <div class="kaya-up-note">PDF up to <?php echo esc_html($max_mb_text); ?></div>

                        <div class="kaya-up-filehint" id="kayaFileHint" style="display:none;">
                            <span>Selected:</span> <b id="kayaFileName"></b>
                        </div>

                        <input type="file" name="pdf_file" accept="application/pdf" id="kayaFileInput">
                    </div>

                    <div style="margin-top:14px; display:flex; justify-content:center;">
                        <button type="button" id="kaya_cert_submit_btn" class="kaya-up-btn kaya-up-btn--primary" style="min-width:320px;">
                            Save Changes
                        </button>
                    </div>
                </form>
            </div>
        </div>
    </div>

    <script>
        window.kayaCertEditAjax = {
            ajaxUrl: <?php echo wp_json_encode(admin_url('admin-ajax.php')); ?>,
            nonce: <?php echo wp_json_encode(wp_create_nonce('kaya_check_serial_nonce')); ?>,
            currentId: <?php echo wp_json_encode($edit_id); ?>
        };
    </script>

    <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>

    <script>
    (function() {
        document.addEventListener('DOMContentLoaded', function() {
            const drop = document.getElementById('kayaDrop');
            const fileInput = document.getElementById('kayaFileInput');
            const pickBtn = document.getElementById('kayaPickBtn');
            const hint = document.getElementById('kayaFileHint');
            const nameEl = document.getElementById('kayaFileName');
            const todayInput = document.getElementById('kayaTodayDate');
            const expiredInput = document.getElementById('kayaExpiredDate');
            const form = document.getElementById('kayaPdfEditForm');
            const submitBtn = document.getElementById('kaya_cert_submit_btn');
            const serialInput = document.getElementById('serial_number');

            function calculateExpiredDate(todayStr){
                if (!todayStr || !/^\d{4}-\d{2}-\d{2}$/.test(todayStr)) return '';
                const parts = todayStr.split('-');
                const year = parseInt(parts[0], 10);
                const month = parseInt(parts[1], 10);
                const day = parseInt(parts[2], 10);
                const base = new Date(Date.UTC(year, month - 1, day));
                if (isNaN(base.getTime())) return '';
                const result = new Date(base);
                result.setUTCFullYear(result.getUTCFullYear() + 1);
                result.setUTCDate(result.getUTCDate() - 1);
                const yyyy = result.getUTCFullYear();
                const mm = String(result.getUTCMonth() + 1).padStart(2, '0');
                const dd = String(result.getUTCDate()).padStart(2, '0');
                return `${yyyy}-${mm}-${dd}`;
            }

            function syncExpiredDate(){
                if (!todayInput || !expiredInput) return;
                const suggested = calculateExpiredDate(todayInput.value);
                if (suggested) expiredInput.value = suggested;
            }

            if (todayInput && expiredInput) {
                todayInput.addEventListener('change', syncExpiredDate);
                todayInput.addEventListener('input', syncExpiredDate);
            }

            if (drop && fileInput) {
                function showFileName(){
                    const f = fileInput.files && fileInput.files[0];
                    if (!f) {
                        if (hint) hint.style.display = 'none';
                        return;
                    }
                    if (hint) hint.style.display = 'block';
                    if (nameEl) nameEl.textContent = f.name;
                }

                if (pickBtn){
                    pickBtn.addEventListener('click', function(e){
                        e.preventDefault();
                        fileInput.click();
                    });
                }

                fileInput.addEventListener('change', showFileName);

                ['dragenter','dragover'].forEach(function(evt){
                    drop.addEventListener(evt, function(e){
                        e.preventDefault();
                        e.stopPropagation();
                        drop.classList.add('is-drag');
                    });
                });

                ['dragleave','drop'].forEach(function(evt){
                    drop.addEventListener(evt, function(e){
                        e.preventDefault();
                        e.stopPropagation();
                        drop.classList.remove('is-drag');
                    });
                });

                drop.addEventListener('drop', function(e){
                    if (!e.dataTransfer || !e.dataTransfer.files || !e.dataTransfer.files.length) return;
                    fileInput.files = e.dataTransfer.files;
                    showFileName();
                });
            }

            if (form && submitBtn && serialInput) {
                submitBtn.addEventListener('click', async function(e) {
                    e.preventDefault();

                    // Normalize to lowercase on client side
                    let serialNumber = (serialInput.value || '').trim().toLowerCase();
                    serialInput.value = serialNumber;

                    if (!serialNumber) {
                        alert('Serial number is required.');
                        serialInput.focus();
                        return;
                    }

                    submitBtn.disabled = true;
                    submitBtn.textContent = 'Checking...';

                    try {
                        const fd = new FormData();
                        fd.append('action', 'kaya_check_existing_certificate_serial_for_edit');
                        fd.append('nonce', window.kayaCertEditAjax.nonce);
                        fd.append('serial_number', serialNumber);
                        fd.append('current_id', window.kayaCertEditAjax.currentId);

                        const response = await fetch(window.kayaCertEditAjax.ajaxUrl, {
                            method: 'POST',
                            credentials: 'same-origin',
                            body: fd
                        });

                        const result = await response.json();

                        if (!result.success) {
                            await Swal.fire({
                                icon: 'error',
                                title: 'Check Failed',
                                text: result.data?.message || 'Unable to verify serial number.'
                            });
                            submitBtn.disabled = false;
                            submitBtn.textContent = 'Save Changes';
                            return;
                        }

                        if (result.data.exists) {
                            await Swal.fire({
                                icon: 'el�@*��Y����������F�
D?�/**
 * FRONTEND PDF UPLOAD SHORTCODE + AJAX SERIAL CHECK
 * Shortcode: [pdf_frontend_upload]
 *
 * - Creates a post with PDF viewer, QR code, and stores record in wp_kaya_certificates.
 * - Duplicate serial check via AJAX + SweetAlert2.
 * - Preserves original serial number casing for display/storage.
 * - Uses serial_number_key for case-insensitive duplicate checking.
 * - Uses a button with type="button" to prevent default submission until after the check.
 * - Extended table columns: renewal_of_id, replaced_by_id, version_no, is_current, cert_status.
 * - Success popup contains custom "View Page" and "Open PDF" buttons that do not close the popup.
 * - On duplicate serial, redirects to certificate list page with ?kaya_search=serial (original case).
 */

if (!defined('ABSPATH')) exit;

/** =========================
 * SETTINGS
 * ========================= */
if (!defined('KAYA_INV_SHOW_FILE_URL')) {
    define('KAYA_INV_SHOW_FILE_URL', true);
}
if (!defined('KAYA_INV_QR_FILENAME_PREFIX')) {
    define('KAYA_INV_QR_FILENAME_PREFIX', 'QR-');
}

/** =========================
 * HELPER FUNCTIONS
 * ========================= */
function kaya_certificates_table_exists() {
    global $wpdb;
    $table_name = $wpdb->prefix . 'kaya_certificates';
    $found = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name));
    return ($found === $table_name);
}

/**
 * Normalise a serial number to a case-insensitive key.
 *
 * @param string $serial
 * @return string
 */
function kaya_normalize_serial_key($serial) {
    return strtolower(trim((string) $serial));
}

// Add a CSS class to generated certificate posts
add_filter('post_class', function($classes, $class, $post_id){
    if (get_post_meta($post_id, '_kaya_invoice_post', true)) {
        $classes[] = 'kaya-invoice-post';
        $classes[] = 'kaya-invoice-post--v10';
    }
    return $classes;
}, 10, 3);

/** =========================
 * AJAX HANDLER – Check duplicate serial
 * ========================= */
function kaya_check_existing_certificate_serial() {
    // Security & permissions
    if (!is_user_logged_in()) {
        wp_send_json_error(['message' => 'Unauthorized.'], 403);
    }
    $current_user = wp_get_current_user();
    if (!array_intersect(['administrator', 'editor'], (array) $current_user->roles)) {
        wp_send_json_error(['message' => 'Permission denied.'], 403);
    }
    check_ajax_referer('kaya_check_serial_nonce', 'nonce');

    global $wpdb;
    $table_name = $wpdb->prefix . 'kaya_certificates';

    // Preserve original case, but build a case-insensitive key for lookup
    $raw_serial        = sanitize_text_field(wp_unslash($_POST['serial_number'] ?? ''));
    $serial_number     = trim($raw_serial);
    $serial_number_key = kaya_normalize_serial_key($serial_number);

    if ($serial_number === '') {
        wp_send_json_error(['message' => 'Serial number is required.'], 400);
    }

    // Look for an active, current certificate using the normalised key
    $row = $wpdb->get_row(
        $wpdb->prepare("
            SELECT id, serial_number, serial_number_key, today_date, expired_date, post_id
            FROM {$table_name}
            WHERE serial_number_key = %s
              AND is_active = 'T'
              AND is_current = 'T'
            ORDER BY id DESC
            LIMIT 1
        ", $serial_number_key),
        ARRAY_A
    );

    if ($row) {
        wp_send_json_success([
            'exists'        => true,
            'id'            => (int) $row['id'],
            'serial_number' => (string) $row['serial_number'],   // original case for display
            'today_date'    => !empty($row['today_date']) ? $row['today_date'] : '',
            'expired_date'  => !empty($row['expired_date']) ? $row['expired_date'] : '',
            'post_id'       => (int) $row['post_id'],
        ]);
    }

    wp_send_json_success(['exists' => false]);
}
add_action('wp_ajax_kaya_check_existing_certificate_serial', 'kaya_check_existing_certificate_serial');

/** =========================
 * SHORTCODE – PDF Upload Form (FULL PROCESSING)
 * ========================= */
function frontend_pdf_uploader_kaya_qr() {

    if (!is_user_logged_in()) {
        return '<div class="kaya-up-alert kaya-up-alert--warn">Please login to upload PDF.</div>';
    }

    $current_user = wp_get_current_user();
    if (!array_intersect(['administrator','editor'], (array) $current_user->roles)) {
        return '<div class="kaya-up-alert kaya-up-alert--err">Only administrators or editors can upload certificates.</div>';
    }

    if (!kaya_certificates_table_exists()) {
        return '<div class="kaya-up-alert kaya-up-alert--err">Certificate table is missing. Please enable the table setup snippet first.</div>';
    }

    global $wpdb;
    $table_name = $wpdb->prefix . 'kaya_certificates';

    $flash = '';
    $success_popup = null;

    $BASE_REL = 'FILES';
    $max_mb_text = '100 MB';

    // ===== PROCESS FORM SUBMISSION =====
    if (isset($_POST['kaya_pdf_upload_nonce']) &&
        wp_verify_nonce($_POST['kaya_pdf_upload_nonce'], 'kaya_pdf_upload_action')) {

        if (empty($_FILES['pdf_file']['name'])) {
            $flash = '<div class="kaya-up-alert kaya-up-alert--err">Please select a PDF file.</div>';
        } else {
            // Preserve original case and create normalised key
            $raw_serial        = sanitize_text_field(wp_unslash($_POST['serial_number'] ?? ''));
            $serial_number     = trim($raw_serial);                 // original case as typed
            $serial_number_key = kaya_normalize_serial_key($serial_number);

            $category_id   = absint($_POST['post_category'] ?? 0);
            $today_date    = sanitize_text_field(wp_unslash($_POST['today_date'] ?? ''));
            $expired_date  = sanitize_text_field(wp_unslash($_POST['expired_date'] ?? ''));
            $renewal_of_id = absint($_POST['renewal_of_id'] ?? 0);
            $category      = get_term($category_id, 'category');
            $category_name = ($category && !is_wp_error($category)) ? $category->name : '';

            if ($serial_number === '') {
                $flash = '<div class="kaya-up-alert kaya-up-alert--err">Please fill in Serial Number.</div>';
            } elseif (!$category || is_wp_error($category)) {
                $flash = '<div class="kaya-up-alert kaya-up-alert--err">Invalid category.</div>';
            } elseif ($today_date === '') {
                $flash = '<div class="kaya-up-alert kaya-up-alert--err">Please fill in Today Date.</div>';
            } elseif (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $today_date)) {
                $flash = '<div class="kaya-up-alert kaya-up-alert--err">Invalid today date format.</div>';
            } else {
                // Auto-calculate only if expired date is empty
                if ($expired_date === '') {
                    $today_dt = DateTime::createFromFormat('Y-m-d', $today_date);
                    if (!$today_dt || $today_dt->format('Y-m-d') !== $today_date) {
                        $flash = '<div class="kaya-up-alert kaya-up-alert--err">Invalid today date value.</div>';
                    } else {
                        $expired_dt = clone $today_dt;
                        $expired_dt->modify('+1 year');
                        $expired_dt->modify('-1 day');
                        $expired_date = $expired_dt->format('Y-m-d');
                    }
                }

                if ($flash === '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $expired_date)) {
                    $flash = '<div class="kaya-up-alert kaya-up-alert--err">Invalid expired date format.</div>';
                } elseif ($flash === '') {
                    $slug = sanitize_title($category->slug);

                    if ($slug === '') {
                        $flash = '<div class="kaya-up-alert kaya-up-alert--err">Category slug is empty.</div>';
                    } else {
                        $folder_name = strtoupper($slug);

                        $target_dir = rtrim(ABSPATH, '/\\') . DIRECTORY_SEPARATOR
                                    . trim($BASE_REL, '/\\') . DIRECTORY_SEPARATOR
                                    . $folder_name . DIRECTORY_SEPARATOR;

                        $base_url = home_url('/' . trim($BASE_REL, '/\\') . '/' . $folder_name . '/');

                        // ===== DIRECTORY CREATION =====
                        if (!is_dir($target_dir)) {
                            if (!wp_mkdir_p($target_dir)) {
                                $flash = '<div class="kaya-up-alert kaya-up-alert--err"><b>Failed to create folder</b><div class="kaya-up-small">'
                                       . esc_html($target_dir) . '</div></div>';
                            }
                        }

                        if ($flash === '' && !is_writable($target_dir)) {
                            $flash = '<div class="kaya-up-alert kaya-up-alert--err"><b>Folder not writable</b><div class="kaya-up-small">'
                                   . esc_html($target_dir) . '</div></div>';
                        }

                        if ($flash === '') {
                            $file  = $_FILES['pdf_file'];
                            $check = wp_check_filetype_and_ext($file['tmp_name'], $file['name']);
                            $ext   = strtolower((string)($check['ext'] ?? ''));

                            if ($ext !== 'pdf') {
                                $flash = '<div class="kaya-up-alert kaya-up-alert--err">Only PDF allowed.</div>';
                            } else {
                                $random      = wp_generate_password(20, false, false);
                                $filename    = strtolower($random) . '.pdf';
                                $target_path = $target_dir . $filename;

                                if (!@move_uploaded_file($file['tmp_name'], $target_path)) {
                                    $err = error_get_last();
                                    $flash  = '<div class="kaya-up-alert kaya-up-alert--err"><b>Upload failed while moving file</b>.</div>';
                                    $flash .= '<div class="kaya-up-debug"><b>Target:</b> ' . esc_html($target_path) . '<br><pre>'
                                            . esc_html(print_r($err, true)) . '</pre></div>';
                                } else {
                                    $pdf_url   = $base_url . rawurlencode($filename);
                                    $row_title = $serial_number; // uses original case
                                    $qr_box_id = 'kaya-qr-box-' . wp_generate_password(8, false, false);

                                    $qepw = '[qepw_pdf_viewer file="' . esc_url($pdf_url) . '"]';

                                    $kaya_qr = '
                                        <div class="kaya-qr-download-wrap" id="' . esc_attr($qr_box_id) . '">
                                            <div class="kaya-qr-download-title">' . esc_html($serial_number) . '</div>
                                            <div class="kaya-qr-download-inner">
                                                [kaya_qrcode content="' . esc_url($pdf_url) . '" dynamic_content="0" download_button="0" download_align="aligncenter"]
                                            </div>
                                        </div>

                                        <div class="kaya-qr-download-actions">
                                            <button type="button"
                                                    class="kaya-up-btn kaya-up-btn--primary kaya-download-qr-btn"
                                                    data-target="' . esc_attr($qr_box_id) . '"
                                                    data-filename="' . esc_attr(sanitize_file_name($serial_number)) . '-qr.png">
                                                Download QR Image
                                            </button>
                                        </div>
                                    ';

                                    $content = '<div class="kaya-inv-page kaya-inv-page--v10">' .
                                        '<div class="kaya-inv-viewer kaya-inv-viewer--qepw">' .
                                            $qepw .
                                        '</div>' .
                                        '<div class="kaya-inv-qr kaya-inv-qr--kaya">' .
                                            '<div class="kaya-inv-qrbox">' .
                                                $kaya_qr .
                                            '</div>';

                                    $content .= '<div class="kaya-inv-meta kaya-inv-serial-number">' .
                                                    '<div class="kaya-inv-label">Serial Number</div>' .
                                                    '<div class="kaya-inv-text">' . esc_html($serial_number) . '</div>' .
                                                '</div>';

                                    if (KAYA_INV_SHOW_FILE_URL) {
                                        $content .= '<div class="kaya-inv-meta kaya-inv-urlwrap">' .
                                                      '<div class="kaya-inv-label">File URL</div>' .
                                                      '<div class="kaya-inv-url">' . esc_html($pdf_url) . '</div>' .
                                                    '</div>';
                                    }

                                    $content .= '<div class="kaya-inv-meta kaya-inv-cert-availability">' .
                                                    '<div class="kaya-inv-label">Certificate Availability</div>' .
                                                    '<div class="kaya-inv-text">' . esc_html($today_date) . ' - ' . esc_html($expired_date) . '</div>' .
                                                '</div>';

                                    $content .= '<div class="kaya-inv-meta kaya-inv-cert-days">' .
                                                    '<div class="kaya-inv-label">Days Left Until Expired</div>' .
                                                    '<div class="kaya-inv-cert-row">' .
                                                        '<div class="kaya-inv-text">' .
                                                            '<span class="kaya-cert-countdown" data-expire="' . esc_attr($expired_date) . '">Checking...</span>' .
                                                        '</div>' .
                                                        '<span class="kaya-cert-status">Checking...</span>' .
                                                    '</div>' .
                                                '</div>';

                                    $content .= '</div></div>';

                                    $post_id = wp_insert_post(array(
                                        'post_title'    => $row_title,
                                        'post_content'  => $content,
                                        'post_status'   => 'publish',
                                        'post_type'     => 'post',
                                        'post_category' => array($category_id),
                                        'post_author'   => get_current_user_id()
                                    ), true);

                                    if (is_wp_error($post_id)) {
                                        $flash = '<div class="kaya-up-alert kaya-up-alert--err">Post creation failed: '
                                               . esc_html($post_id->get_error_message()) . '</div>';
                                    } else {
                                        // Determine certificate status
                                        $today_now   = current_time('Y-m-d');
                                        $cert_status = ($expired_date < $today_now) ? 'expired' : 'active';

                                        // Insert into custom table with extended columns, including serial_number_key and category_name
                                        $inserted = $wpdb->insert(
                                            $table_name,
                                      ��F��m�C
����������X
D?�/**
 * FRONTEND PDF EDIT SHORTCODE + AJAX SERIAL CHECK
 * Shortcode: [pdf_frontend_edit]
 *
 * - Edits an existing certificate row using ?edit_id=ID
 * - Updates wp_kaya_certificates and related WP post
 * - Duplicate serial check ignores current editing row
 * - PDF upload is optional; if not selected, old PDF is kept
 * - Success popup contains custom "View Page" and "Open PDF" buttons
 * - Preserves original serial number casing for display/storage.
 * - Uses serial_number_key for case-insensitive duplicate checking.
 */

if (!defined('ABSPATH')) exit;

/** =========================
 * SETTINGS
 * ========================= */
if (!defined('KAYA_INV_SHOW_FILE_URL')) {
    define('KAYA_INV_SHOW_FILE_URL', true);
}
if (!defined('KAYA_INV_QR_FILENAME_PREFIX')) {
    define('KAYA_INV_QR_FILENAME_PREFIX', 'QR-');
}

/** =========================
 * HELPERS (wrapped to avoid redeclaration)
 * ========================= */

if (!function_exists('kaya_certificates_table_exists')) {
    function kaya_certificates_table_exists() {
        global $wpdb;
        $table_name = $wpdb->prefix . 'kaya_certificates';
        $found = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name));
        return ($found === $table_name);
    }
}

if (!function_exists('kaya_cert_get_existing_pdf_filename')) {
    function kaya_cert_get_existing_pdf_filename($pdf_url) {
        $path = wp_parse_url($pdf_url, PHP_URL_PATH);
        if (!$path) return '';
        return basename($path);
    }
}

if (!function_exists('kaya_normalize_serial_key')) {
    function kaya_normalize_serial_key($serial) {
        return strtolower(trim((string) $serial));
    }
}

/** =========================
 * AJAX HANDLER – Check duplicate serial for edit
 * Ignores current row ID, uses case‑insensitive key
 * ========================= */
function kaya_check_existing_certificate_serial_for_edit() {
    if (!is_user_logged_in()) {
        wp_send_json_error(['message' => 'Unauthorized.'], 403);
    }

    $current_user = wp_get_current_user();
    if (!array_intersect(['administrator', 'editor'], (array) $current_user->roles)) {
        wp_send_json_error(['message' => 'Permission denied.'], 403);
    }

    check_ajax_referer('kaya_check_serial_nonce', 'nonce');

    global $wpdb;
    $table_name = $wpdb->prefix . 'kaya_certificates';

    // Preserve original case, build key for lookup
    $raw_serial        = sanitize_text_field(wp_unslash($_POST['serial_number'] ?? ''));
    $serial_number     = trim($raw_serial);                 // original case
    $serial_number_key = kaya_normalize_serial_key($serial_number);
    $current_id        = absint($_POST['current_id'] ?? 0);

    if ($serial_number === '') {
        wp_send_json_error(['message' => 'Serial number is required.'], 400);
    }

    if ($current_id > 0) {
        $row = $wpdb->get_row(
            $wpdb->prepare("
                SELECT id, serial_number, serial_number_key, today_date, expired_date, post_id
                FROM {$table_name}
                WHERE serial_number_key = %s
                  AND is_active = 'T'
                  AND is_current = 'T'
                  AND id != %d
                ORDER BY id DESC
                LIMIT 1
            ", $serial_number_key, $current_id),
            ARRAY_A
        );
    } else {
        $row = $wpdb->get_row(
            $wpdb->prepare("
                SELECT id, serial_number, serial_number_key, today_date, expired_date, post_id
                FROM {$table_name}
                WHERE serial_number_key = %s
                  AND is_active = 'T'
                  AND is_current = 'T'
                ORDER BY id DESC
                LIMIT 1
            ", $serial_number_key),
            ARRAY_A
        );
    }

    if ($row) {
        wp_send_json_success([
            'exists'        => true,
            'id'            => (int) $row['id'],
            'serial_number' => (string) $row['serial_number'], // original case
            'today_date'    => !empty($row['today_date']) ? $row['today_date'] : '',
            'expired_date'  => !empty($row['expired_date']) ? $row['expired_date'] : '',
            'post_id'       => (int) $row['post_id'],
        ]);
    }

    wp_send_json_success(['exists' => false]);
}
add_action('wp_ajax_kaya_check_existing_certificate_serial_for_edit', 'kaya_check_existing_certificate_serial_for_edit');

/** =========================
 * SHORTCODE – EDIT FORM
 * ========================= */
function frontend_pdf_editor_kaya_qr() {

    if (!is_user_logged_in()) {
        return '<div class="kaya-up-alert kaya-up-alert--warn">Please login to edit certificate.</div>';
    }

    $current_user = wp_get_current_user();
    if (!array_intersect(['administrator','editor'], (array) $current_user->roles)) {
        return '<div class="kaya-up-alert kaya-up-alert--err">Only administrators or editors can edit certificates.</div>';
    }

    if (!kaya_certificates_table_exists()) {
        return '<div class="kaya-up-alert kaya-up-alert--err">Certificate table is missing. Please enable the table setup snippet first.</div>';
    }

    global $wpdb;
    $table_name = $wpdb->prefix . 'kaya_certificates';

    $flash = '';
    $success_popup = null;

    $BASE_REL = 'FILES';
    $max_mb_text = '100 MB';

    $edit_id = absint($_GET['edit_id'] ?? 0);
    if ($edit_id <= 0) {
        return '<div class="kaya-up-alert kaya-up-alert--err">Missing or invalid edit_id.</div>';
    }

    $existing = $wpdb->get_row(
        $wpdb->prepare("SELECT * FROM {$table_name} WHERE id = %d LIMIT 1", $edit_id),
        ARRAY_A
    );

    if (!$existing) {
        return '<div class="kaya-up-alert kaya-up-alert--err">Certificate record not found.</div>';
    }

    $post_id_existing = isset($existing['post_id']) ? absint($existing['post_id']) : 0;
    $post_existing = $post_id_existing ? get_post($post_id_existing) : null;

    if ($_SERVER['REQUEST_METHOD'] === 'POST' &&
        isset($_POST['kaya_pdf_edit_nonce']) &&
        wp_verify_nonce($_POST['kaya_pdf_edit_nonce'], 'kaya_pdf_edit_action')) {

        // Preserve original case, build key
        $raw_serial        = sanitize_text_field(wp_unslash($_POST['serial_number'] ?? ''));
        $serial_number     = trim($raw_serial);                 // original case
        $serial_number_key = kaya_normalize_serial_key($serial_number);

        $category_id   = absint($_POST['post_category'] ?? 0);
        $today_date    = sanitize_text_field(wp_unslash($_POST['today_date'] ?? ''));
        $expired_date  = sanitize_text_field(wp_unslash($_POST['expired_date'] ?? ''));
        $category      = get_term($category_id, 'category');
        $category_name = ($category && !is_wp_error($category)) ? $category->name : '';

        if ($serial_number === '') {
            $flash = '<div class="kaya-up-alert kaya-up-alert--err">Please fill in Serial Number.</div>';
        } elseif (!$category || is_wp_error($category)) {
            $flash = '<div class="kaya-up-alert kaya-up-alert--err">Invalid category.</div>';
        } elseif ($today_date === '') {
            $flash = '<div class="kaya-up-alert kaya-up-alert--err">Please fill in Today Date.</div>';
        } elseif (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $today_date)) {
            $flash = '<div class="kaya-up-alert kaya-up-alert--err">Invalid today date format.</div>';
        } else {

            if ($expired_date === '') {
                $today_dt = DateTime::createFromFormat('Y-m-d', $today_date);
                if (!$today_dt || $today_dt->format('Y-m-d') !== $today_date) {
                    $flash = '<div class="kaya-up-alert kaya-up-alert--err">Invalid today date value.</div>';
                } else {
                    $expired_dt = clone $today_dt;
                    $expired_dt->modify('+1 year');
                    $expired_dt->modify('-1 day');
                    $expired_date = $expired_dt->format('Y-m-d');
                }
            }

            if ($flash === '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $expired_date)) {
                $flash = '<div class="kaya-up-alert kaya-up-alert--err">Invalid expired date format.</div>';
            }

            // duplicate check server-side too (case‑insensitive, using key)
            if ($flash === '') {
                $duplicate = $wpdb->get_var(
                    $wpdb->prepare("
                        SELECT id
                        FROM {$table_name}
                        WHERE serial_number_key = %s
                          AND is_active = 'T'
                          AND is_current = 'T'
                          AND id != %d
                        LIMIT 1
                    ", $serial_number_key, $edit_id)
                );

                if ($duplicate) {
                    $flash = '<div class="kaya-up-alert kaya-up-alert--err">This serial number already exists on another current certificate.</div>';
                }
            }

            if ($flash === '') {
                $slug = sanitize_title($category->slug);

                if ($slug === '') {
                    $flash = '<div class="kaya-up-alert kaya-up-alert--err">Category slug is empty.</div>';
                } else {
                    $folder_name = strtoupper($slug);

                    $target_dir = rtrim(ABSPATH, '/\\') . DIRECTORY_SEPARATOR
                                . trim($BASE_REL, '/\\') . DIRECTORY_SEPARATOR
                                . $folder_name . DIRECTORY_SEPARATOR;

                    $base_url = home_url('/' . trim($BASE_REL, '/\\') . '/' . $folder_name . '/');

                    if (!is_dir($target_dir)) {
                        $flash = '<div class="kaya-up-alert kaya-up-alert--err"><b>Folder does not exist</b><div class="kaya-up-small">'
                               . esc_html($target_dir) . '</div></div>';
                    } elseif (!is_writable($target_dir)) {
                        $flash = '<div class="kaya-up-alert kaya-up-alert--err"><b>Folder not writable</b><div class="kaya-up-small">'
                               . esc_html($target_dir) . '</div></div>';
                    } else {

                        $pdf_url = isset($existing['pdf_url']) ? (string) $existing['pdf_url'] : '';
                        $new_file_uploaded = !empty($_FILES['pdf_file']['name']);

                        if ($new_file_uploaded) {
                            $file  = $_FILES['pdf_file'];
                            $check = wp_check_filetype_and_ext($file['tmp_name'], $file['name']);
                            $ext   = strtolower((string)($check['ext'] ?? ''));

                            if ($ext !== 'pdf') {
                                $flash = '<div class="kaya-up-alert kaya-up-alert--err">Only PDF allowed.</div>';
                            } else {
                                // Reuse existing filename to keep URL unchanged
                                $old_pdf_url  = isset($existing['pdf_url']) ? (string) $existing['pdf_url'] : '';
                                $old_filename = kaya_cert_get_existing_pdf_filename($old_pdf_url);

                                if ($old_filename === '') {
                                    $flash = '<div class="kaya-up-alert kaya-up-alert--err">Existing PDF filename could not be detected.</div>';
                                } else {
                                    $target_path = $target_dir . $old_filename;

                                    // Remove old file first so move_uploaded_file can replace cleanly
                                    if (is_file($target_path)) {
                                        @unlink($target_path);
                                    }

                                    if (!@move_uploaded_file($file['tmp_name'], $target_path)) {
                                        $err = error_get_last();
                                        $flash  = '<div class="kaya-up-alert kaya-up-alert--err"><b>Upload failed while replacing file</b>.</div>';
                                        $flash .= '<div class="kaya-up-debug"><b>Target:</b> ' . esc_html($target_path) . '<br><pre>'
                                                . esc_html(print_r($err, true)) . '</pre></div>';
                                    } else {
                                        // Keep same URL so QR code does not change
                                        $pdf_url = $old_pdf_url;
                                    }
                                }
                            }
                        }

                        if ($flash === '') {
                            $row_title = $serial_number; // original case
                            $qr_box_id = 'kaya-qr-box-' . wp_generate_password(8, false, false);

                            $qepw = '[qepw_pdf_viewer file="' . esc_url($pdf_url) . '"]';

                            $kaya_qr = '
                                <div class="kaya-qr-download-wrap" id="' . esc_attr($qr_box_id) . '">
                                    <div class="kaya-qr-download-title">' . esc_html($serial_number) . '</div>
                                    <div class="kaya-qr-download-inner">
                                        [kaya_qrcode content="' . esc_url($pdf_url) . '" dynamic_content="0" download_button="0" download_align="aligncenter"]
                                    </div>
                                </div>

                                <div class="kaya-qr-download-actions">
                                    <button type="button"
                                            class="kaya-up-btn kaya-up-btn--primary kaya-download-qr-btn"
                                            data-target="' . esc_attr($qr_box_id) . '"
                                            data-filename="' . esc_attr(sanitize_file_name($serial_number)) . '-qr.png">
                                        Download QR Image
                                    </button>
                                </div>
                            ';

                            $content = '<div class="kaya-inv-page kaya-inv-page--v10">' .
                                '<div class="kaya-inv-viewer kaya-inv-viewer--qepw">' .
                                    $qepw .
                                '</div>' .
                                '<div class="kaya-inv-qr kaya-inv-qr--kaya">' .
                                    '<div class="kaya-inv-qrbox">' .
                                        $kaya_qr .
                                    '</div>';

                            $content .= '<div class="kaya-inv-meta kaya-inv-serial-number">' .
                                            '<div class="kaya-inv-label">Serial Number</div>' .
                                            '<div class="kaya-inv-text">' . esc_html($serial_number) . '</div>' .
                                        '</div>';

                            if (KAYA_INV_SHOW_FILE_URL) {
                                $content .= '<div class="kaya-inv-meta kaya-inv-urlwrap">' .
                                              '<div class="kaya-inv-label">File URL</div>' .
                                              '<div class="kaya-inv-url">' . esc_html($pdf_url) . '</div>' .
                                            '</div>';
                            }

                            $content .= '<div class="kaya-inv-meta kaya-inv-cert-availability">' .
                                            '<div class="kaya-inv-label">Certificate Availability</div>' .
                                            '<div class="kaya-inv-text">' . esc_html($today_date) . ' - ' . esc_html($expired_date) . '</div>' .
                                        '</div>';

                            $content .= '<div class="kaya-inv-meta kaya-inv-cert-days">' .
                                            '<div class="kaya-inv-label">Days Left Until Expired</div>' .
                                            '<div class="kaya-inv-cert-row">' .
                                                '<div class="kaya-inv-text">' .
                                                    '<span class="kaya-cert-countdown" data-expire="' . esc_attr($expired_date) . '">Checking...</span>' .
��X���&�����������r
D?�                                                '</div>' .
                                                '<span class="kaya-cert-status">Checking...</span>' .
                                            '</div>' .
                                        '</div>';

                            $content .= '</div></div>';

                            $post_result = false;

                            if ($post_existing) {
                                $post_result = wp_update_post([
                                    'ID'            => $post_id_existing,
                                    'post_title'    => $row_title,
                                    'post_content'  => $content,
                                    'post_category' => [$category_id],
                                ], true);
                            } else {
                                $post_result = wp_insert_post([
                                    'post_title'    => $row_title,
                                    'post_content'  => $content,
                                    'post_status'   => 'publish',
                                    'post_type'     => 'post',
                                    'post_category' => [$category_id],
                                    'post_author'   => get_current_user_id()
                                ], true);

                                if (!is_wp_error($post_result)) {
                                    $post_id_existing = (int) $post_result;
                                }
                            }

                            if (is_wp_error($post_result)) {
                                $flash = '<div class="kaya-up-alert kaya-up-alert--err">Post update failed: '
                                       . esc_html($post_result->get_error_message()) . '</div>';
                            } else {
                                $today_now   = current_time('Y-m-d');
                                $cert_status = ($expired_date < $today_now) ? 'expired' : 'active';

                                // Update database with category_name
                                $updated = $wpdb->update(
                                    $table_name,
                                    [
                                        'post_id'           => $post_id_existing,
                                        'serial_number'     => $serial_number,
                                        'serial_number_key' => $serial_number_key,
                                        'category_id'       => $category_id,
                                        'category_name'     => $category_name,
                                        'category_slug'     => $slug,
                                        'pdf_url'           => esc_url_raw($pdf_url),
                                        'today_date'        => $today_date,
                                        'expired_date'      => $expired_date,
                                        'cert_status'       => $cert_status,
                                    ],
                                    ['id' => $edit_id],
                                    ['%d','%s','%s','%d','%s','%s','%s','%s','%s','%s'],
                                    ['%d']
                                );

                                if ($updated === false) {
                                    $flash = '<div class="kaya-up-alert kaya-up-alert--err"><b>Post updated but DB update failed.</b><div class="kaya-up-small">'
                                           . esc_html($wpdb->last_error) . '</div></div>';
                                } else {
                                    // Update post meta (including category fields)
                                    update_post_meta($post_id_existing, '_kaya_invoice_post', 1);
                                    update_post_meta($post_id_existing, '_kaya_invoice_pdf_url', esc_url_raw($pdf_url));

                                    update_post_meta($post_id_existing, '_kaya_category_id', $category_id);
                                    update_post_meta($post_id_existing, '_kaya_category_name', $category_name);
                                    update_post_meta($post_id_existing, '_kaya_category_slug', $slug);

                                    update_post_meta($post_id_existing, '_kaya_cert_row_id', $edit_id);
                                    update_post_meta($post_id_existing, '_kaya_serial_number', $serial_number);
                                    update_post_meta($post_id_existing, '_kaya_serial_number_key', $serial_number_key);
                                    update_post_meta($post_id_existing, '_kaya_today_date', $today_date);
                                    update_post_meta($post_id_existing, '_kaya_expired_date', $expired_date);
                                    update_post_meta($post_id_existing, '_kaya_cert_status', $cert_status);

                                    $success_popup = [
                                        'title'    => 'Update Successful!',
                                        'text'     => 'Certificate has been updated successfully.',
                                        'view_url' => get_permalink($post_id_existing),
                                        'pdf_url'  => $pdf_url,
                                    ];

                                    // refresh data shown in form
                                    $existing = $wpdb->get_row(
                                        $wpdb->prepare("SELECT * FROM {$table_name} WHERE id = %d LIMIT 1", $edit_id),
                                        ARRAY_A
                                    );
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    $default_serial = isset($existing['serial_number']) ? (string) $existing['serial_number'] : '';
    $default_category_id = isset($existing['category_id']) ? absint($existing['category_id']) : 0;
    $default_today = !empty($existing['today_date']) ? (string) $existing['today_date'] : current_time('Y-m-d');
    $default_expired = !empty($existing['expired_date']) ? (string) $existing['expired_date'] : date('Y-m-d', strtotime($default_today . ' +1 year -1 day'));
    $current_pdf_url = isset($existing['pdf_url']) ? (string) $existing['pdf_url'] : '';
    $view_post_url = !empty($existing['post_id']) ? get_permalink((int)$existing['post_id']) : '';

    ob_start();
    ?>
    <div class="kaya-up">
        <div class="kaya-up-shell">
            <?php echo $flash; ?>

            <div class="kaya-up-card">
                <form method="post" enctype="multipart/form-data" id="kayaPdfEditForm">
                    <?php wp_nonce_field('kaya_pdf_edit_action', 'kaya_pdf_edit_nonce'); ?>
                    <input type="hidden" name="edit_id" id="edit_id" value="<?php echo esc_attr($edit_id); ?>">

                    <div class="kaya-up-top">
                        <div class="kaya-up-field">
                            <label>Serial Number</label>
                            <!-- ✅ Made read‑only to prevent QR code breakage -->
                            <input type="text" name="serial_number" id="serial_number"
                                   value="<?php echo esc_attr($default_serial); ?>"
                                   required readonly
                                   style="background:#f8fafc; color:#475569; cursor:not-allowed;">
                        </div>

                        <div class="kaya-up-field">
                            <label>Category</label>
                            <select name="post_category" required>
                                <?php
                                $categories = get_terms([
                                    'taxonomy'   => 'category',
                                    'hide_empty' => false
                                ]);
                                if (!is_wp_error($categories) && $categories) {
                                    foreach ($categories as $cat) {
                                        echo '<option value="' . esc_attr($cat->term_id) . '" ' . selected($default_category_id, $cat->term_id, false) . '>' . esc_html($cat->name) . '</option>';
                                    }
                                }
                                ?>
                            </select>
                        </div>
                    </div>

                    <div class="kaya-up-top">
                        <div class="kaya-up-field">
                            <label>Today Date</label>
                            <input type="date" name="today_date" id="kayaTodayDate" value="<?php echo esc_attr($default_today); ?>" required>
                        </div>

                        <div class="kaya-up-field">
                            <label>Expired Date</label>
                            <input type="date" name="expired_date" id="kayaExpiredDate" value="<?php echo esc_attr($default_expired); ?>" required>
                        </div>
                    </div>

                    <?php if ($current_pdf_url): ?>
                    <div class="kaya-up-alert kaya-up-alert--warn" style="margin-bottom:14px;">
                        Current PDF:
                        <a href="<?php echo esc_url($current_pdf_url); ?>" target="_blank" rel="noopener">Open current PDF</a>
                        <?php if ($view_post_url): ?>
                            | <a href="<?php echo esc_url($view_post_url); ?>" target="_blank" rel="noopener">View current page</a>
                        <?php endif; ?>
                    </div>
                    <?php endif; ?>

                    <div class="kaya-up-drop" id="kayaDrop">
                        <div class="kaya-up-illu" aria-hidden="true">
                            <svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                                <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
                                <path d="M14 2v6h6"/>
                                <path d="M12 18v-6"/>
                                <path d="M9.5 14.5 12 12l2.5 2.5"/>
                            </svg>
                        </div>

                        <div class="kaya-up-title">Replace PDF (optional)</div>
                        <div class="kaya-up-or">or keep current file</div>

                        <button type="button" class="kaya-up-btn kaya-up-btn--primary" id="kayaPickBtn">
                            Upload New PDF
                        </button>

                        <div class="kaya-up-note">PDF up to <?php echo esc_html($max_mb_text); ?></div>

                        <div class="kaya-up-filehint" id="kayaFileHint" style="display:none;">
                            <span>Selected:</span> <b id="kayaFileName"></b>
                        </div>

                        <input type="file" name="pdf_file" accept="application/pdf" id="kayaFileInput">
                    </div>

                    <div style="margin-top:14px; display:flex; justify-content:center;">
                        <button type="button" id="kaya_cert_submit_btn" class="kaya-up-btn kaya-up-btn--primary" style="min-width:320px;">
                            Save Changes
                        </button>
                    </div>
                </form>
            </div>
        </div>
    </div>

    <script>
        window.kayaCertEditAjax = {
            ajaxUrl: <?php echo wp_json_encode(admin_url('admin-ajax.php')); ?>,
            nonce: <?php echo wp_json_encode(wp_create_nonce('kaya_check_serial_nonce')); ?>,
            currentId: <?php echo wp_json_encode($edit_id); ?>
        };
    </script>

    <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>

    <script>
    (function() {
        document.addEventListener('DOMContentLoaded', function() {
            const drop = document.getElementById('kayaDrop');
            const fileInput = document.getElementById('kayaFileInput');
            const pickBtn = document.getElementById('kayaPickBtn');
            const hint = document.getElementById('kayaFileHint');
            const nameEl = document.getElementById('kayaFileName');
            const todayInput = document.getElementById('kayaTodayDate');
            const expiredInput = document.getElementById('kayaExpiredDate');
            const form = document.getElementById('kayaPdfEditForm');
            const submitBtn = document.getElementById('kaya_cert_submit_btn');
            const serialInput = document.getElementById('serial_number');

            function calculateExpiredDate(todayStr){
                if (!todayStr || !/^\d{4}-\d{2}-\d{2}$/.test(todayStr)) return '';
                const parts = todayStr.split('-');
                const year = parseInt(parts[0], 10);
                const month = parseInt(parts[1], 10);
                const day = parseInt(parts[2], 10);
                const base = new Date(Date.UTC(year, month - 1, day));
                if (isNaN(base.getTime())) return '';
                const result = new Date(base);
                result.setUTCFullYear(result.getUTCFullYear() + 1);
                result.setUTCDate(result.getUTCDate() - 1);
                const yyyy = result.getUTCFullYear();
                const mm = String(result.getUTCMonth() + 1).padStart(2, '0');
                const dd = String(result.getUTCDate()).padStart(2, '0');
                return `${yyyy}-${mm}-${dd}`;
            }

            function syncExpiredDate(){
                if (!todayInput || !expiredInput) return;
                const suggested = calculateExpiredDate(todayInput.value);
                if (suggested) expiredInput.value = suggested;
            }

            if (todayInput && expiredInput) {
                todayInput.addEventListener('change', syncExpiredDate);
                todayInput.addEventListener('input', syncExpiredDate);
            }

            if (drop && fileInput) {
                function showFileName(){
                    const f = fileInput.files && fileInput.files[0];
                    if (!f) {
                        if (hint) hint.style.display = 'none';
                        return;
                    }
                    if (hint) hint.style.display = 'block';
                    if (nameEl) nameEl.textContent = f.name;
                }

                if (pickBtn){
                    pickBtn.addEventListener('click', function(e){
                        e.preventDefault();
                        fileInput.click();
                    });
                }

                fileInput.addEventListener('change', showFileName);

                ['dragenter','dragover'].forEach(function(evt){
                    drop.addEventListener(evt, function(e){
                        e.preventDefault();
                        e.stopPropagation();
                        drop.classList.add('is-drag');
                    });
                });

                ['dragleave','drop'].forEach(function(evt){
                    drop.addEventListener(evt, function(e){
                        e.preventDefault();
                        e.stopPropagation();
                        drop.classList.remove('is-drag');
                    });
                });

                drop.addEventListener('drop', function(e){
                    if (!e.dataTransfer || !e.dataTransfer.files || !e.dataTransfer.files.length) return;
                    fileInput.files = e.dataTransfer.files;
                    showFileName();
                });
            }

            if (form && submitBtn && serialInput) {
                submitBtn.addEventListener('click', async function(e) {
                    e.preventDefault();

                    // Preserve original case – do NOT convert to lowercase
                    let serialNumber = (serialInput.value || '').trim();
                    serialInput.value = serialNumber;

                    if (!serialNumber) {
                        alert('Serial number is required.');
                        serialInput.focus();
                       ���r�>h��������l�@*
D�����rror',
                                title: 'Serial Number Already Exists',
                                text: 'Another current certificate already uses this serial number.'
                            });
                            submitBtn.disabled = false;
                            submitBtn.textContent = 'Save Changes';
                            return;
                        }

                        submitBtn.textContent = 'Saving...';
                        form.submit();

                    } catch (err) {
                        console.error('AJAX error:', err);
                        await Swal.fire({
                            icon: 'error',
                            title: 'Submission Error',
                            text: err.message || 'An unexpected error occurred.'
                        });
                        submitBtn.disabled = false;
                        submitBtn.textContent = 'Save Changes';
                    }
                });
            }
        });
    })();
    </script>

    <?php if (!empty($success_popup)) : ?>
    <script>
    document.addEventListener('DOMContentLoaded', function () {
        Swal.fire({
            icon: 'success',
            title: <?php echo wp_json_encode($success_popup['title']); ?>,
            html: `
                <div style="margin-bottom:14px;">
                    <?php echo esc_js($success_popup['text']); ?>
                </div>
                <div style="display:flex; gap:10px; justify-content:center; flex-wrap:wrap;">
                    <button type="button" id="swal-view-page-btn" class="swal2-styled" style="margin:0;">
                        View Page
                    </button>
                    <button type="button" id="swal-open-pdf-btn" class="swal2-styled" style="margin:0; background:#6b7280;">
                        Open PDF
                    </button>
                </div>
            `,
            confirmButtonText: 'Close',
            allowOutsideClick: false,
            allowEscapeKey: false,
            allowEnterKey: false,
            showCloseButton: false,
            didOpen: function () {
                var viewBtn = document.getElementById('swal-view-page-btn');
                var pdfBtn  = document.getElementById('swal-open-pdf-btn');

                if (viewBtn) {
                    viewBtn.addEventListener('click', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        window.open(<?php echo wp_json_encode($success_popup['view_url']); ?>, '_blank');
                    });
                }

                if (pdfBtn) {
                    pdfBtn.addEventListener('click', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        window.open(<?php echo wp_json_encode($success_popup['pdf_url']); ?>, '_blank');
                    });
                }
            }
        });
    });
    </script>
    <?php endif; ?>

    <?php
    return ob_get_clean();
}
add_shortcode('pdf_frontend_edit', 'frontend_pdf_editor_kaya_qr');

// (The post_class filter was already removed as it belongs to the create snippet)l�@*��|����������dS
D?�      array(
                                                'post_id'           => $post_id,
                                                'serial_number'     => $serial_number,
                                                'serial_number_key' => $serial_number_key,
                                                'category_id'       => $category_id,
                                                'category_name'     => $category_name,
                                                'category_slug'     => $slug,
                                                'pdf_url'           => esc_url_raw($pdf_url),
                                                'today_date'        => $today_date,
                                                'expired_date'      => $expired_date,
                                                'renewal_of_id'     => $renewal_of_id,
                                                'replaced_by_id'    => 0,
                                                'version_no'        => 1,
                                                'is_current'        => 'T',
                                                'cert_status'       => $cert_status,
                                                'is_active'         => 'T',
                                                'created_by'        => get_current_user_id(),
                                            ),
                                            array(
                                                '%d', // post_id
                                                '%s', // serial_number
                                                '%s', // serial_number_key
                                                '%d', // category_id
                                                '%s', // category_name
                                                '%s', // category_slug
                                                '%s', // pdf_url
                                                '%s', // today_date
                                                '%s', // expired_date
                                                '%d', // renewal_of_id
                                                '%d', // replaced_by_id
                                                '%d', // version_no
                                                '%s', // is_current
                                                '%s', // cert_status
                                                '%s', // is_active
                                                '%d', // created_by
                                            )
                                        );

                                        if ($inserted === false) {
                                            $flash = '<div class="kaya-up-alert kaya-up-alert--err"><b>Upload succeeded but DB insert failed.</b><div class="kaya-up-small">'
                                                   . esc_html($wpdb->last_error) . '</div>'
                                                   . '<div class="kaya-up-actions">'
                                                   . '<a class="kaya-up-btn kaya-up-btn--primary" href="' . esc_url(get_permalink($post_id)) . '" target="_blank" rel="noopener">View Page</a>'
                                                   . '<a class="kaya-up-btn kaya-up-btn--ghost" href="' . esc_url($pdf_url) . '" target="_blank" rel="noopener">Open PDF</a>'
                                                   . '</div></div>';
                                        } else {
                                            $cert_row_id = (int) $wpdb->insert_id;

                                            // Update post meta with all certificate details
                                            update_post_meta($post_id, '_kaya_invoice_post', 1);
                                            update_post_meta($post_id, '_kaya_invoice_pdf_url', esc_url_raw($pdf_url));

                                            update_post_meta($post_id, '_kaya_cert_row_id', $cert_row_id);
                                            update_post_meta($post_id, '_kaya_serial_number', $serial_number);
                                            update_post_meta($post_id, '_kaya_serial_number_key', $serial_number_key);
                                            update_post_meta($post_id, '_kaya_today_date', $today_date);
                                            update_post_meta($post_id, '_kaya_expired_date', $expired_date);
                                            update_post_meta($post_id, '_kaya_cert_status', $cert_status);
                                            update_post_meta($post_id, '_kaya_cert_is_active', 'T');
                                            update_post_meta($post_id, '_kaya_cert_is_current', 'T');
                                            update_post_meta($post_id, '_kaya_cert_version_no', 1);
                                            update_post_meta($post_id, '_kaya_cert_renewal_of_id', $renewal_of_id);
                                            update_post_meta($post_id, '_kaya_cert_replaced_by_id', 0);
                                            update_post_meta($post_id, '_kaya_cert_created_by', get_current_user_id());
                                            update_post_meta($post_id, '_kaya_cert_created_at', current_time('mysql'));

                                            // Save category information in post meta
                                            update_post_meta($post_id, '_kaya_category_id', $category_id);
                                            update_post_meta($post_id, '_kaya_category_name', $category_name);
                                            update_post_meta($post_id, '_kaya_category_slug', $slug);

                                            // SUCCESS – set popup data
                                            $success_popup = array(
                                                'title'    => 'Upload Successful!',
                                                'text'     => 'Certificate has been created successfully.',
                                                'view_url' => get_permalink($post_id),
                                                'pdf_url'  => $pdf_url,
                                            );
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    $default_today = current_time('Y-m-d');

    ob_start();
    ?>
    <div class="kaya-up">
        <div class="kaya-up-shell">
            <?php echo $flash; // Only error messages will appear here ?>

            <div class="kaya-up-card">
                <form method="post" enctype="multipart/form-data" id="kayaPdfUploadForm">
                    <?php wp_nonce_field('kaya_pdf_upload_action', 'kaya_pdf_upload_nonce'); ?>
                    <!-- Hidden field to store renewal_of_id if needed (still present, but no longer used in renewal flow) -->
                    <input type="hidden" name="renewal_of_id" id="renewal_of_id" value="0">

                    <div class="kaya-up-top">
                        <div class="kaya-up-field">
                            <label>Serial Number</label>
                            <input type="text" name="serial_number" id="serial_number" placeholder="e.g. WM-2026-000123" required>
                        </div>

                        <!-- ===== IMPROVED CATEGORY DROPDOWN ===== -->
                        <div class="kaya-up-field">
                            <label>Category</label>
                            <select name="post_category" id="post_category" required>
                                <option value="" selected disabled>Please Select Category</option>
                                <?php
                                $categories = get_terms(array(
                                    'taxonomy'   => 'category',
                                    'hide_empty' => false
                                ));

                                $selected_cat = absint($_POST['post_category'] ?? 0);

                                if (!is_wp_error($categories) && $categories) {
                                    foreach ($categories as $cat) {
                                        echo '<option value="' . esc_attr($cat->term_id) . '" ' . selected($selected_cat, $cat->term_id, false) . '>'
                                            . esc_html($cat->name) .
                                        '</option>';
                                    }
                                }
                                ?>
                            </select>
                        </div>
                    </div>

                    <div class="kaya-up-top">
                        <div class="kaya-up-field">
                            <label>Today Date</label>
                            <input type="date" name="today_date" id="kayaTodayDate" value="<?php echo esc_attr($default_today); ?>" required>
                        </div>

                        <div class="kaya-up-field">
                            <label>Expired Date</label>
                            <input type="date" name="expired_date" id="kayaExpiredDate" value="<?php echo esc_attr(date('Y-m-d', strtotime($default_today . ' +1 year -1 day'))); ?>" required>
                        </div>
                    </div>

                    <div class="kaya-up-drop" id="kayaDrop">
                        <div class="kaya-up-illu" aria-hidden="true">
                            <svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                                <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
                                <path d="M14 2v6h6"/>
                                <path d="M12 18v-6"/>
                                <path d="M9.5 14.5 12 12l2.5 2.5"/>
                            </svg>
                        </div>

                        <div class="kaya-up-title">Drag &amp; drop your file</div>
                        <div class="kaya-up-or">or</div>

                        <button type="button" class="kaya-up-btn kaya-up-btn--primary" id="kayaPickBtn">
                            Upload PDF
                        </button>

                        <div class="kaya-up-note">PDF up to <?php echo esc_html($max_mb_text); ?></div>

                        <div class="kaya-up-filehint" id="kayaFileHint" style="display:none;">
                            <span>Selected:</span> <b id="kayaFileName"></b>
                        </div>

                        <input type="file" name="pdf_file" accept="application/pdf" required id="kayaFileInput">
                    </div>

                    <div style="margin-top:14px; display:flex; justify-content:center;">
                        <!-- This button is type="button", not "submit" -->
                        <button type="button" id="kaya_cert_submit_btn" class="kaya-up-btn kaya-up-btn--primary" style="min-width:320px;">
                            Submit Upload
                        </button>
                    </div>
                </form>
            </div>
        </div>
    </div>

    <script>
        window.kayaCertAjax = {
            ajaxUrl: <?php echo wp_json_encode(admin_url('admin-ajax.php')); ?>,
            nonce: <?php echo wp_json_encode(wp_create_nonce('kaya_check_serial_nonce')); ?>,
            certificateListUrl: <?php echo wp_json_encode('https://cert.weldmaster.my/?page_id=162'); ?>
        };
    </script>

    <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>

    <script>
    (function() {
        document.addEventListener('DOMContentLoaded', function() {
            const drop = document.getElementById('kayaDrop');
            const fileInput = document.getElementById('kayaFileInput');
            const pickBtn = document.getElementById('kayaPickBtn');
            const hint = document.getElementById('kayaFileHint');
            const nameEl = document.getElementById('kayaFileName');
            const todayInput = document.getElementById('kayaTodayDate');
            const expiredInput = document.getElementById('kayaExpiredDate');
            const form = document.getElementById('kayaPdfUploadForm');
            const submitBtn = document.getElementById('kaya_cert_submit_btn');
            const serialInput = document.getElementById('serial_number');

            // Date sync
            function calculateExpiredDate(todayStr){
                if (!todayStr || !/^\d{4}-\d{2}-\d{2}$/.test(todayStr)) return '';
                const parts = todayStr.split('-');
                const year = parseInt(parts[0], 10);
                const month = parseInt(parts[1], 10);
                const day = parseInt(parts[2], 10);
                const base = new Date(Date.UTC(year, month - 1, day));
                if (isNaN(base.getTime())) return '';
                const result = new Date(base);
                result.setUTCFullYear(result.getUTCFullYear() + 1);
                result.setUTCDate(result.getUTCDate() - 1);
                const yyyy = result.getUTCFullYear();
                const mm = String(result.getUTCMonth() + 1).padStart(2, '0');
                const dd = String(result.getUTCDate()).padStart(2, '0');
                return `${yyyy}-${mm}-${dd}`;
            }

            function syncExpiredDate(){
                if (!todayInput || !expiredInput) return;
                const suggested = calculateExpiredDate(todayInput.value);
                if (suggested) expiredInput.value = suggested;
            }

            if (todayInput && expiredInput) {
                syncExpiredDate();
                todayInput.addEventListener('change', syncExpiredDate);
                todayInput.addEventListener('input', syncExpiredDate);
            }

            // Drag & drop
            if (drop && fileInput) {
                function showFileName(){
                    const f = fileInput.files && fileInput.files[0];
                    if (!f) {
                        if (hint) hint.style.display = 'none';
                        return;
                    }
                    if (hint) hint.style.display = 'block';
                    if (nameEl) nameEl.textContent = f.name;
                }

                if (pickBtn){
                    pickBtn.addEventListener('click', function(e){
                        e.preventDefault();
                        fileInput.click();
                    });
                }

                fileInput.addEventListener('change', showFileName);

                ['dragenter','dragover'].forEach(function(evt){
                    drop.addEventListener(evt, function(e){
                        e.preventDefault();
                        e.stopPropagation();
                        drop.classList.add('is-drag');
                    });
                });

                ['dragleave','drop'].forEach(function(evt){
                    drop.addEventListener(evt, function(e){
                        e.preventDefault();
                        e.stopPropagation();
                        drop.classList.remove('is-drag');
                    });
                });

                drop.addEventListener('drop', function(e){
                    if (!e.dataTransfer || !e.dataTransfer.files || !e.dataTransfer.files.length) return;
                    fileInput.files = e.dataTransfer.files;
                    showFileName();
                });
            }

            // QR download
            document.addEventListener('click', function(e){
                const btn = e.target.closest('.kaya-download-qr-btn');
                if (!btn) return;
                const targetId = btn.getAttribute('data-target');
                const filename = btn.getAttribute('data-filename') || 'qr-image.png';
                const box = document.getElementById(targetId);
                if (!box || typeof html2canvas === 'undefined') {
                    al��dS/�������������dS
D0����ert('QR image downloader is not ready.');
                    return;
                }
                html2canvas(box, {
                    backgroundColor: '#ffffff',
                    scale: 2,
                    useCORS: true
                }).then(function(canvas){
                    const link = document.createElement('a');
                    link.download = filename;
                    link.href = canvas.toDataURL('image/png');
                    link.click();
                }).catch(function(err){
                    console.error(err);
                    alert('Failed to download QR image.');
                });
            });

            // Main submit handler
            if (form && submitBtn && serialInput) {
                submitBtn.addEventListener('click', async function(e) {
                    e.preventDefault();

                    // ===== BROWSER VALIDATION =====
                    if (!form.reportValidity()) {
                        return;
                    }

                    // Preserve original case – do NOT convert to lowercase
                    let serialNumber = (serialInput.value || '').trim();
                    serialInput.value = serialNumber;

                    if (!serialNumber) {
                        alert('Serial number is required.');
                        serialInput.focus();
                        return;
                    }

                    submitBtn.disabled = true;
                    submitBtn.textContent = 'Checking...';

                    try {
                        const fd = new FormData();
                        fd.append('action', 'kaya_check_existing_certificate_serial');
                        fd.append('nonce', window.kayaCertAjax.nonce);
                        fd.append('serial_number', serialNumber); // send original case

                        const response = await fetch(window.kayaCertAjax.ajaxUrl, {
                            method: 'POST',
                            credentials: 'same-origin',
                            body: fd
                        });

                        const result = await response.json();

                        if (!result.success) {
                            await Swal.fire({
                                icon: 'error',
                                title: 'Check Failed',
                                text: result.data?.message || 'Unable to verify serial number.'
                            });
                            submitBtn.disabled = false;
                            submitBtn.textContent = 'Submit Upload';
                            return;
                        }

                        // Duplicate handling now redirects to certificate list with search
                        if (result.data.exists) {
                            const infoText = 'This serial number already exists.' +
                                (result.data.expired_date ? ' Current certificate expires on ' + result.data.expired_date + '.' : '') +
                                ' Click below to open the certificate list filtered to this serial number.';

                            const swalResult = await Swal.fire({
                                icon: 'warning',
                                title: 'Serial Number Already Exists',
                                text: infoText,
                                showCancelButton: true,
                                confirmButtonText: 'View Existing Certificate',
                                cancelButtonText: 'Cancel',
                                reverseButtons: true
                            });

                            if (!swalResult.isConfirmed) {
                                submitBtn.disabled = false;
                                submitBtn.textContent = 'Submit Upload';
                                return;
                            }

                            const url = new URL(window.kayaCertAjax.certificateListUrl);
                            // Use the stored original serial number for the search
                            url.searchParams.set('kaya_search', result.data.serial_number || serialNumber);

                            window.location.href = url.toString();
                            return;
                        }

                        // No duplicate – submit the form
                        submitBtn.textContent = 'Submitting...';
                        form.submit();

                    } catch (err) {
                        console.error('AJAX error:', err);
                        await Swal.fire({
                            icon: 'error',
                            title: 'Submission Error',
                            text: err.message || 'An unexpected error occurred.'
                        });
                        submitBtn.disabled = false;
                        submitBtn.textContent = 'Submit Upload';
                    }
                });
            }
        });
    })();
    </script>

    <?php
    // SUCCESS POPUP WITH CUSTOM BUTTONS
    if (!empty($success_popup)) :
    ?>
    <script>
    document.addEventListener('DOMContentLoaded', function () {
        Swal.fire({
            icon: 'success',
            title: <?php echo wp_json_encode($success_popup['title']); ?>,
            html: `
                <div style="margin-bottom:14px;">
                    <?php echo esc_js($success_popup['text']); ?>
                </div>
                <div style="display:flex; gap:10px; justify-content:center; flex-wrap:wrap;">
                    <button type="button" id="swal-view-page-btn" class="swal2-styled" style="margin:0;">
                        View Page
                    </button>
                    <button type="button" id="swal-open-pdf-btn" class="swal2-styled" style="margin:0; background:#6b7280;">
                        Open PDF
                    </button>
                </div>
            `,
            confirmButtonText: 'Close',
            allowOutsideClick: false,
            allowEscapeKey: false,
            allowEnterKey: false,
            showCloseButton: false,
            didOpen: function () {
                var viewBtn = document.getElementById('swal-view-page-btn');
                var pdfBtn  = document.getElementById('swal-open-pdf-btn');

                if (viewBtn) {
                    viewBtn.addEventListener('click', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        window.open(<?php echo wp_json_encode($success_popup['view_url']); ?>, '_blank');
                    });
                }

                if (pdfBtn) {
                    pdfBtn.addEventListener('click', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        window.open(<?php echo wp_json_encode($success_popup['pdf_url']); ?>, '_blank');
                    });
                }
            }
        });
    });
    </script>
    <?php
    endif;

    return ob_get_clean();
}
add_shortcode('pdf_frontend_upload', 'frontend_pdf_uploader_kaya_qr');��dS�\'�����������r
D8���� return;
                    }

                    submitBtn.disabled = true;
                    submitBtn.textContent = 'Checking...';

                    try {
                        const fd = new FormData();
                        fd.append('action', 'kaya_check_existing_certificate_serial_for_edit');
                        fd.append('nonce', window.kayaCertEditAjax.nonce);
                        fd.append('serial_number', serialNumber);
                        fd.append('current_id', window.kayaCertEditAjax.currentId);

                        const response = await fetch(window.kayaCertEditAjax.ajaxUrl, {
                            method: 'POST',
                            credentials: 'same-origin',
                            body: fd
                        });

                        const result = await response.json();

                        if (!result.success) {
                            await Swal.fire({
                                icon: 'error',
                                title: 'Check Failed',
                                text: result.data?.message || 'Unable to verify serial number.'
                            });
                            submitBtn.disabled = false;
                            submitBtn.textContent = 'Save Changes';
                            return;
                        }

                        if (result.data.exists) {
                            await Swal.fire({
                                icon: 'error',
                                title: 'Serial Number Already Exists',
                                text: 'Another current certificate already uses this serial number.'
                            });
                            submitBtn.disabled = false;
                            submitBtn.textContent = 'Save Changes';
                            return;
                        }

                        submitBtn.textContent = 'Saving...';
                        form.submit();

                    } catch (err) {
                        console.error('AJAX error:', err);
                        await Swal.fire({
                            icon: 'error',
                            title: 'Submission Error',
                            text: err.message || 'An unexpected error occurred.'
                        });
                        submitBtn.disabled = false;
                        submitBtn.textContent = 'Save Changes';
                    }
                });
            }
        });
    })();
    </script>

    <?php if (!empty($success_popup)) : ?>
    <script>
    document.addEventListener('DOMContentLoaded', function () {
        Swal.fire({
            icon: 'success',
            title: <?php echo wp_json_encode($success_popup['title']); ?>,
            html: `
                <div style="margin-bottom:14px;">
                    <?php echo esc_js($success_popup['text']); ?>
                </div>
                <div style="display:flex; gap:10px; justify-content:center; flex-wrap:wrap;">
                    <button type="button" id="swal-view-page-btn" class="swal2-styled" style="margin:0;">
                        View Page
                    </button>
                    <button type="button" id="swal-open-pdf-btn" class="swal2-styled" style="margin:0; background:#6b7280;">
                        Open PDF
                    </button>
                </div>
            `,
            confirmButtonText: 'Close',
            allowOutsideClick: false,
            allowEscapeKey: false,
            allowEnterKey: false,
            showCloseButton: false,
            didOpen: function () {
                var viewBtn = document.getElementById('swal-view-page-btn');
                var pdfBtn  = document.getElementById('swal-open-pdf-btn');

                if (viewBtn) {
                    viewBtn.addEventListener('click', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        window.open(<?php echo wp_json_encode($success_popup['view_url']); ?>, '_blank');
                    });
                }

                if (pdfBtn) {
                    pdfBtn.addEventListener('click', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        window.open(<?php echo wp_json_encode($success_popup['pdf_url']); ?>, '_blank');
                    });
                }
            }
        });
    });
    </script>
    <?php endif; ?>

    <?php
    return ob_get_clean();
}
add_shortcode('pdf_frontend_edit', 'frontend_pdf_editor_kaya_qr');���ryk�'�����������
D?�/**
 * FRONTEND PDF RENEWAL SHORTCODE + AJAX SERIAL CHECK
 * Shortcode: [pdf_frontend_renewal]
 *
 * - Renews an existing certificate row using ?renew_id=ID
 * - Creates a NEW wp_kaya_certificates row and a NEW WP post
 * - Marks old certificate as no longer current and links it to the new one
 * - Serial number stays the same and preserves original casing for display/storage
 * - Uses serial_number_key for case-insensitive renewal validation
 * - PDF upload is required for renewal
 * - Success popup contains custom "View Page" and "Open PDF" buttons
 */

if (!defined('ABSPATH')) exit;

/** =========================
 * SETTINGS
 * ========================= */
if (!defined('KAYA_INV_SHOW_FILE_URL')) {
    define('KAYA_INV_SHOW_FILE_URL', true);
}
if (!defined('KAYA_INV_QR_FILENAME_PREFIX')) {
    define('KAYA_INV_QR_FILENAME_PREFIX', 'QR-');
}

/** =========================
 * HELPERS (wrapped to avoid redeclaration)
 * ========================= */

if (!function_exists('kaya_certificates_table_exists')) {
    function kaya_certificates_table_exists() {
        global $wpdb;
        $table_name = $wpdb->prefix . 'kaya_certificates';
        $found = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table_name));
        return ($found === $table_name);
    }
}

if (!function_exists('kaya_cert_get_existing_pdf_filename')) {
    function kaya_cert_get_existing_pdf_filename($pdf_url) {
        $path = wp_parse_url($pdf_url, PHP_URL_PATH);
        if (!$path) return '';
        return basename($path);
    }
}

if (!function_exists('kaya_normalize_serial_key')) {
    function kaya_normalize_serial_key($serial) {
        return strtolower(trim((string) $serial));
    }
}

/** =========================
 * AJAX HANDLER – Validate renewal source
 * Ensures the source row is still the current active certificate
 * ========================= */
function kaya_check_existing_certificate_serial_for_renewal() {
    if (!is_user_logged_in()) {
        wp_send_json_error(['message' => 'Unauthorized.'], 403);
    }

    $current_user = wp_get_current_user();
    if (!array_intersect(['administrator', 'editor'], (array) $current_user->roles)) {
        wp_send_json_error(['message' => 'Permission denied.'], 403);
    }

    check_ajax_referer('kaya_check_serial_nonce', 'nonce');

    global $wpdb;
    $table_name = $wpdb->prefix . 'kaya_certificates';

    $raw_serial        = sanitize_text_field(wp_unslash($_POST['serial_number'] ?? ''));
    $serial_number     = trim($raw_serial);                 // preserve original case
    $serial_number_key = kaya_normalize_serial_key($serial_number);
    $renew_id          = absint($_POST['renew_id'] ?? 0);

    if ($serial_number === '') {
        wp_send_json_error(['message' => 'Serial number is required.'], 400);
    }

    if ($renew_id <= 0) {
        wp_send_json_error(['message' => 'Invalid renewal source.'], 400);
    }

    $source_row = $wpdb->get_row(
        $wpdb->prepare("
            SELECT id, serial_number, serial_number_key, today_date, expired_date, post_id, is_active, is_current
            FROM {$table_name}
            WHERE id = %d
            LIMIT 1
        ", $renew_id),
        ARRAY_A
    );

    if (!$source_row) {
        wp_send_json_error(['message' => 'Source certificate not found.'], 404);
    }

    if (($source_row['is_active'] ?? '') !== 'T' || ($source_row['is_current'] ?? '') !== 'T') {
        wp_send_json_error(['message' => 'This certificate is no longer the current active record and cannot be renewed.'], 409);
    }

    $source_serial_key = !empty($source_row['serial_number_key'])
        ? (string) $source_row['serial_number_key']
        : kaya_normalize_serial_key((string) $source_row['serial_number']);

    if ($source_serial_key !== $serial_number_key) {
        wp_send_json_error(['message' => 'Serial number does not match the selected renewal source.'], 409);
    }

    wp_send_json_success([
        'valid'         => true,
        'id'            => (int) $source_row['id'],
        'serial_number' => (string) $source_row['serial_number'],
        'today_date'    => !empty($source_row['today_date']) ? $source_row['today_date'] : '',
        'expired_date'  => !empty($source_row['expired_date']) ? $source_row['expired_date'] : '',
        'post_id'       => (int) $source_row['post_id'],
    ]);
}
add_action('wp_ajax_kaya_check_existing_certificate_serial_for_renewal', 'kaya_check_existing_certificate_serial_for_renewal');

/** =========================
 * SHORTCODE – RENEWAL FORM
 * ========================= */
function frontend_pdf_renewal_kaya_qr() {

    if (!is_user_logged_in()) {
        return '<div class="kaya-up-alert kaya-up-alert--warn">Please login to renew certificate.</div>';
    }

    $current_user = wp_get_current_user();
    if (!array_intersect(['administrator','editor'], (array) $current_user->roles)) {
        return '<div class="kaya-up-alert kaya-up-alert--err">Only administrators or editors can renew certificates.</div>';
    }

    if (!kaya_certificates_table_exists()) {
        return '<div class="kaya-up-alert kaya-up-alert--err">Certificate table is missing. Please enable the table setup snippet first.</div>';
    }

    global $wpdb;
    $table_name = $wpdb->prefix . 'kaya_certificates';

    $flash = '';
    $success_popup = null;

    $BASE_REL = 'FILES';
    $max_mb_text = '100 MB';

    $renew_id = absint($_GET['renew_id'] ?? 0);
    if ($renew_id <= 0) {
        return '<div class="kaya-up-alert kaya-up-alert--err">Missing or invalid renew_id.</div>';
    }

    $existing = $wpdb->get_row(
        $wpdb->prepare("
            SELECT *
            FROM {$table_name}
            WHERE id = %d
              AND is_active = 'T'
              AND is_current = 'T'
            LIMIT 1
        ", $renew_id),
        ARRAY_A
    );

    if (!$existing) {
        return '<div class="kaya-up-alert kaya-up-alert--err">Current certificate record not found or already renewed.</div>';
    }

    $post_id_existing = isset($existing['post_id']) ? absint($existing['post_id']) : 0;
    $view_post_url = $post_id_existing ? get_permalink($post_id_existing) : '';
    $current_pdf_url = isset($existing['pdf_url']) ? (string) $existing['pdf_url'] : '';

    if ($_SERVER['REQUEST_METHOD'] === 'POST' &&
        isset($_POST['kaya_pdf_renewal_nonce']) &&
        wp_verify_nonce($_POST['kaya_pdf_renewal_nonce'], 'kaya_pdf_renewal_action')) {

        $posted_renew_id = absint($_POST['renew_id'] ?? 0);

        if ($posted_renew_id !== $renew_id) {
            $flash = '<div class="kaya-up-alert kaya-up-alert--err">Renewal source mismatch.</div>';
        } else {
            // Preserve original case, build key
            $raw_serial        = sanitize_text_field(wp_unslash($_POST['serial_number'] ?? ''));
            $serial_number     = trim($raw_serial);                 // original case
            $serial_number_key = kaya_normalize_serial_key($serial_number);

            $category_id   = absint($_POST['post_category'] ?? 0);
            $today_date    = sanitize_text_field(wp_unslash($_POST['today_date'] ?? ''));
            $expired_date  = sanitize_text_field(wp_unslash($_POST['expired_date'] ?? ''));
            $category      = get_term($category_id, 'category');
            $category_name = ($category && !is_wp_error($category)) ? $category->name : '';

            if ($serial_number === '') {
                $flash = '<div class="kaya-up-alert kaya-up-alert--err">Please fill in Serial Number.</div>';
            } elseif (!$category || is_wp_error($category)) {
                $flash = '<div class="kaya-up-alert kaya-up-alert--err">Invalid category.</div>';
            } elseif ($today_date === '') {
                $flash = '<div class="kaya-up-alert kaya-up-alert--err">Please fill in Today Date.</div>';
            } elseif (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $today_date)) {
                $flash = '<div class="kaya-up-alert kaya-up-alert--err">Invalid today date format.</div>';
            } else {

                if ($expired_date === '') {
                    $today_dt = DateTime::createFromFormat('Y-m-d', $today_date);
                    if (!$today_dt || $today_dt->format('Y-m-d') !== $today_date) {
                        $flash = '<div class="kaya-up-alert kaya-up-alert--err">Invalid today date value.</div>';
                    } else {
                        $expired_dt = clone $today_dt;
                        $expired_dt->modify('+1 year');
                        $expired_dt->modify('-1 day');
                        $expired_date = $expired_dt->format('Y-m-d');
                    }
                }

                if ($flash === '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $expired_date)) {
                    $flash = '<div class="kaya-up-alert kaya-up-alert--err">Invalid expired date format.</div>';
                }

                // Re-validate source row server-side (case‑insensitive using key)
                if ($flash === '') {
                    $source_current = $wpdb->get_row(
                        $wpdb->prepare("
                            SELECT id, serial_number, serial_number_key, version_no, is_active, is_current
                            FROM {$table_name}
                            WHERE id = %d
                            LIMIT 1
                        ", $renew_id),
                        ARRAY_A
                    );

                    if (!$source_current) {
                        $flash = '<div class="kaya-up-alert kaya-up-alert--err">Source certificate no longer exists.</div>';
                    } elseif (($source_current['is_active'] ?? '') !== 'T' || ($source_current['is_current'] ?? '') !== 'T') {
                        $flash = '<div class="kaya-up-alert kaya-up-alert--err">This certificate is no longer the current active record and cannot be renewed.</div>';
                    } else {
                        $source_serial_key = !empty($source_current['serial_number_key'])
                            ? (string) $source_current['serial_number_key']
                            : kaya_normalize_serial_key((string) $source_current['serial_number']);

                        if ($source_serial_key !== $serial_number_key) {
                            $flash = '<div class="kaya-up-alert kaya-up-alert--err">Serial number does not match the selected renewal source.</div>';
                        }
                    }
                }

                if ($flash === '') {
                    $slug = sanitize_title($category->slug);

                    if ($slug === '') {
                        $flash = '<div class="kaya-up-alert kaya-up-alert--err">Category slug is empty.</div>';
                    } else {
                        $folder_name = strtoupper($slug);

                        $target_dir = rtrim(ABSPATH, '/\\') . DIRECTORY_SEPARATOR
                                    . trim($BASE_REL, '/\\') . DIRECTORY_SEPARATOR
                                    . $folder_name . DIRECTORY_SEPARATOR;

                        $base_url = home_url('/' . trim($BASE_REL, '/\\') . '/' . $folder_name . '/');

                        if (!is_dir($target_dir)) {
                            $flash = '<div class="kaya-up-alert kaya-up-alert--err"><b>Folder does not exist</b><div class="kaya-up-small">'
                                   . esc_html($target_dir) . '</div></div>';
                        } elseif (!is_writable($target_dir)) {
                            $flash = '<div class="kaya-up-alert kaya-up-alert--err"><b>Folder not writable</b><div class="kaya-up-small">'
                                   . esc_html($target_dir) . '</div></div>';
                        } else {

                            $new_file_uploaded = !empty($_FILES['pdf_file']['name']);

                            if (!$new_file_uploaded) {
                                $flash = '<div class="kaya-up-alert kaya-up-alert--err">Please upload the renewed PDF file.</div>';
                            } else {
                                $file  = $_FILES['pdf_file'];
                                $check = wp_check_filetype_and_ext($file['tmp_name'], $file['name']);
                                $ext   = strtolower((string)($check['ext'] ?? ''));

                                if ($ext !== 'pdf') {
                                    $flash = '<div class="kaya-up-alert kaya-up-alert--err">Only PDF allowed.</div>';
                                } else {
                                    $random      = wp_generate_password(20, false, false);
                                    $filename    = strtolower($random) . '.pdf';
                                    $target_path = $target_dir . $filename;

                                    if (!@move_uploaded_file($file['tmp_name'], $target_path)) {
                                        $err = error_get_last();
                                        $flash  = '<div class="kaya-up-alert kaya-up-alert--err"><b>Upload failed while moving file</b>.</div>';
                                        $flash .= '<div class="kaya-up-debug"><b>Target:</b> ' . esc_html($target_path) . '<br><pre>'
                                                . esc_html(print_r($err, true)) . '</pre></div>';
                                    } else {
                                        $pdf_url   = $base_url . rawurlencode($filename);
                                        $row_title = $serial_number;
                                        $qr_box_id = 'kaya-qr-box-' . wp_generate_password(8, false, false);

                                        $qepw = '[qepw_pdf_viewer file="' . esc_url($pdf_url) . '"]';

                                        $kaya_qr = '
                                            <div class="kaya-qr-download-wrap" id="' . esc_attr($qr_box_id) . '">
                                                <div class="kaya-qr-download-title">' . esc_html($serial_number) . '</div>
                                                <div class="kaya-qr-download-inner">
                                                    [kaya_qrcode content="' . esc_url($pdf_url) . '" dynamic_content="0" download_button="0" download_align="aligncenter"]
                                                </div>
                                            </div>

                                            <div class="kaya-qr-download-actions">
                                                <button type="button"
                                                        class="kaya-up-btn kaya-up-btn--primary kaya-download-qr-btn"
                                                        data-target="' . esc_attr($qr_box_id) . '"
                                                        data-filename="' . esc_attr(sanitize_file_name($serial_number)) . '-qr.png">
                                                    Download QR Image
                                                </button>
                                            </div>
                                        ';

                                        $content = '<div class="kaya-inv-page kaya-inv-page--v10">' .
                                            '<div class="kaya-inv-viewer kaya-inv-viewer--qepw">' .
                                                $qepw .
                                            '</div>' .
                                            '<div class="kaya-inv-qr kaya-inv-qr--kaya">' .
                                                '<div class="kaya-inv-qrbox">' .
                                                    $kaya_qr .
                                                '</div>';

                                        $content .= '<div class="kaya-inv-meta kaya-inv-serial-number">' .
                                                        '<div class="kaya-inv-label">Serial Number</div>' .
                                                        '<div class="kaya-inv-text">' . esc_html($serial_number) . '</div>' .
                                                    '</div>';

                                        if (KAYA_INV_SHOW_FILE_URL) {
                                            $content .= '<div class="kaya-inv-meta kaya-inv-urlwrap">' .
                  �����V5����������A�
D?�                                        '<div class="kaya-inv-label">File URL</div>' .
                                                          '<div class="kaya-inv-url">' . esc_html($pdf_url) . '</div>' .
                                                        '</div>';
                                        }

                                        $content .= '<div class="kaya-inv-meta kaya-inv-cert-availability">' .
                                                        '<div class="kaya-inv-label">Certificate Availability</div>' .
                                                        '<div class="kaya-inv-text">' . esc_html($today_date) . ' - ' . esc_html($expired_date) . '</div>' .
                                                    '</div>';

                                        $content .= '<div class="kaya-inv-meta kaya-inv-cert-days">' .
                                                        '<div class="kaya-inv-label">Days Left Until Expired</div>' .
                                                        '<div class="kaya-inv-cert-row">' .
                                                            '<div class="kaya-inv-text">' .
                                                                '<span class="kaya-cert-countdown" data-expire="' . esc_attr($expired_date) . '">Checking...</span>' .
                                                            '</div>' .
                                                            '<span class="kaya-cert-status">Checking...</span>' .
                                                        '</div>' .
                                                    '</div>';

                                        $content .= '</div></div>';

                                        $post_result = wp_insert_post([
                                            'post_title'    => $row_title,
                                            'post_content'  => $content,
                                            'post_status'   => 'publish',
                                            'post_type'     => 'post',
                                            'post_category' => [$category_id],
                                            'post_author'   => get_current_user_id()
                                        ], true);

                                        if (is_wp_error($post_result)) {
                                            $flash = '<div class="kaya-up-alert kaya-up-alert--err">Post creation failed: '
                                                   . esc_html($post_result->get_error_message()) . '</div>';
                                        } else {
                                            $new_post_id = (int) $post_result;
                                            $today_now   = current_time('Y-m-d');
                                            $cert_status = ($expired_date < $today_now) ? 'expired' : 'active';

                                            $old_version_no = isset($existing['version_no']) ? (int) $existing['version_no'] : 1;
                                            $new_version_no = max(1, $old_version_no + 1);

                                            $inserted = $wpdb->insert(
                                                $table_name,
                                                [
                                                    'post_id'           => $new_post_id,
                                                    'serial_number'     => $serial_number,
                                                    'serial_number_key' => $serial_number_key,
                                                    'category_id'       => $category_id,
                                                    'category_name'     => $category_name,
                                                    'category_slug'     => $slug,
                                                    'pdf_url'           => esc_url_raw($pdf_url),
                                                    'today_date'        => $today_date,
                                                    'expired_date'      => $expired_date,
                                                    'renewal_of_id'     => $renew_id,
                                                    'replaced_by_id'    => 0,
                                                    'version_no'        => $new_version_no,
                                                    'is_current'        => 'T',
                                                    'cert_status'       => $cert_status,
                                                    'is_active'         => 'T',
                                                    'created_by'        => get_current_user_id(),
                                                ],
                                                ['%d','%s','%s','%d','%s','%s','%s','%s','%s','%d','%d','%d','%s','%s','%s','%d']
                                            );

                                            if ($inserted === false) {
                                                $flash = '<div class="kaya-up-alert kaya-up-alert--err"><b>Renewal post created but DB insert failed.</b><div class="kaya-up-small">'
                                                       . esc_html($wpdb->last_error) . '</div></div>';
                                            } else {
                                                $new_cert_id = (int) $wpdb->insert_id;

                                                // Update old certificate: link to new one and mark as not current
                                                $old_updated = $wpdb->update(
                                                    $table_name,
                                                    [
                                                        'replaced_by_id' => $new_cert_id,
                                                        'is_current'     => 'F',
                                                    ],
                                                    ['id' => $renew_id],
                                                    ['%d','%s'],
                                                    ['%d']
                                                );

                                                if ($old_updated === false) {
                                                    $flash = '<div class="kaya-up-alert kaya-up-alert--err"><b>Renewal created but old certificate could not be updated.</b><div class="kaya-up-small">'
                                                           . esc_html($wpdb->last_error) . '</div></div>';
                                                } else {

                                                    $old_post_ok = true;

                                                    if ($post_id_existing > 0 && get_post($post_id_existing)) {
                                                        $old_post_result = wp_update_post([
                                                            'ID'          => $post_id_existing,
                                                            'post_status' => 'draft',
                                                        ], true);

                                                        if (is_wp_error($old_post_result)) {
                                                            $old_post_ok = false;
                                                        }
                                                    }

                                                    if (!$old_post_ok) {
                                                        $flash = '<div class="kaya-up-alert kaya-up-alert--err"><b>Renewal created, but old post could not be set to draft.</b></div>';
                                                    } else {
                                                        update_post_meta($new_post_id, '_kaya_invoice_post', 1);
                                                        update_post_meta($new_post_id, '_kaya_invoice_pdf_url', esc_url_raw($pdf_url));

                                                        update_post_meta($new_post_id, '_kaya_category_id', $category_id);
                                                        update_post_meta($new_post_id, '_kaya_category_name', $category_name);
                                                        update_post_meta($new_post_id, '_kaya_category_slug', $slug);

                                                        update_post_meta($new_post_id, '_kaya_cert_row_id', $new_cert_id);
                                                        update_post_meta($new_post_id, '_kaya_serial_number', $serial_number);
                                                        update_post_meta($new_post_id, '_kaya_serial_number_key', $serial_number_key);
                                                        update_post_meta($new_post_id, '_kaya_today_date', $today_date);
                                                        update_post_meta($new_post_id, '_kaya_expired_date', $expired_date);
                                                        update_post_meta($new_post_id, '_kaya_cert_status', $cert_status);
                                                        update_post_meta($new_post_id, '_kaya_cert_is_active', 'T');
                                                        update_post_meta($new_post_id, '_kaya_cert_is_current', 'T');
                                                        update_post_meta($new_post_id, '_kaya_cert_version_no', $new_version_no);
                                                        update_post_meta($new_post_id, '_kaya_cert_renewal_of_id', $renew_id);
                                                        update_post_meta($new_post_id, '_kaya_cert_replaced_by_id', 0);
                                                        update_post_meta($new_post_id, '_kaya_cert_created_by', get_current_user_id());
                                                        update_post_meta($new_post_id, '_kaya_cert_created_at', current_time('mysql'));

                                                        $success_popup = [
                                                            'title'    => 'Renewal Successful!',
                                                            'text'     => 'Certificate renewal has been created successfully.',
                                                            'view_url' => get_permalink($new_post_id),
                                                            'pdf_url'  => $pdf_url,
                                                        ];

                                                        // refresh source data in case the same page is revisited
                                                        $existing = $wpdb->get_row(
                                                            $wpdb->prepare("SELECT * FROM {$table_name} WHERE id = %d LIMIT 1", $renew_id),
                                                            ARRAY_A
                                                        );
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    $default_serial      = isset($existing['serial_number']) ? (string) $existing['serial_number'] : '';
    $default_category_id = isset($existing['category_id']) ? absint($existing['category_id']) : 0;
    $default_today       = current_time('Y-m-d');

    $default_expired = date('Y-m-d', strtotime($default_today . ' +1 year -1 day'));

    $old_today   = !empty($existing['today_date']) ? (string) $existing['today_date'] : '';
    $old_expired = !empty($existing['expired_date']) ? (string) $existing['expired_date'] : '';

    ob_start();
    ?>
    <div class="kaya-up">
        <div class="kaya-up-shell">
            <?php echo $flash; ?>

            <div class="kaya-up-card">
                <form method="post" enctype="multipart/form-data" id="kayaPdfRenewalForm">
                    <?php wp_nonce_field('kaya_pdf_renewal_action', 'kaya_pdf_renewal_nonce'); ?>
                    <input type="hidden" name="renew_id" id="renew_id" value="<?php echo esc_attr($renew_id); ?>">

                    <div class="kaya-up-top">
                        <div class="kaya-up-field">
                            <label>Serial Number</label>
                            <input type="text" name="serial_number" id="serial_number"
                                   value="<?php echo esc_attr($default_serial); ?>"
                                   required readonly
                                   style="background:#f8fafc; color:#475569; cursor:not-allowed;">
                        </div>

                        <div class="kaya-up-field">
                            <label>Category</label>
                            <select name="post_category" required>
                                <?php
                                $categories = get_terms([
                                    'taxonomy'   => 'category',
                                    'hide_empty' => false
                                ]);
                                if (!is_wp_error($categories) && $categories) {
                                    foreach ($categories as $cat) {
                                        echo '<option value="' . esc_attr($cat->term_id) . '" ' . selected($default_category_id, $cat->term_id, false) . '>' . esc_html($cat->name) . '</option>';
                                    }
                                }
                                ?>
                            </select>
                        </div>
                    </div>

                    <div class="kaya-up-top">
                        <div class="kaya-up-field">
                            <label>Renewal Start Date</label>
                            <input type="date" name="today_date" id="kayaTodayDate" value="<?php echo esc_attr($default_today); ?>" required>
                        </div>

                        <div class="kaya-up-field">
                            <label>Renewal Expired Date</label>
                            <input type="date" name="expired_date" id="kayaExpiredDate" value="<?php echo esc_attr($default_expired); ?>" required>
                        </div>
                    </div>

                    <div class="kaya-up-alert kaya-up-alert--warn" style="margin-bottom:14px;">
                        Current certificate period:
                        <strong><?php echo esc_html($old_today ?: '-'); ?> - <?php echo esc_html($old_expired ?: '-'); ?></strong>
                        <?php if ($current_pdf_url): ?>
                            <br>Current PDF:
                            <a href="<?php echo esc_url($current_pdf_url); ?>" target="_blank" rel="noopener">Open current PDF</a>
                        <?php endif; ?>
                        <?php if ($view_post_url): ?>
                            | <a href="<?php echo esc_url($view_post_url); ?>" target="_blank" rel="noopener">View current page</a>
                        <?php endif; ?>
                    </div>

                    <div class="kaya-up-drop" id="kayaDrop">
                        <div class="kaya-up-illu" aria-hidden="true">
                            <svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                                <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
                                <path d="M14 2v6h6"/>
                                <path d="M12 18v-6"/>
                                <path d="M9.5 14.5 12 12l2.5 2.5"/>
                            </svg>
                        </div>

                        <div class="kaya-up-title">Upload Renewed PDF</div>
                        <div class="kaya-up-or">new file is required</div>

                        <button type="button" class="kaya-up-btn kaya-up-btn--primary" id="kayaPickBtn">
                         ��A��A�����������A�
D'd����   Upload New PDF
                        </button>

                        <div class="kaya-up-note">PDF up to <?php echo esc_html($max_mb_text); ?></div>

                        <div class="kaya-up-filehint" id="kayaFileHint" style="display:none;">
                            <span>Selected:</span> <b id="kayaFileName"></b>
                        </div>

                        <input type="file" name="pdf_file" accept="application/pdf" id="kayaFileInput" required>
                    </div>

                    <div style="margin-top:14px; display:flex; justify-content:center;">
                        <button type="button" id="kaya_cert_submit_btn" class="kaya-up-btn kaya-up-btn--primary" style="min-width:320px;">
                            Create Renewal
                        </button>
                    </div>
                </form>
            </div>
        </div>
    </div>

    <script>
        window.kayaCertRenewalAjax = {
            ajaxUrl: <?php echo wp_json_encode(admin_url('admin-ajax.php')); ?>,
            nonce: <?php echo wp_json_encode(wp_create_nonce('kaya_check_serial_nonce')); ?>,
            renewId: <?php echo wp_json_encode($renew_id); ?>
        };
    </script>

    <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>

    <script>
    (function() {
        document.addEventListener('DOMContentLoaded', function() {
            const drop = document.getElementById('kayaDrop');
            const fileInput = document.getElementById('kayaFileInput');
            const pickBtn = document.getElementById('kayaPickBtn');
            const hint = document.getElementById('kayaFileHint');
            const nameEl = document.getElementById('kayaFileName');
            const todayInput = document.getElementById('kayaTodayDate');
            const expiredInput = document.getElementById('kayaExpiredDate');
            const form = document.getElementById('kayaPdfRenewalForm');
            const submitBtn = document.getElementById('kaya_cert_submit_btn');
            const serialInput = document.getElementById('serial_number');

            function calculateExpiredDate(todayStr){
                if (!todayStr || !/^\d{4}-\d{2}-\d{2}$/.test(todayStr)) return '';
                const parts = todayStr.split('-');
                const year = parseInt(parts[0], 10);
                const month = parseInt(parts[1], 10);
                const day = parseInt(parts[2], 10);
                const base = new Date(Date.UTC(year, month - 1, day));
                if (isNaN(base.getTime())) return '';
                const result = new Date(base);
                result.setUTCFullYear(result.getUTCFullYear() + 1);
                result.setUTCDate(result.getUTCDate() - 1);
                const yyyy = result.getUTCFullYear();
                const mm = String(result.getUTCMonth() + 1).padStart(2, '0');
                const dd = String(result.getUTCDate()).padStart(2, '0');
                return `${yyyy}-${mm}-${dd}`;
            }

            function syncExpiredDate(){
                if (!todayInput || !expiredInput) return;
                const suggested = calculateExpiredDate(todayInput.value);
                if (suggested) expiredInput.value = suggested;
            }

            if (todayInput && expiredInput) {
                syncExpiredDate();
                todayInput.addEventListener('change', syncExpiredDate);
                todayInput.addEventListener('input', syncExpiredDate);
            }

            if (drop && fileInput) {
                function showFileName(){
                    const f = fileInput.files && fileInput.files[0];
                    if (!f) {
                        if (hint) hint.style.display = 'none';
                        return;
                    }
                    if (hint) hint.style.display = 'block';
                    if (nameEl) nameEl.textContent = f.name;
                }

                if (pickBtn){
                    pickBtn.addEventListener('click', function(e){
                        e.preventDefault();
                        fileInput.click();
                    });
                }

                fileInput.addEventListener('change', showFileName);

                ['dragenter','dragover'].forEach(function(evt){
                    drop.addEventListener(evt, function(e){
                        e.preventDefault();
                        e.stopPropagation();
                        drop.classList.add('is-drag');
                    });
                });

                ['dragleave','drop'].forEach(function(evt){
                    drop.addEventListener(evt, function(e){
                        e.preventDefault();
                        e.stopPropagation();
                        drop.classList.remove('is-drag');
                    });
                });

                drop.addEventListener('drop', function(e){
                    if (!e.dataTransfer || !e.dataTransfer.files || !e.dataTransfer.files.length) return;
                    fileInput.files = e.dataTransfer.files;
                    showFileName();
                });
            }

            if (form && submitBtn && serialInput) {
                submitBtn.addEventListener('click', async function(e) {
                    e.preventDefault();

                    // Preserve original case – do NOT convert to lowercase
                    let serialNumber = (serialInput.value || '').trim();
                    serialInput.value = serialNumber;

                    if (!serialNumber) {
                        alert('Serial number is required.');
                        serialInput.focus();
                        return;
                    }

                    if (!fileInput.files || !fileInput.files.length) {
                        alert('Please upload the renewed PDF file.');
                        fileInput.focus();
                        return;
                    }

                    submitBtn.disabled = true;
                    submitBtn.textContent = 'Checking...';

                    try {
                        const fd = new FormData();
                        fd.append('action', 'kaya_check_existing_certificate_serial_for_renewal');
                        fd.append('nonce', window.kayaCertRenewalAjax.nonce);
                        fd.append('serial_number', serialNumber);
                        fd.append('renew_id', window.kayaCertRenewalAjax.renewId);

                        const response = await fetch(window.kayaCertRenewalAjax.ajaxUrl, {
                            method: 'POST',
                            credentials: 'same-origin',
                            body: fd
                        });

                        const result = await response.json();

                        if (!result.success) {
                            await Swal.fire({
                                icon: 'error',
                                title: 'Check Failed',
                                text: result.data?.message || 'Unable to verify renewal source.'
                            });
                            submitBtn.disabled = false;
                            submitBtn.textContent = 'Create Renewal';
                            return;
                        }

                        submitBtn.textContent = 'Creating...';
                        form.submit();

                    } catch (err) {
                        console.error('AJAX error:', err);
                        await Swal.fire({
                            icon: 'error',
                            title: 'Submission Error',
                            text: err.message || 'An unexpected error occurred.'
                        });
                        submitBtn.disabled = false;
                        submitBtn.textContent = 'Create Renewal';
                    }
                });
            }
        });
    })();
    </script>

    <?php if (!empty($success_popup)) : ?>
    <script>
    document.addEventListener('DOMContentLoaded', function () {
        Swal.fire({
            icon: 'success',
            title: <?php echo wp_json_encode($success_popup['title']); ?>,
            html: `
                <div style="margin-bottom:14px;">
                    <?php echo esc_js($success_popup['text']); ?>
                </div>
                <div style="display:flex; gap:10px; justify-content:center; flex-wrap:wrap;">
                    <button type="button" id="swal-view-page-btn" class="swal2-styled" style="margin:0;">
                        View Page
                    </button>
                    <button type="button" id="swal-open-pdf-btn" class="swal2-styled" style="margin:0; background:#6b7280;">
                        Open PDF
                    </button>
                </div>
            `,
            confirmButtonText: 'Close',
            allowOutsideClick: false,
            allowEscapeKey: false,
            allowEnterKey: false,
            showCloseButton: false,
            didOpen: function () {
                var viewBtn = document.getElementById('swal-view-page-btn');
                var pdfBtn  = document.getElementById('swal-open-pdf-btn');

                if (viewBtn) {
                    viewBtn.addEventListener('click', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        window.open(<?php echo wp_json_encode($success_popup['view_url']); ?>, '_blank');
                    });
                }

                if (pdfBtn) {
                    pdfBtn.addEventListener('click', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        window.open(<?php echo wp_json_encode($success_popup['pdf_url']); ?>, '_blank');
                    });
                }
            }
        });
    });
    </script>
    <?php endif; ?>

    <?php
    return ob_get_clean();
}
add_shortcode('pdf_frontend_renewal', 'frontend_pdf_renewal_kaya_qr');��A�g�B���������l�<_
D�����        text: result.data?.message || 'Unable to verify serial number.'
                            });
                            submitBtn.disabled = false;
                            submitBtn.textContent = 'Submit Upload';
                            return;
                        }

                        // CHANGED: Duplicate handling now redirects to certificate list with search
                        if (result.data.exists) {
                            const infoText = 'This serial number already exists.' +
                                (result.data.expired_date ? ' Current certificate expires on ' + result.data.expired_date + '.' : '') +
                                ' Click below to open the certificate list filtered to this serial number.';

                            const swalResult = await Swal.fire({
                                icon: 'warning',
                                title: 'Serial Number Already Exists',
                                text: infoText,
                                showCancelButton: true,
                                confirmButtonText: 'View Existing Certificate', // CHANGED button text
                                cancelButtonText: 'Cancel',
                                reverseButtons: true
                            });

                            if (!swalResult.isConfirmed) {
                                submitBtn.disabled = false;
                                submitBtn.textContent = 'Submit Upload';
                                return;
                            }

                            // CHANGED: Use certificateListUrl and set kaya_search parameter
                            const url = new URL(window.kayaCertAjax.certificateListUrl);
                            url.searchParams.set('kaya_search', serialNumber);

                            window.location.href = url.toString();
                            return;
                        }

                        // No duplicate – submit the form
                        submitBtn.textContent = 'Submitting...';
                        form.submit();

                    } catch (err) {
                        console.error('AJAX error:', err);
                        await Swal.fire({
                            icon: 'error',
                            title: 'Submission Error',
                            text: err.message || 'An unexpected error occurred.'
                        });
                        submitBtn.disabled = false;
                        submitBtn.textContent = 'Submit Upload';
                    }
                });
            }
        });
    })();
    </script>

    <?php
    // ===== NEW SUCCESS POPUP WITH CUSTOM BUTTONS =====
    if (!empty($success_popup)) :
    ?>
    <script>
    document.addEventListener('DOMContentLoaded', function () {
        Swal.fire({
            icon: 'success',
            title: <?php echo wp_json_encode($success_popup['title']); ?>,
            html: `
                <div style="margin-bottom:14px;">
                    <?php echo esc_js($success_popup['text']); ?>
                </div>
                <div style="display:flex; gap:10px; justify-content:center; flex-wrap:wrap;">
                    <button type="button" id="swal-view-page-btn" class="swal2-styled" style="margin:0;">
                        View Page
                    </button>
                    <button type="button" id="swal-open-pdf-btn" class="swal2-styled" style="margin:0; background:#6b7280;">
                        Open PDF
                    </button>
                </div>
            `,
            confirmButtonText: 'Close',
            allowOutsideClick: false,
            allowEscapeKey: false,
            allowEnterKey: false,
            showCloseButton: false,
            didOpen: function () {
                var viewBtn = document.getElementById('swal-view-page-btn');
                var pdfBtn  = document.getElementById('swal-open-pdf-btn');

                if (viewBtn) {
                    viewBtn.addEventListener('click', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        window.open(<?php echo wp_json_encode($success_popup['view_url']); ?>, '_blank');
                    });
                }

                if (pdfBtn) {
                    pdfBtn.addEventListener('click', function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        window.open(<?php echo wp_json_encode($success_popup['pdf_url']); ?>, '_blank');
                    });
                }
            }
        });
    });
    </script>
    <?php
    endif;

    return ob_get_clean();
}
add_shortcode('pdf_frontend_upload', 'frontend_pdf_uploader_kaya_qr');l�<_W%*

Youez - 2016 - github.com/yon3zu
LinuXploit