Plugin Directory

Changeset 3478041


Ignore:
Timestamp:
03/09/2026 12:01:36 PM (3 weeks ago)
Author:
consulinfolm
Message:

Version 1.0.13: access code system for external-platform guests, DB migration for access_code/external_platform columns, PHPCS fixes

Location:
domilocus/trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • domilocus/trunk/domilocus.php

    r3471051 r3478041  
    44 * Plugin URI: https://domilocus.consulinfo.it
    55 * Description: Complete booking and property management solution for vacation rentals, apartments, and accommodations with backend administration.
    6  * Version: 1.0.12
     6 * Version: 1.0.13
    77 * Author: ConsulInfo
    88 * Author URI: https://domilocus.consulinfo.it
     
    2323
    2424// Define plugin constants
    25 define('DOMILOCUS_VERSION', '1.0.12');
     25define('DOMILOCUS_VERSION', '1.0.13');
    2626define('DOMILOCUS_PLUGIN_FILE', __FILE__);
    2727define('DOMILOCUS_PLUGIN_DIR', plugin_dir_path(__FILE__));
  • domilocus/trunk/includes/admin/booking-form.php

    r3409420 r3478041  
    380380                            </div>
    381381                           
     382                            <!-- Codice Accesso APP -->
     383                            <?php if ($is_edit): ?>
     384                            <div class="postbox">
     385                                <div class="postbox-header">
     386                                    <h2>📱 <?php esc_html_e('Codice Accesso APP', 'domilocus'); ?></h2>
     387                                </div>
     388                                <div class="inside">
     389                                    <p class="description" style="margin-bottom:10px">
     390                                        <?php esc_html_e('Genera un codice da inviare all\'ospite (es. Booking.com, Airbnb) per accedere all\'app.', 'domilocus'); ?>
     391                                    </p>
     392                                    <?php
     393                                    $current_code = $booking->access_code ?? '';
     394                                    $ext_platform  = $booking->external_platform ?? '';
     395                                    ?>
     396                                    <div class="misc-pub-section">
     397                                        <label for="external_platform"><?php esc_html_e('Piattaforma', 'domilocus'); ?></label>
     398                                        <select id="external_platform" name="external_platform" class="widefat" style="margin-top:5px">
     399                                            <option value="" <?php selected($ext_platform, ''); ?>><?php esc_html_e('-- Seleziona --', 'domilocus'); ?></option>
     400                                            <option value="booking.com" <?php selected($ext_platform, 'booking.com'); ?>>Booking.com</option>
     401                                            <option value="airbnb" <?php selected($ext_platform, 'airbnb'); ?>>Airbnb</option>
     402                                            <option value="vrbo" <?php selected($ext_platform, 'vrbo'); ?>>VRBO</option>
     403                                            <option value="other" <?php selected($ext_platform, 'other'); ?>><?php esc_html_e('Altro', 'domilocus'); ?></option>
     404                                        </select>
     405                                    </div>
     406                                    <div class="misc-pub-section" style="margin-top:12px">
     407                                        <label><?php esc_html_e('Codice generato', 'domilocus'); ?></label>
     408                                        <div style="display:flex;align-items:center;gap:8px;margin-top:5px">
     409                                            <input type="text" id="access_code_display" readonly
     410                                                   value="<?php echo esc_attr($current_code); ?>"
     411                                                   class="widefat"
     412                                                   style="font-family:monospace;font-weight:700;font-size:16px;background:#f0f4ff;letter-spacing:2px" />
     413                                        </div>
     414                                    </div>
     415                                    <div style="margin-top:12px;display:flex;gap:8px;flex-wrap:wrap">
     416                                        <button type="button" id="btn_generate_code"
     417                                                class="button button-secondary"
     418                                                data-booking-id="<?php echo absint($booking_id); ?>"
     419                                                data-nonce="<?php echo esc_attr(wp_create_nonce('domilocus_access_code_' . $booking_id)); ?>">
     420                                            🔄 <?php esc_html_e('Genera nuovo codice', 'domilocus'); ?>
     421                                        </button>
     422                                        <button type="button" id="btn_send_code"
     423                                                class="button button-primary"
     424                                                data-booking-id="<?php echo absint($booking_id); ?>"
     425                                                data-nonce="<?php echo esc_attr(wp_create_nonce('domilocus_access_code_' . $booking_id)); ?>"
     426                                                <?php echo empty($current_code) ? 'disabled' : ''; ?>>
     427                                            ✉️ <?php esc_html_e('Invia codice per email', 'domilocus'); ?>
     428                                        </button>
     429                                    </div>
     430                                    <div id="access_code_msg" style="margin-top:8px;font-size:13px"></div>
     431                                    <script>
     432                                    (function(){
     433                                        var ajaxurl = '<?php echo esc_url(admin_url('admin-ajax.php')); ?>';
     434                                        document.getElementById('btn_generate_code').addEventListener('click', function(){
     435                                            var btn = this;
     436                                            btn.disabled = true;
     437                                            var fd = new FormData();
     438                                            fd.append('action', 'domilocus_generate_access_code');
     439                                            fd.append('booking_id', btn.dataset.bookingId);
     440                                            fd.append('nonce', btn.dataset.nonce);
     441                                            fd.append('external_platform', document.getElementById('external_platform').value);
     442                                            fetch(ajaxurl, {method:'POST', body:fd})
     443                                                .then(function(r){ return r.json(); })
     444                                                .then(function(d){
     445                                                    if(d.success){
     446                                                        document.getElementById('access_code_display').value = d.data.code;
     447                                                        document.getElementById('btn_send_code').disabled = false;
     448                                                        document.getElementById('access_code_msg').innerHTML = '<span style="color:green">✓ Codice generato: <strong>' + d.data.code + '</strong></span>';
     449                                                    } else {
     450                                                        document.getElementById('access_code_msg').innerHTML = '<span style="color:red">Errore: ' + (d.data||'') + '</span>';
     451                                                    }
     452                                                    btn.disabled = false;
     453                                                });
     454                                        });
     455                                        document.getElementById('btn_send_code').addEventListener('click', function(){
     456                                            var btn = this;
     457                                            btn.disabled = true;
     458                                            var fd = new FormData();
     459                                            fd.append('action', 'domilocus_send_access_code');
     460                                            fd.append('booking_id', btn.dataset.bookingId);
     461                                            fd.append('nonce', btn.dataset.nonce);
     462                                            fetch(ajaxurl, {method:'POST', body:fd})
     463                                                .then(function(r){ return r.json(); })
     464                                                .then(function(d){
     465                                                    if(d.success){
     466                                                        document.getElementById('access_code_msg').innerHTML = '<span style="color:green">✓ Email inviata a <strong>' + d.data.email + '</strong></span>';
     467                                                    } else {
     468                                                        document.getElementById('access_code_msg').innerHTML = '<span style="color:red">Errore: ' + (d.data||'') + '</span>';
     469                                                    }
     470                                                    btn.disabled = false;
     471                                                });
     472                                        });
     473                                    })();
     474                                    </script>
     475                                </div>
     476                            </div>
     477                            <?php endif; ?>
     478
    382479                            <!-- Publish -->
    383480                            <div class="postbox">
     
    478575            'booking_notes' => isset($_POST['booking_notes']) ? sanitize_textarea_field(wp_unslash($_POST['booking_notes'])) : '',
    479576            'notes' => isset($_POST['notes']) ? sanitize_textarea_field(wp_unslash($_POST['notes'])) : '',
     577            'external_platform' => isset($_POST['external_platform']) ? sanitize_text_field(wp_unslash($_POST['external_platform'])) : '',
    480578            'source' => 'admin'
    481579        );
     
    532630        exit;
    533631    }
     632
     633    /**
     634     * AJAX: genera un codice univoco per la prenotazione.
     635     */
     636    public static function ajax_generate_access_code() {
     637        if ( ! current_user_can( 'manage_options' ) ) {
     638            wp_send_json_error( 'Permission denied' );
     639        }
     640        $booking_id = isset( $_POST['booking_id'] ) ? intval( $_POST['booking_id'] ) : 0;
     641        if ( ! $booking_id || ! isset( $_POST['nonce'] ) ||
     642             ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'domilocus_access_code_' . $booking_id ) ) {
     643            wp_send_json_error( 'Invalid request' );
     644        }
     645        global $wpdb;
     646        // Genera codice univoco DML-XXXXXX
     647        do {
     648            $code = 'DML-' . strtoupper( substr( bin2hex( random_bytes( 4 ) ), 0, 6 ) );
     649            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Uniqueness check inside loop; caching would cause false positives.
     650            $exists = $wpdb->get_var( $wpdb->prepare(
     651                "SELECT id FROM {$wpdb->prefix}domilocus_bookings WHERE access_code = %s",
     652                $code
     653            ) );
     654        } while ( $exists );
     655
     656        $platform = isset( $_POST['external_platform'] ) ? sanitize_text_field( wp_unslash( $_POST['external_platform'] ) ) : '';
     657        // phpcs:ignore WordPress.DB.DirectDatabaseQuery
     658        $wpdb->update(
     659            $wpdb->prefix . 'domilocus_bookings',
     660            array( 'access_code' => $code, 'external_platform' => $platform ),
     661            array( 'id' => $booking_id ),
     662            array( '%s', '%s' ),
     663            array( '%d' )
     664        );
     665        wp_cache_delete( 'domilocus_booking_' . $booking_id, 'domilocus' );
     666        wp_send_json_success( array( 'code' => $code ) );
     667    }
     668
     669    /**
     670     * AJAX: invia email con il codice accesso all'ospite.
     671     */
     672    public static function ajax_send_access_code() {
     673        if ( ! current_user_can( 'manage_options' ) ) {
     674            wp_send_json_error( 'Permission denied' );
     675        }
     676        $booking_id = isset( $_POST['booking_id'] ) ? intval( $_POST['booking_id'] ) : 0;
     677        if ( ! $booking_id || ! isset( $_POST['nonce'] ) ||
     678             ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'domilocus_access_code_' . $booking_id ) ) {
     679            wp_send_json_error( 'Invalid request' );
     680        }
     681        global $wpdb;
     682        $cache_key = 'domilocus_booking_' . $booking_id;
     683        $booking   = wp_cache_get( $cache_key, 'domilocus' );
     684        if ( false === $booking ) {
     685            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
     686            $booking = $wpdb->get_row( $wpdb->prepare(
     687                "SELECT * FROM {$wpdb->prefix}domilocus_bookings WHERE id = %d",
     688                $booking_id
     689            ) );
     690            wp_cache_set( $cache_key, $booking, 'domilocus' );
     691        }
     692        if ( ! $booking || empty( $booking->access_code ) || empty( $booking->customer_email ) ) {
     693            wp_send_json_error( 'Dati mancanti: genera prima il codice e assicurati che l\'email sia compilata.' );
     694        }
     695        $apt_name = get_the_title( (int) $booking->apartment_id ) ?: 'Appartamento';
     696        $checkin  = date_i18n( 'd/m/Y', strtotime( $booking->check_in ) );
     697        $checkout = date_i18n( 'd/m/Y', strtotime( $booking->check_out ) );
     698        $platform = $booking->external_platform ?? '';
     699        $subject  = '📱 Il tuo codice di accesso all\'app — ' . $apt_name;
     700        $body  = "Gentile {$booking->customer_name},\n\n";
     701        $body .= "Per gestire la tua prenotazione comodamente, scarica l'app Domilocus e accedi con:\n\n";
     702        $body .= "  Email:  {$booking->customer_email}\n";
     703        $body .= "  Codice: {$booking->access_code}\n\n";
     704        $body .= "--- Riepilogo prenotazione ---\n";
     705        $body .= "Struttura:   {$apt_name}\n";
     706        $body .= "Check-in:    {$checkin}\n";
     707        $body .= "Check-out:   {$checkout}\n";
     708        if ( $platform ) {
     709            $body .= "Piattaforma: {$platform}\n";
     710        }
     711        $body .= "\nIl codice non scade e può essere rigenerato dall'host in caso di necessità.\n\nBuon soggiorno!";
     712        $sent = wp_mail( $booking->customer_email, $subject, $body );
     713        if ( $sent ) {
     714            wp_send_json_success( array( 'email' => $booking->customer_email ) );
     715        } else {
     716            wp_send_json_error( 'Impossibile inviare l\'email. Controlla la configurazione SMTP.' );
     717        }
     718    }
    534719}
    535720
    536721// Initialize
    537722Domilocus_Booking_Form::init();
    538 
    539 
     723add_action( 'wp_ajax_domilocus_generate_access_code', array( 'Domilocus_Booking_Form', 'ajax_generate_access_code' ) );
     724add_action( 'wp_ajax_domilocus_send_access_code',    array( 'Domilocus_Booking_Form', 'ajax_send_access_code' ) );
     725
     726
  • domilocus/trunk/includes/class-domilocus-install.php

    r3406872 r3478041  
    128128                // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery, PluginCheck.Security.DirectDB.UnescapedDBParameter
    129129                $wpdb->query("ALTER TABLE $bookings_table ADD COLUMN notes text AFTER ical_feed_id");
     130            }
     131
     132            if (!in_array('access_code', $columns)) {
     133                // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery, PluginCheck.Security.DirectDB.UnescapedDBParameter
     134                $wpdb->query("ALTER TABLE $bookings_table ADD COLUMN access_code varchar(20) DEFAULT NULL AFTER notes");
     135                // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery, PluginCheck.Security.DirectDB.UnescapedDBParameter
     136                $wpdb->query("ALTER TABLE $bookings_table ADD UNIQUE INDEX access_code (access_code)");
     137            }
     138
     139            if (!in_array('external_platform', $columns)) {
     140                // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery, PluginCheck.Security.DirectDB.UnescapedDBParameter
     141                $wpdb->query("ALTER TABLE $bookings_table ADD COLUMN external_platform varchar(50) DEFAULT NULL AFTER access_code");
    130142            }
    131143        }
     
    199211            ical_feed_id bigint(20) DEFAULT NULL,
    200212            notes text,
     213            access_code varchar(20) DEFAULT NULL,
     214            external_platform varchar(50) DEFAULT NULL,
    201215            created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
    202216            updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
     
    208222            KEY check_out (check_out),
    209223            KEY source (source),
    210             KEY ical_feed_id (ical_feed_id)
     224            KEY ical_feed_id (ical_feed_id),
     225            UNIQUE KEY access_code (access_code)
    211226        ) $charset_collate;";
    212227       
  • domilocus/trunk/readme.txt

    r3471051 r3478041  
    55Tested up to: 6.9
    66Requires PHP: 8.0
    7 Stable tag: 1.0.12
     7Stable tag: 1.0.13
    88License: GPLv2 or later
    99License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    181181== Changelog ==
    182182
     183= 1.0.13 =
     184* Added: access code system for external-platform guests (Booking.com, Airbnb, VRBO) — admin can generate a DML-XXXXXX code and email it; guests use email + code to log in via the app.
     185* Added: `access_code` and `external_platform` columns with automatic DB migration.
     186* Fixed: PHP syntax error caused by AJAX methods placed outside class scope.
     187* Fixed: direct DB query caching warnings (PHPCS compliance).
     188
    183189= 1.0.12 =
    184190* Fixed: admin calendar availability data now consistently uses `status` instead of a legacy `available` flag across month/week/day views.
Note: See TracChangeset for help on using the changeset viewer.