Plugin Directory

Changeset 3434060


Ignore:
Timestamp:
01/07/2026 05:41:49 AM (6 weeks ago)
Author:
awcode
Message:

captcha

Location:
dive-admin/trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • dive-admin/trunk/admin/class-dive-admin-admin.php

    r3239009 r3434060  
    124124
    125125        update_option( 'diveadmin_sync_woo',  sanitize_text_field(wp_unslash( isset($_POST['diveadmin_sync_woo']) ? 1 : 0 )) );
     126       
     127        if(isset($_POST['diveadmin_turnstile_site_key'])){
     128            update_option( 'diveadmin_turnstile_site_key',  sanitize_text_field(wp_unslash($_POST['diveadmin_turnstile_site_key'])) );
     129        }
     130        if(isset($_POST['diveadmin_turnstile_secret_key'])){
     131            update_option( 'diveadmin_turnstile_secret_key',  sanitize_text_field(wp_unslash($_POST['diveadmin_turnstile_secret_key'])) );
     132        }
    126133
    127134        wp_safe_redirect(esc_url(get_admin_url(null, 'admin.php?page=diveadmin_settings')));
  • dive-admin/trunk/admin/css/dive-admin-admin.css

    r3239009 r3434060  
    11.grid {
    2   display: grid;
    3   column-gap: 50px;
    4   grid-auto-flow: column;
    5   column-count: 3;
    6   margin-top: 1em;
     2    display: grid;
     3    grid-template-columns: repeat(auto-fit, minmax(450px, 1fr));
     4    gap: 20px;
     5    grid-auto-flow: row;
     6    margin-top: 1em;
    77}
    88
    9 .box{
    10     border: 1px solid #ccc;
    11     border-radius: 7px;
     9.box {
     10    border: 1px solid #ccc;
     11    border-radius: 7px;
    1212
    13     background: #fff;
    14 }
    15 .box-header{
    16     background: #dcdcde;
    17     padding: 1em;
    18     font-weight: bold;
     13    background: #fff;
    1914}
    2015
    21 .box-body{
    22     padding: 1em;
     16.box-header {
     17    background: #dcdcde;
     18    padding: 1em;
     19    font-weight: bold;
    2320}
     21
     22.box-body {
     23    padding: 1em;
     24}
     25
    2426.alert {
    2527    position: relative;
     
    2931    border-radius: .25rem;
    3032}
     33
    3134.alert-success {
    3235    color: #155724;
     
    3437    border-color: #c3e6cb;
    3538}
     39
    3640.alert-warning {
    3741    color: #856404;
  • dive-admin/trunk/admin/partials/dive-admin-admin-display.php

    r3411697 r3434060  
    100100    </div>
    101101
     102    <div class="box">
     103        <div class="box-header">
     104            Spam Protection (Cloudflare Turnstile)
     105        </div>
     106        <div class="box-body">
     107            <label for="diveadmin_turnstile_site_key">Site Key</label><br>
     108            <input type="text" name="diveadmin_turnstile_site_key" value="<?php echo esc_attr(get_option('diveadmin_turnstile_site_key')); ?>" style="width:100%"><br><br>
     109           
     110            <label for="diveadmin_turnstile_secret_key">Secret Key</label><br>
     111            <input type="text" name="diveadmin_turnstile_secret_key" value="<?php echo esc_attr(get_option('diveadmin_turnstile_secret_key')); ?>" style="width:100%">
     112        </div>
     113    </div>
     114
    102115</div>
    103116<br>
  • dive-admin/trunk/dive-admin.php

    r3411697 r3434060  
    66 * Plugin URI:        https://diveadmin.com/resources/wordpress
    77 * Description:       DiveAdmin.com is a software solution for diveschools. This plugin connects your website with your account.
    8  * Version:           1.0.7
     8 * Version:           1.0.8
    99 * Author:            Dive Admin
    1010 * Author URI:        https://diveadmin.com
  • dive-admin/trunk/public/class-dive-admin-public.php

    r3411697 r3434060  
    137137        wp_verify_nonce('diveadmin_leadform');
    138138
    139         //TODO Validate
    140         //TODO Captcha and Honeypot
    141 
    142139        $data = json_decode(file_get_contents('php://input'), true);
     140
     141        // Validation
     142        $message = isset($data['message']) ? sanitize_text_field(wp_unslash($data['message'])) : '';
     143        if ( empty($message) ) {
     144            wp_die('{"message":"Message is required"}', 400);
     145        }
     146
     147        $first_name = isset($data['first_name']) ? sanitize_text_field(wp_unslash($data['first_name'])) : '';
     148        $surname = isset($data['surname']) ? sanitize_text_field(wp_unslash($data['surname'])) : '';
     149
     150        if ( empty($first_name) || trim($first_name) === '?' ) {
     151            wp_die('{"message":"Valid First Name is required"}', 400);
     152        }
     153        if ( empty($surname) || trim($surname) === '?' ) {
     154            wp_die('{"message":"Valid Surname is required"}', 400);
     155        }
     156
     157        // Turnstile Verification
     158        if ( get_option('diveadmin_turnstile_secret_key') ) {
     159            $turnstile_response = isset($data['cf-turnstile-response']) ? $data['cf-turnstile-response'] : '';
     160            if ( empty($turnstile_response) ) {
     161                wp_die('{"message":"Security verification failed (Turnstile)"}', 400);
     162            }
     163
     164            $verify = wp_remote_post('https://challenges.cloudflare.com/turnstile/v0/siteverify', [
     165                'body' => [
     166                    'secret' => get_option('diveadmin_turnstile_secret_key'),
     167                    'response' => $turnstile_response,
     168                    'remoteip' => $_SERVER['REMOTE_ADDR']
     169                ]
     170            ]);
     171
     172            $verify_body = json_decode(wp_remote_retrieve_body($verify));
     173            if ( ! $verify_body->success ) {
     174                wp_die('{"message":"Security verification failed (Turnstile)"}', 400);
     175            }
     176        }
     177
     178
    143179        $post = [
    144180            'api_key' => get_option('diveadmin_api_key'),
    145181            'status' => 'enquiry',
    146             'first_name' => isset($data['first_name']) ? sanitize_text_field(wp_unslash($data['first_name'])): '',
    147             'surname' => isset($data['surname']) ? sanitize_text_field(wp_unslash($data['surname'])): '',
     182            'first_name' => $first_name,
     183            'surname' => $surname,
    148184            'email' => isset($data['email']) ? sanitize_text_field(wp_unslash($data['email'])): '',
    149185            'mobile' => isset($data['mobile']) ? sanitize_text_field(wp_unslash($data['mobile'])): '',
    150186            'arrival_date' => isset($data['arrival_date']) ? sanitize_text_field(wp_unslash($data['arrival_date'])): '',
    151             'message' => isset($data['message']) ? sanitize_text_field(wp_unslash($data['message'])): '',
     187            'message' => $message,
    152188        ];
    153189
  • dive-admin/trunk/public/css/dive-admin-public.css

    r3239009 r3434060  
    66    border-radius: .25rem;
    77}
     8
    89.alert-success {
    910    color: #155724;
     
    1112    border-color: #c3e6cb;
    1213}
     14
    1315.alert-warning {
    1416    color: #856404;
     
    2325}
    2426
    25 .diveadmin_leadform{
     27.diveadmin_leadform {}
    2628
     29.diveadmin_leadform input[type=text],
     30.diveadmin_leadform input[type=tel],
     31.diveadmin_leadform input[type=email],
     32.diveadmin_leadform input[type=date],
     33.diveadmin_leadform textarea {
     34    display: block;
     35    width: 100%;
     36    height: calc(2.25rem + 2px);
     37    padding: 0rem .75rem;
     38    font-size: 1rem;
     39    line-height: 1.2;
     40    color: #495057;
     41    background-color: #fff;
     42    background-clip: padding-box;
     43    border: 1px solid #ced4da;
     44    border-radius: .25rem;
     45    transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
    2746}
    2847
    29 .diveadmin_leadform input[type=text], .diveadmin_leadform input[type=tel], .diveadmin_leadform input[type=email], .diveadmin_leadform textarea{
    30     display: block;
    31     width: 100%;
    32     height: calc(2.25rem + 2px);
    33     padding: 0rem .75rem;
    34     font-size: 1rem;
    35     line-height: 1.2;
    36     color: #495057;
    37     background-color: #fff;
    38     background-clip: padding-box;
    39     border: 1px solid #ced4da;
    40     border-radius: .25rem;
    41     transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out;
     48.diveadmin_leadform textarea {
     49    min-height: 4em;
    4250}
    4351
    44 .diveadmin_leadform textarea{
    45     min-height: 4em;
    46 }
    47 
    48 .diveadmin_leadform input[type=submit]{
    49     display: inline-block;
     52.diveadmin_leadform input[type=submit] {
     53    display: inline-block;
    5054    font-weight: 400;
    5155    text-align: center;
     
    6266    border-radius: .25rem;
    6367    transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;
    64     color: #fff;
     68    color: #fff;
    6569    background-color: #007bff;
    6670    border-color: #007bff;
  • dive-admin/trunk/public/js/dive-admin-public.js

    r3239009 r3434060  
    11document.addEventListener("DOMContentLoaded", () => {
    22    if (document.querySelector(".diveadmin-ajax-form")) {
    3         document.querySelector('.diveadmin-ajax-form').addEventListener('submit', function(e) {
    4             e.preventDefault();
    5             let formData = new FormData(this);
    6             let parsedData = {};
    7             for(let name of formData) {
    8               if (typeof(parsedData[name[0]]) == "undefined") {
    9                 let tempdata = formData.getAll(name[0]);
    10                 if (tempdata.length > 1) {
    11                   parsedData[name[0]] = tempdata;
    12                 } else {
    13                   parsedData[name[0]] = tempdata[0];
    14                 }
    15               }
    16             }
     3        document.querySelector('.diveadmin-ajax-form').addEventListener('submit', function (e) {
     4            e.preventDefault();
    175
    18             let options = {};
    19             switch (this.method.toLowerCase()) {
    20               case 'post':
    21                 options.body = JSON.stringify(parsedData);
    22               case 'get':
    23                 options.method = this.method;
    24                 options.headers = {'Content-Type': 'application/json'};
    25               break;
    26             }
     6            // Remove existing alerts
     7            const existingAlert = this.querySelector('.diveadmin-alert');
     8            if (existingAlert) existingAlert.remove();
    279
    28             fetch(this.action, options).then(r => r.json()).then(data => {
     10            let formData = new FormData(this);
     11
     12            // Client-side Turnstile Check
     13            if (document.querySelector('.cf-turnstile')) {
     14                if (!formData.get('cf-turnstile-response')) {
     15                    let messageObj = document.createElement("div");
     16                    messageObj.innerHTML = "Please verify you are human (Turnstile)";
     17                    messageObj.classList.add('diveadmin-alert');
     18                    messageObj.classList.add('alert-warning');
     19                    this.prepend(messageObj);
     20                    return;
     21                }
     22            }
     23
     24            let parsedData = {};
     25            for (let name of formData) {
     26                if (typeof (parsedData[name[0]]) == "undefined") {
     27                    let tempdata = formData.getAll(name[0]);
     28                    if (tempdata.length > 1) {
     29                        parsedData[name[0]] = tempdata;
     30                    } else {
     31                        parsedData[name[0]] = tempdata[0];
     32                    }
     33                }
     34            }
     35
     36            let options = {};
     37            switch (this.method.toLowerCase()) {
     38                case 'post':
     39                    options.body = JSON.stringify(parsedData);
     40                case 'get':
     41                    options.method = this.method;
     42                    options.headers = { 'Content-Type': 'application/json' };
     43                    break;
     44            }
     45
     46            fetch(this.action, options).then(r => {
     47                const isSuccess = r.ok;
     48                return r.json().then(data => ({ isSuccess, data }));
     49            }).then(({ isSuccess, data }) => {
    2950                console.log(data);
    30                 if(data == 0){
    31                     window.alert('Message not sent, unknown error')
    32                 }else{
    33                     messageObj = document.createElement("p");
     51                if (!isSuccess || data == 0) {
     52                    let message = data && data.message ? data.message : 'Unknown error occurred';
     53                    if (data == 0) message = 'Message not sent, unknown error';
     54
     55                    let messageObj = document.createElement("div");
     56                    messageObj.innerHTML = message;
     57                    messageObj.classList.add('diveadmin-alert');
     58                    messageObj.classList.add('alert-warning');
     59                    this.prepend(messageObj);
     60                } else {
     61                    let messageObj = document.createElement("div");
    3462                    messageObj.innerHTML = data.message;
    3563                    messageObj.classList.add('diveadmin-alert');
     
    3765                    this.replaceWith(messageObj);
    3866                }
    39             });
     67            }).catch(err => {
     68                console.error(err);
     69                let messageObj = document.createElement("div");
     70                messageObj.innerHTML = "An error occurred. Please try again.";
     71                messageObj.classList.add('diveadmin-alert');
     72                messageObj.classList.add('alert-warning');
     73                this.prepend(messageObj);
     74            });
    4075        });
    4176    }
  • dive-admin/trunk/public/partials/lead_form.php

    r3411697 r3434060  
    3030    <label for="message">Message</label><br>
    3131    <textarea id="message" name="message" required></textarea><br>
    32     <?php /* TODO Captcha support and Honeypot */ ?>
     32   
     33    <?php if(get_option('diveadmin_turnstile_site_key')):
     34        $site_key = get_option('diveadmin_turnstile_site_key');
     35    ?>
     36        <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
     37        <div class="cf-turnstile" data-sitekey="<?php echo esc_attr($site_key); ?>"></div>
     38        <br>
     39    <?php endif; ?>
    3340    <input type="submit" value="Send Enquiry">
    3441</form>
  • dive-admin/trunk/readme.txt

    r3411697 r3434060  
    44Requires at least: 6.0
    55Tested up to: 6.9
    6 Stable tag: 1.0.7
     6Stable tag: 1.0.8
    77License: GPLv2
    88
     
    4040== Upgrade Notice ==
    4141
    42 = 1.0.7 =
    43 Added dive trip schedule shortcodes for calendar and list views with filtering options.
    44 
    45 
    46 
     42    = 1.0.8 =
     43    Added Turnstile support for lead form.
    4744
    4845== Changelog ==
     46
     47= 1.0.8 =
     48* Added Turnstile support for lead form.
    4949
    5050= 1.0.7 =
Note: See TracChangeset for help on using the changeset viewer.