Changeset 3478041
- Timestamp:
- 03/09/2026 12:01:36 PM (3 weeks ago)
- Location:
- domilocus/trunk
- Files:
-
- 4 edited
-
domilocus.php (modified) (2 diffs)
-
includes/admin/booking-form.php (modified) (3 diffs)
-
includes/class-domilocus-install.php (modified) (3 diffs)
-
readme.txt (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
domilocus/trunk/domilocus.php
r3471051 r3478041 4 4 * Plugin URI: https://domilocus.consulinfo.it 5 5 * Description: Complete booking and property management solution for vacation rentals, apartments, and accommodations with backend administration. 6 * Version: 1.0.1 26 * Version: 1.0.13 7 7 * Author: ConsulInfo 8 8 * Author URI: https://domilocus.consulinfo.it … … 23 23 24 24 // Define plugin constants 25 define('DOMILOCUS_VERSION', '1.0.1 2');25 define('DOMILOCUS_VERSION', '1.0.13'); 26 26 define('DOMILOCUS_PLUGIN_FILE', __FILE__); 27 27 define('DOMILOCUS_PLUGIN_DIR', plugin_dir_path(__FILE__)); -
domilocus/trunk/includes/admin/booking-form.php
r3409420 r3478041 380 380 </div> 381 381 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 382 479 <!-- Publish --> 383 480 <div class="postbox"> … … 478 575 'booking_notes' => isset($_POST['booking_notes']) ? sanitize_textarea_field(wp_unslash($_POST['booking_notes'])) : '', 479 576 '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'])) : '', 480 578 'source' => 'admin' 481 579 ); … … 532 630 exit; 533 631 } 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 } 534 719 } 535 720 536 721 // Initialize 537 722 Domilocus_Booking_Form::init(); 538 539 723 add_action( 'wp_ajax_domilocus_generate_access_code', array( 'Domilocus_Booking_Form', 'ajax_generate_access_code' ) ); 724 add_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 128 128 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery, PluginCheck.Security.DirectDB.UnescapedDBParameter 129 129 $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"); 130 142 } 131 143 } … … 199 211 ical_feed_id bigint(20) DEFAULT NULL, 200 212 notes text, 213 access_code varchar(20) DEFAULT NULL, 214 external_platform varchar(50) DEFAULT NULL, 201 215 created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, 202 216 updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, … … 208 222 KEY check_out (check_out), 209 223 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) 211 226 ) $charset_collate;"; 212 227 -
domilocus/trunk/readme.txt
r3471051 r3478041 5 5 Tested up to: 6.9 6 6 Requires PHP: 8.0 7 Stable tag: 1.0.1 27 Stable tag: 1.0.13 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 181 181 == Changelog == 182 182 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 183 189 = 1.0.12 = 184 190 * 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.