PK œqhYîļJ‚ßFßF)nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/ $#$#$#

Dir : /home2/medicu/.trash/Incomplete Order/
Server: Linux tista.bd.svlogins.com 5.14.0-611.49.1.el9_7.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Apr 21 16:39:08 EDT 2026 x86_64
IP: 103.159.37.114
Choose File :

Url:
Dir : /home2/medicu/.trash/Incomplete Order/sohag-online-solution.php

<?php
/**
 * Plugin Name: Incomplete Order
 * Version: 3.2
 * Author: Sohag Islam
 */

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

/* ----------------------------
 * Helpers
 * ---------------------------- */
function sos_tbl() { global $wpdb; return $wpdb->prefix . 'sos_incomplete_orders'; }

function sos_get_ip() {
    // proxy/CDN support
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $parts = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        return trim(end($parts));
    }
    return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
}

function sos_valid_bd_phone($p) {
    // 11 digits, starts with 01 and 2nd digit 3-9
    return (bool) preg_match('/^(01[3-9][0-9]{8})$/', $p);
}

/* ----------------------------
 * Activation: DB + CRON
 * ---------------------------- */
register_activation_hook(__FILE__, function(){
    global $wpdb;
    $table = sos_tbl();
    $charset = $wpdb->get_charset_collate();
    $sql = "CREATE TABLE IF NOT EXISTS {$table} (
        id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
        name VARCHAR(200) NOT NULL,
        phone VARCHAR(30) NOT NULL,
        address TEXT NOT NULL,
        ip_address VARCHAR(64) DEFAULT NULL,
        created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
        PRIMARY KEY (id),
        KEY phone (phone),
        KEY created_at (created_at)
    ) {$charset};";
    require_once ABSPATH . 'wp-admin/includes/upgrade.php';
    dbDelta($sql);

    if (!wp_next_scheduled('sos_cleanup_incomplete_hourly')) {
        wp_schedule_event(time(), 'hourly', 'sos_cleanup_incomplete_hourly');
    }
});

register_deactivation_hook(__FILE__, function(){
    wp_clear_scheduled_hook('sos_cleanup_incomplete_hourly');
});

/* ----------------------------
 * Checkout fields: Email optional; Name/Phone/Address required
 * ---------------------------- */
add_filter('woocommerce_checkout_fields', function($fields){
    if (isset($fields['billing']['billing_email'])) {
        $fields['billing']['billing_email']['required'] = false;
        unset($fields['billing']['billing_email']['validate']); // remove strict email validate
        $fields['billing']['billing_email']['label'] = __('(Optional) Email');
    }
    if (isset($fields['billing']['billing_first_name'])) {
        $fields['billing']['billing_first_name']['required'] = true;
        $fields['billing']['billing_first_name']['label'] = 'āφāĻĒāύāĻžāϰ āύāĻžāĻŽ';
    }
    if (isset($fields['billing']['billing_address_1'])) {
        $fields['billing']['billing_address_1']['required'] = true;
        $fields['billing']['billing_address_1']['label'] = 'āφāĻĒāύāĻžāϰ āϏāĻŽā§āĻĒā§‚āĻ°ā§āĻŖ āĻ āĻŋāĻ•āĻžāύāĻž';
    }
    if (isset($fields['billing']['billing_phone'])) {
        $fields['billing']['billing_phone']['required'] = true;
        $fields['billing']['billing_phone']['label'] = 'āφāĻĒāύāĻžāϰ āĻĢā§‹āύ āύāĻžāĻŽā§āĻŦāĻžāϰ';
    }
    return $fields;
}, 20);

/* ----------------------------
 * Server-side phone validation
 * ---------------------------- */
add_action('woocommerce_checkout_process', function(){
    $phone = isset($_POST['billing_phone']) ? sanitize_text_field($_POST['billing_phone']) : '';
    if (!sos_valid_bd_phone($phone)) {
        wc_add_notice('👉 āφāĻĒāύāĻžāϰ ā§§ā§§ āϏāĻ‚āĻ–ā§āϝāĻžāϰ āĻŽā§‹āĻŦāĻžāχāϞ āύāĻžāĻŽā§āĻŦāĻžāϰ āϞāĻŋāϖ⧁āύ (01 āĻĻāĻŋā§Ÿā§‡ āĻļ⧁āϰ⧁, 2nd digit 3-9)āĨ¤', 'error');
    }
});

/* ----------------------------
 * IP block ONLY AFTER successful order (10 minutes)
 * - Check during checkout to block if still active
 * - Set on thankyou if order not failed/cancelled/refunded
 * ---------------------------- */
function sos_ip_blocked_msg_minutes_left($ip) {
    $until = get_transient('sos_block_until_' . md5($ip));
    if (!$until) return 0;
    $sec = max(0, $until - time());
    return (int) ceil($sec / 60);
}

add_action('woocommerce_checkout_process', function(){
    $ip = sos_get_ip();
    $block = get_transient('sos_block_flag_' . md5($ip));
    if ($block) {
        $left = sos_ip_blocked_msg_minutes_left($ip);
        $left = ($left > 0) ? $left : 10;
        wc_add_notice("đŸšĢ āĻĒāϰāĻŦāĻ°ā§āϤ⧀ āĻ…āĻ°ā§āĻĄāĻžāϰ⧇āϰ āϜāĻ¨ā§āϝ {$left} āĻŽāĻŋāύāĻŋāϟ āĻ…āĻĒ⧇āĻ•ā§āώāĻž āĻ•āϰ⧁āύāĨ¤", 'error');
    }
});

add_action('woocommerce_thankyou', function($order_id){
    if (!$order_id) return;
    $order = wc_get_order($order_id);
    if (!$order) return;

    // Only block if actually a successful order (not failed/cancelled/refunded)
    if ($order->has_status(array('failed','cancelled','refunded'))) return;

    $ip = sos_get_ip();
    set_transient('sos_block_flag_' . md5($ip), 1, 10 * MINUTE_IN_SECONDS);
    set_transient('sos_block_until_' . md5($ip), time() + 10 * MINUTE_IN_SECONDS, 10 * MINUTE_IN_SECONDS);
});

/* ----------------------------
 * Enqueue front-end JS (real-time phone check + robust AJAX save)
 * ---------------------------- */
add_action('wp_enqueue_scripts', function(){
    if (function_exists('is_checkout') && is_checkout()) {
        wp_enqueue_script('sos-checkout', plugin_dir_url(__FILE__) . 'assets/sos-checkout.js', array('jquery'), '3.2', true);
        wp_localize_script('sos-checkout', 'sosAjax', array(
            'url'   => admin_url('admin-ajax.php'),
            'nonce' => wp_create_nonce('sos_nonce')
        ));
    }
});

/* ----------------------------
 * AJAX: Save Incomplete Order (NEVER MISS)
 * - Validates required fields & phone
 * - Deduplicates rapid repeats (30s)
 * ---------------------------- */
add_action('wp_ajax_sos_save_incomplete', 'sos_save_incomplete');
add_action('wp_ajax_nopriv_sos_save_incomplete', 'sos_save_incomplete');
function sos_save_incomplete() {
    check_ajax_referer('sos_nonce', 'nonce');

    $name    = isset($_POST['name'])    ? sanitize_text_field($_POST['name'])    : '';
    $phone   = isset($_POST['phone'])   ? sanitize_text_field($_POST['phone'])   : '';
    $address = isset($_POST['address']) ? sanitize_textarea_field($_POST['address']) : '';
    $ip      = sos_get_ip();

    if ($name === '' || $address === '' || $phone === '') {
        wp_send_json_error(array('msg' => 'āϏāĻŦ āϘāϰ āĻĒā§‚āϰāĻŖ āĻ•āϰ⧁āύ'));
    }
    if (!sos_valid_bd_phone($phone)) {
        wp_send_json_error(array('msg' => 'ā§§ā§§ āϏāĻ‚āĻ–ā§āϝāĻžāϰ āϏāĻ āĻŋāĻ• āĻŽā§‹āĻŦāĻžāχāϞ āύāĻžāĻŽā§āĻŦāĻžāϰ āĻĻāĻŋāύ (01[3-9]...)'));
    }

    global $wpdb;
    $table = sos_tbl();

    // Prevent spammy rapid duplicates from same IP within 30s
    $last = $wpdb->get_var($wpdb->prepare("SELECT created_at FROM {$table} WHERE ip_address=%s ORDER BY created_at DESC LIMIT 1", $ip));
    if ($last && strtotime($last) > (time() - 30)) {
        wp_send_json_success(array('msg' => 'Already saved recently')); // not an error, just skip duplicate
    }

    $ok = $wpdb->insert($table, array(
        'name'       => $name,
        'phone'      => $phone,
        'address'    => $address,
        'ip_address' => $ip,
        'created_at' => current_time('mysql')
    ), array('%s','%s','%s','%s','%s'));

    if ($ok) {
        wp_send_json_success(array('msg' => 'Saved'));
    } else {
        wp_send_json_error(array('msg' => 'Server error, try again'));
    }
}

/* ----------------------------
 * Admin: Incomplete Orders (List + Create Order + Delete)
 * ---------------------------- */
add_action('admin_menu', function(){
    add_menu_page(
        'Incomplete Orders',
        'Incomplete Orders',
        'manage_woocommerce',
        'sos-incomplete-orders',
        'sos_admin_page',
        'dashicons-list-view',
        56
    );
});

function sos_admin_page(){
    if (!current_user_can('manage_woocommerce')) wp_die('Permission denied');
    global $wpdb;
    $table = sos_tbl();

    // CREATE ORDER
    if (isset($_GET['create']) && isset($_GET['_wpnonce']) && wp_verify_nonce($_GET['_wpnonce'], 'sos_create_'.intval($_GET['create']))) {
        $id = intval($_GET['create']);
        $row = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$table} WHERE id=%d", $id));
        if ($row && function_exists('wc_create_order')) {
            $order = wc_create_order();
            // Set billing info
            $order->set_billing_first_name($row->name);
            $order->set_billing_phone($row->phone);
            $order->set_billing_address_1($row->address);

            // Optional: add a zero-fee line for visibility
            $fee = new WC_Order_Item_Fee();
            $fee->set_name('Created from Incomplete Order #'.$row->id);
            $fee->set_amount(0);
            $fee->set_total(0);
            $order->add_item($fee);

            $order->calculate_totals();
            $order->save();

            echo '<div class="notice notice-success is-dismissible"><p>Order created. ID: '.esc_html($order->get_id()).'</p></div>';
        } else {
            echo '<div class="notice notice-error is-dismissible"><p>Failed to create order.</p></div>';
        }
    }

    // DELETE
    if (isset($_GET['delete']) && isset($_GET['_wpnonce']) && wp_verify_nonce($_GET['_wpnonce'], 'sos_delete_'.intval($_GET['delete']))) {
        $wpdb->delete($table, array('id'=>intval($_GET['delete'])), array('%d'));
        echo '<div class="notice notice-success is-dismissible"><p>Deleted.</p></div>';
    }

    // LIST
    $rows = $wpdb->get_results("SELECT * FROM {$table} ORDER BY created_at DESC");

    echo '<div class="wrap"><h1>Incomplete Orders</h1>';
    echo '<table class="widefat striped"><thead><tr>
        <th>ID</th><th>Name</th><th>Phone</th><th>Address</th><th>IP</th><th>Created</th><th>Actions</th>
    </tr></thead><tbody>';

    if ($rows) {
        foreach ($rows as $r) {
            $create_url = wp_nonce_url(admin_url('admin.php?page=sos-incomplete-orders&create='.$r->id), 'sos_create_'.$r->id);
            $delete_url = wp_nonce_url(admin_url('admin.php?page=sos-incomplete-orders&delete='.$r->id), 'sos_delete_'.$r->id);
            echo '<tr>
                <td>'.(int)$r->id.'</td>
                <td>'.esc_html($r->name).'</td>
                <td>'.esc_html($r->phone).'</td>
                <td>'.esc_html($r->address).'</td>
                <td>'.esc_html($r->ip_address).'</td>
                <td>'.esc_html($r->created_at).'</td>
                <td>
                    <a class="button" href="'.esc_url($create_url).'">Create Order</a>
                    <a class="button" style="background:#d63638;color:#fff" href="'.esc_url($delete_url).'">Delete</a>
                </td>
            </tr>';
        }
    } else {
        echo '<tr><td colspan="7">No incomplete orders found.</td></tr>';
    }
    echo '</tbody></table></div>';
}

/* ----------------------------
 * Cleanup old incomplete (24h)
 * ---------------------------- */
add_action('sos_cleanup_incomplete_hourly', function(){
    global $wpdb;
    $table = sos_tbl();
    $cut = gmdate('Y-m-d H:i:s', time() - 24*HOUR_IN_SECONDS);
    $wpdb->query($wpdb->prepare("DELETE FROM {$table} WHERE created_at < %s", $cut));
});