Changeset 3454590
- Timestamp:
- 02/05/2026 11:59:11 AM (7 weeks ago)
- Location:
- creavi-booking-service
- Files:
-
- 56 added
- 6 edited
-
tags/1.1.7 (added)
-
tags/1.1.7/assets (added)
-
tags/1.1.7/assets/css (added)
-
tags/1.1.7/assets/css/admin.css (added)
-
tags/1.1.7/assets/css/creavibc-deactivation-feedback.css (added)
-
tags/1.1.7/assets/css/style.css (added)
-
tags/1.1.7/assets/images (added)
-
tags/1.1.7/assets/images/service_placeholder.png (added)
-
tags/1.1.7/assets/js (added)
-
tags/1.1.7/assets/js/admin.js (added)
-
tags/1.1.7/assets/js/booking.js (added)
-
tags/1.1.7/assets/js/cbs-gcal-busy-admin.js (added)
-
tags/1.1.7/assets/js/creavibc-deactivation-feedback.js (added)
-
tags/1.1.7/assets/vendor (added)
-
tags/1.1.7/assets/vendor/flatpickr (added)
-
tags/1.1.7/assets/vendor/flatpickr/flatpickr.min.css (added)
-
tags/1.1.7/assets/vendor/flatpickr/flatpickr.min.js (added)
-
tags/1.1.7/assets/vendor/flatpickr/l10n (added)
-
tags/1.1.7/assets/vendor/flatpickr/l10n/da.js (added)
-
tags/1.1.7/assets/vendor/flatpickr/l10n/fr.js (added)
-
tags/1.1.7/assets/vendor/luxon (added)
-
tags/1.1.7/assets/vendor/luxon/luxon.min.js (added)
-
tags/1.1.7/creavi-booking-service.php (added)
-
tags/1.1.7/includes (added)
-
tags/1.1.7/includes/admin.php (added)
-
tags/1.1.7/includes/ajax-handlers.php (added)
-
tags/1.1.7/includes/cbs-gcal-remote.php (added)
-
tags/1.1.7/includes/deactivation-feedback.php (added)
-
tags/1.1.7/includes/functions.php (added)
-
tags/1.1.7/includes/gcal-freebusy.php (added)
-
tags/1.1.7/includes/meta-boxes.php (added)
-
tags/1.1.7/includes/placeholders.php (added)
-
tags/1.1.7/includes/post-types.php (added)
-
tags/1.1.7/includes/reminders.php (added)
-
tags/1.1.7/includes/render-booking-inline.php (added)
-
tags/1.1.7/includes/save-service.php (added)
-
tags/1.1.7/languages (added)
-
tags/1.1.7/languages/creavi-booking-service-da_DK-creavibc-script.json (added)
-
tags/1.1.7/languages/creavi-booking-service-da_DK.mo (added)
-
tags/1.1.7/languages/creavi-booking-service-da_DK.po (added)
-
tags/1.1.7/languages/creavi-booking-service-fr_FR-creavibc-script.json (added)
-
tags/1.1.7/languages/creavi-booking-service-fr_FR.mo (added)
-
tags/1.1.7/languages/creavi-booking-service-fr_FR.po (added)
-
tags/1.1.7/languages/creavi-booking-service.pot (added)
-
tags/1.1.7/readme.txt (added)
-
trunk/assets/js/admin.js (modified) (3 diffs)
-
trunk/assets/js/booking.js (modified) (9 diffs)
-
trunk/assets/vendor/flatpickr/l10n (added)
-
trunk/assets/vendor/flatpickr/l10n/da.js (added)
-
trunk/assets/vendor/flatpickr/l10n/fr.js (added)
-
trunk/creavi-booking-service.php (modified) (7 diffs)
-
trunk/includes/functions.php (modified) (2 diffs)
-
trunk/includes/meta-boxes.php (modified) (28 diffs)
-
trunk/languages (added)
-
trunk/languages/creavi-booking-service-da_DK-creavibc-script.json (added)
-
trunk/languages/creavi-booking-service-da_DK.mo (added)
-
trunk/languages/creavi-booking-service-da_DK.po (added)
-
trunk/languages/creavi-booking-service-fr_FR-creavibc-script.json (added)
-
trunk/languages/creavi-booking-service-fr_FR.mo (added)
-
trunk/languages/creavi-booking-service-fr_FR.po (added)
-
trunk/languages/creavi-booking-service.pot (added)
-
trunk/readme.txt (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
creavi-booking-service/trunk/assets/js/admin.js
r3431070 r3454590 95 95 }); 96 96 97 /*98 document.addEventListener('DOMContentLoaded', function () {99 const field = document.querySelector("#creavibc_available_booking_days");100 101 if (!field || typeof flatpickr === "undefined") {102 console.warn('Flatpickr or input not found');103 return;104 }105 106 const defaultDates = field.value107 ? field.value.split(',').map(s => s.trim())108 : [];109 110 flatpickr(field, {111 mode: "multiple",112 dateFormat: "Y-m-d",113 defaultDate: defaultDates,114 closeOnSelect: false,115 onChange: function (selectedDates, dateStr, instance) {116 const formatted = selectedDates.map(date =>117 instance.formatDate(date, "Y-m-d")118 ).join(',');119 field.value = formatted;120 field.dispatchEvent(new Event('input', { bubbles: true }));121 }122 });123 });*/124 97 125 98 document.addEventListener('DOMContentLoaded', function () { … … 202 175 203 176 if (addBtn && container) { 204 205 177 206 178 207 179 addBtn.addEventListener('click', () => { … … 577 549 } 578 550 579 580 581 582 583 584 551 }); 585 552 -
creavi-booking-service/trunk/assets/js/booking.js
r3448790 r3454590 1 1 jQuery(function ($) { 2 3 const i18n = (window.wp && wp.i18n) ? wp.i18n : null; 4 const __ = i18n ? i18n.__ : (s) => s; 5 const sprintf = i18n ? i18n.sprintf : (fmt, ...args) => [fmt, ...args].join(' '); 6 const CBS_DOMAIN = 'creavi-booking-service'; 7 8 function creavibcApplyFlatpickrLocale() { 9 if (!window.flatpickr || !window.creavibc_ajax) return; 10 11 const wpLocale = String(creavibc_ajax.locale || '').toLowerCase(); 12 13 if (wpLocale.startsWith('fr') && flatpickr.l10ns.fr) flatpickr.localize(flatpickr.l10ns.fr); 14 if (wpLocale.startsWith('da') && flatpickr.l10ns.da) flatpickr.localize(flatpickr.l10ns.da); 15 } 16 17 creavibcApplyFlatpickrLocale(); 18 19 20 2 21 function isValidEmail(email) { 3 22 return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); … … 24 43 if (val === '') { 25 44 $input.addClass('creavibc-field-error'); 26 $input.after('<span class="creavibc-error-msg">This field is required.</span>'); 45 //$input.after('<span class="creavibc-error-msg">This field is required.</span>'); 46 $input.after('<span class="creavibc-error-msg">' + __( 'This field is required.', CBS_DOMAIN ) + '</span>'); 47 27 48 return false; 28 49 } 29 50 if (isEmail && !isValidEmail(val)) { 30 51 $input.addClass('creavibc-field-error'); 31 $input.after('<span class="creavibc-error-msg">Please enter a valid email address.</span>'); 52 //$input.after('<span class="creavibc-error-msg">Please enter a valid email address.</span>'); 53 $input.after('<span class="creavibc-error-msg">' + __( 'Please enter a valid email address.', CBS_DOMAIN ) + '</span>'); 54 32 55 return false; 33 56 } … … 65 88 const backBtn = popup.querySelector('.creavibc-back'); 66 89 67 if (step === 1) { 68 nextBtn.textContent = 'Next';90 if (step === 1) { 91 nextBtn.textContent = __( 'Next', CBS_DOMAIN ); 69 92 nextBtn.classList.remove('creavibc-submit-final'); 70 93 backBtn.disabled = true; 71 94 } else { 72 nextBtn.textContent = 'Book a Meeting'; 95 96 nextBtn.textContent = __( 'Book a Meeting', CBS_DOMAIN ); 73 97 nextBtn.classList.add('creavibc-submit-final'); 74 98 backBtn.disabled = false; … … 214 238 215 239 const instance = window.CREAVIBC_INSTANCES?.[serviceId]; 216 const thankyouText = instance?.THANKYOU_TEXT || "Thank you for booking\nSee you soon!"; 240 //const thankyouText = instance?.THANKYOU_TEXT || "Thank you for booking\nSee you soon!"; 241 const thankyouText = instance?.THANKYOU_TEXT || __( "Thank you for booking\nSee you soon!", CBS_DOMAIN ); 242 217 243 console.log(instance.THANKYOU_TEXT); 218 244 … … 235 261 .removeClass('creavibc-submit-final') 236 262 .addClass('creavibc-close-final') 237 .text('Close'); 263 .text( __( 'Close', CBS_DOMAIN ) ); 264 238 265 }); 239 266 }); … … 427 454 428 455 const form = CREAVIBC_INSTANCES[serviceId].FORM_FIELDS; 429 let html = '<p class="creavibc-form-heading"><strong>Enter your details:</strong></p>'; 456 //let html = '<p class="creavibc-form-heading"><strong>Enter your details:</strong></p>'; 457 let html = '<p class="creavibc-form-heading"><strong>' + __( 'Enter your details:', CBS_DOMAIN ) + '</strong></p>'; 458 430 459 431 460 if (form.name) { 432 461 const isRequired = form.required?.name ? 'required' : ''; 433 462 const asterisk = isRequired ? ' <span class="creavibc-required">*</span>' : ''; 434 html += `<label>Name${asterisk}<br><input type="text" id="creavibc-name-${serviceId}" ${isRequired}></label>`; 463 //html += `<label>Name${asterisk}<br><input type="text" id="creavibc-name-${serviceId}" ${isRequired}></label>`; 464 html += `<label>${ __( 'Name', CBS_DOMAIN ) }${asterisk}<br><input type="text" id="creavibc-name-${serviceId}" ${isRequired}></label>`; 465 435 466 } 436 467 … … 438 469 const isRequired = form.required?.email ? 'required' : ''; 439 470 const asterisk = isRequired ? ' <span class="creavibc-required">*</span>' : ''; 440 html += `<label>Email${asterisk}<br><input type="email" id="creavibc-email-${serviceId}" ${isRequired}></label>`; 471 //html += `<label>Email${asterisk}<br><input type="email" id="creavibc-email-${serviceId}" ${isRequired}></label>`; 472 html += `<label>${ __( 'Email', CBS_DOMAIN ) }${asterisk}<br><input type="email" id="creavibc-email-${serviceId}" ${isRequired}></label>`; 473 441 474 } 442 475 443 476 if (Array.isArray(form.custom)) { 444 477 form.custom.forEach((field, i) => { 445 const label = field.label || `Field ${i + 1}`; 478 //const label = field.label || `Field ${i + 1}`; 479 const label = field.label || sprintf( __( 'Field %d', CBS_DOMAIN ), i + 1 ); 480 446 481 const type = field.type || 'text'; 447 482 const required = field.required ? 'required' : ''; … … 630 665 631 666 if (!slots.length) { 632 container.innerHTML = '<p>No slots available for this date.</p>'; 667 668 container.innerHTML = '<p>' + __( 'No slots available for this date.', CBS_DOMAIN ) + '</p>'; 669 633 670 return; 634 671 } … … 745 782 let message = ''; 746 783 if (tzMode === 'locked' && adminTimezone !== userTimezone) { 747 message = `Time slots shown in provider’s timezone: ${adminTimezone}`; 784 //message = `Time slots shown in provider’s timezone: ${adminTimezone}`; 785 message = sprintf( 786 __( 'Time slots shown in provider’s timezone: %s', CBS_DOMAIN ), 787 adminTimezone 788 ); 789 748 790 } else { 749 message = `Time slots are shown in your local timezone: ${userTimezone}`; 791 //message = `Time slots are shown in your local timezone: ${userTimezone}`; 792 message = sprintf( 793 __( 'Time slots are shown in your local timezone: %s', CBS_DOMAIN ), 794 userTimezone 795 ); 796 750 797 } 751 798 tzNotice.innerHTML = message; -
creavi-booking-service/trunk/creavi-booking-service.php
r3448790 r3454590 4 4 * Description: Easy appointment booking system. Create services, manage availability, and accept bookings with a simple booking calendar. 5 5 * Text Domain: creavi-booking-service 6 * Version: 1.1.6 6 * Domain Path: /languages 7 * Version: 1.1.7 7 8 * Author: Creavi 8 9 * License: GPL2 … … 15 16 define('CREAVIBC_PLUGIN_URL', plugin_dir_url(__FILE__)); 16 17 define('CREAVIBC_PLUGIN_PATH', plugin_dir_path(__FILE__)); 17 define('CREAVIBC_VERSION', '1.1.6'); 18 define('CREAVIBC_VERSION', '1.1.7'); 19 20 21 add_action( 'plugins_loaded', function () { 22 $domain = 'creavi-booking-service'; 23 $locale = function_exists( 'determine_locale' ) ? determine_locale() : get_locale(); 24 25 $global_mo = WP_LANG_DIR . '/plugins/' . $domain . '-' . $locale . '.mo'; 26 $plugin_mo = plugin_dir_path( __FILE__ ) . 'languages/' . $domain . '-' . $locale . '.mo'; 27 28 // Prefer global packs if present 29 if ( file_exists( $global_mo ) ) { 30 load_textdomain( $domain, $global_mo ); 31 return; 32 } 33 34 // Otherwise load bundled MO 35 if ( file_exists( $plugin_mo ) ) { 36 load_textdomain( $domain, $plugin_mo ); 37 } 38 }, 1 ); 39 18 40 19 41 require_once CREAVIBC_PLUGIN_DIR . 'includes/deactivation-feedback.php'; … … 35 57 36 58 37 add_action( 'wp_enqueue_scripts', function () {38 59 add_action( 'wp_enqueue_scripts', function () { 60 39 61 // Vendor scripts 40 62 wp_enqueue_script( … … 60 82 true 61 83 ); 84 85 // Flatpickr locale loading (conditional) 86 87 $locale = function_exists( 'determine_locale' ) 88 ? determine_locale() 89 : get_locale(); 62 90 91 // Normalize (fr_FR → fr, da_DK → da) 92 $flatpickr_locale = strtolower( substr( $locale, 0, 2 ) ); 63 93 64 wp_enqueue_style('creavibc-style', CREAVIBC_PLUGIN_URL . 'assets/css/style.css', [], CREAVIBC_VERSION); 65 $all_styles = get_option('creavibc_dynamic_button_styles', []); 66 if (!empty($all_styles)) { 67 wp_add_inline_style('creavibc-style', implode("\n", $all_styles)); 94 $supported_locales = [ 'fr', 'da' ]; 95 96 if ( in_array( $flatpickr_locale, $supported_locales, true ) ) { 97 wp_enqueue_script( 98 'flatpickr-l10n-' . $flatpickr_locale, 99 CREAVIBC_PLUGIN_URL . 'assets/vendor/flatpickr/l10n/' . $flatpickr_locale . '.js', 100 [ 'flatpickr' ], 101 '4.6.13', 102 true 103 ); 68 104 } 69 105 70 wp_enqueue_style('dashicons'); 71 106 wp_enqueue_style( 107 'creavibc-style', 108 CREAVIBC_PLUGIN_URL . 'assets/css/style.css', 109 [], 110 CREAVIBC_VERSION 111 ); 112 113 $all_styles = get_option( 'creavibc_dynamic_button_styles', [] ); 114 if ( ! empty( $all_styles ) ) { 115 wp_add_inline_style( 'creavibc-style', implode( "\n", $all_styles ) ); 116 } 117 118 wp_enqueue_style( 'dashicons' ); 119 72 120 }); 73 74 121 75 122 … … 77 124 78 125 function creavibc_booking_admin_menu() { 126 79 127 // Main menu 80 128 add_menu_page( 81 'Creavi Booking',82 'Creavi Booking',129 __( 'Creavi Booking', 'creavi-booking-service' ), 130 __( 'Creavi Booking', 'creavi-booking-service' ), 83 131 'manage_options', 84 132 'edit.php?post_type=creavibc_service', … … 91 139 add_submenu_page( 92 140 'edit.php?post_type=creavibc_service', 93 'Services',94 'Services',141 __( 'Services', 'creavi-booking-service' ), 142 __( 'Services', 'creavi-booking-service' ), 95 143 'manage_options', 96 144 'edit.php?post_type=creavibc_service' … … 100 148 add_submenu_page( 101 149 'edit.php?post_type=creavibc_service', 102 'All Bookings',103 'All Bookings',150 __( 'All Bookings', 'creavi-booking-service' ), 151 __( 'All Bookings', 'creavi-booking-service' ), 104 152 'manage_options', 105 153 'edit.php?post_type=creavibc_booking' 106 154 ); 107 155 } 156 108 157 109 158 register_deactivation_hook(__FILE__, function () { -
creavi-booking-service/trunk/includes/functions.php
r3448790 r3454590 22 22 if (!in_array($service_id, $creavibc_services_on_page)) { 23 23 $creavibc_services_on_page[] = $service_id; 24 } 25 26 $btn_text = get_post_meta($service_id, '_creavibc_button_text', true) ?: 'Book Now'; 24 } 25 26 $btn_text = get_post_meta( $service_id, '_creavibc_button_text', true ); 27 if ( '' === (string) $btn_text ) { 28 $btn_text = __( 'Book Now', 'creavi-booking-service' ); 29 } 30 31 27 32 return '<button class="creavibc-book-now-btn" data-service-id="' . esc_attr($service_id) . '">' . esc_html($btn_text) . '</button>'; 28 33 … … 195 200 196 201 add_action('wp_enqueue_scripts', function() { 197 wp_register_script( 198 'creavibc-script', 199 CREAVIBC_PLUGIN_URL . 'assets/js/booking.js', 200 ['jquery', 'flatpickr', 'luxon'], 201 CREAVIBC_VERSION, 202 true 203 ); 204 205 wp_enqueue_script('creavibc-script'); 206 207 wp_localize_script('creavibc-script', 'creavibc_ajax', [ 202 wp_register_script( 203 'creavibc-script', 204 CREAVIBC_PLUGIN_URL . 'assets/js/booking.js', 205 ['jquery', 'flatpickr', 'luxon', 'wp-i18n'], 206 CREAVIBC_VERSION, 207 true 208 ); 209 210 wp_localize_script('creavibc-script', 'creavibc_ajax', [ 208 211 'ajax_url' => admin_url('admin-ajax.php'), 209 212 'nonce' => wp_create_nonce('creavibc_booking_nonce'), 210 213 'week_starts_on' => (int) get_option('start_of_week', 0), // WP setting 214 'locale' => function_exists('determine_locale') ? determine_locale() : get_locale(), 215 211 216 ]); 212 217 218 wp_set_script_translations( 219 'creavibc-script', 220 'creavi-booking-service', 221 CREAVIBC_PLUGIN_DIR . 'languages' 222 ); 223 224 wp_enqueue_script('creavibc-script'); 225 213 226 }); 227 214 228 215 229 -
creavi-booking-service/trunk/includes/meta-boxes.php
r3448790 r3454590 6 6 add_meta_box( 7 7 'creavibc_output_type', 8 'Booking Display Type',8 __( 'Booking Display Type', 'creavi-booking-service' ), 9 9 'creavibc_render_output_type_box', 10 10 'creavibc_service', … … 12 12 'default' 13 13 ); 14 add_meta_box('creavibc_available_days', 'Available Booking Days', 'creavibc_render_available_days_box', 'creavibc_service', 'normal', 'high'); 15 add_meta_box('creavibc_booking_form_fields', 'Booking Form Fields', 'creavibc_render_form_fields_box', 'creavibc_service', 'normal', 'default'); 16 add_meta_box('creavibc_booking_details', 'Booking Details', 'creavibc_render_booking_meta', 'creavibc_booking', 'normal', 'default'); 14 add_meta_box('creavibc_available_days', __( 'Available Booking Days', 'creavi-booking-service' ), 'creavibc_render_available_days_box', 'creavibc_service', 'normal', 'high'); 15 16 add_meta_box('creavibc_booking_form_fields', __( 'Booking Form Fields', 'creavi-booking-service' ), 'creavibc_render_form_fields_box', 'creavibc_service', 'normal', 'default'); 17 add_meta_box('creavibc_booking_details', __( 'Booking Details', 'creavi-booking-service' ), 'creavibc_render_booking_meta', 'creavibc_booking', 'normal', 'default'); 17 18 add_meta_box( 18 19 'creavibc_time_slot_grid', 19 'Visual Time Slot Selector',20 __( 'Visual Time Slot Selector', 'creavi-booking-service' ), 20 21 'creavibc_render_weekday_slots_grid_box', 21 22 'creavibc_service', … … 26 27 add_meta_box( 27 28 'creavibc_service_options', 28 'Booking Appearance & Notifications',29 __( 'Booking Appearance & Notifications', 'creavi-booking-service' ), 29 30 'creavibc_render_service_options_box', 30 31 'creavibc_service', … … 35 36 add_meta_box( 36 37 'creavibc_google_calendar', 37 'Google Calendar',38 __( 'Google Calendar', 'creavi-booking-service' ), 38 39 'creavibc_render_google_calendar_box', 39 40 'creavibc_service', … … 47 48 add_action('init', function () { 48 49 register_taxonomy('creavibc_service_category', 'creavibc_booking', [ 49 'label' => 'Service Category', 50 'labels' => [ 51 'name' => __( 'Service Categories', 'creavi-booking-service' ), 52 'singular_name' => __( 'Service Category', 'creavi-booking-service' ), 53 'menu_name' => __( 'Service Categories', 'creavi-booking-service' ), 54 ], 55 50 56 'hierarchical' => false, 51 57 'public' => false, … … 57 63 }); 58 64 59 /*60 function creavibc_render_output_type_box($post) {61 $stored_value = get_post_meta($post->ID, '_creavibc_output_type', true);62 $value = in_array($stored_value, ['popup', 'inline']) ? $stored_value : 'popup'; // stricter63 64 ?>65 <p><strong>How should the calendar appear?</strong></p>66 <label>67 <input type="radio" name="creavibc_output_type" value="popup" <?php checked($value, 'popup'); ?> />68 Popup (opens calendar in a modal on button click))69 </label><br>70 <label>71 <input type="radio" name="creavibc_output_type" value="inline" <?php checked($value, 'inline'); ?> />72 Inline (displays booking form directly on the page)73 </label>74 <?php75 wp_nonce_field('creavibc_save_output_type', 'creavibc_output_type_nonce');76 }*/77 65 78 66 function creavibc_render_output_type_box($post) { … … 90 78 <rect x="7" y="8" width="10" height="6" rx="1" fill="#007cba"/> 91 79 </svg> 92 <strong>Popup</strong><br> 93 Opens in a modal after clicking a button 80 <strong><?php esc_html_e( 'Popup', 'creavi-booking-service' ); ?></strong><br> 81 <?php esc_html_e( 'Opens in a modal after clicking a button', 'creavi-booking-service' ); ?> 82 94 83 </label> 95 84 … … 99 88 <path d="M3 4h18v2H3zm0 4h18v2H3zm0 4h18v2H3zm0 4h18v2H3zm0 4h18v2H3z"/> 100 89 </svg> 101 <strong>Inline</strong><br> 102 Embedded directly into the page 90 <strong><?php esc_html_e( 'Inline', 'creavi-booking-service' ); ?></strong><br> 91 <?php esc_html_e( 'Embedded directly into the page', 'creavi-booking-service' ); ?> 92 103 93 </label> 104 94 </div> … … 223 213 <select name="creavibc_dynamic_months_ahead" id="creavibc_dynamic_months_ahead" class="creavibc-select"> 224 214 <?php for ($i = 1; $i <= 12; $i++): ?> 225 <option value="<?php echo esc_attr($i); ?>" <?php selected($months_ahead, $i); ?>> 226 <?php echo esc_html($i . ' ' . __('month', 'creavi-booking-service') . ($i > 1 ? 's' : '')); ?> 215 216 <option value="<?php echo esc_attr( $i ); ?>" <?php selected( $months_ahead, $i ); ?>> 217 <?php 218 echo esc_html( 219 sprintf( 220 _n( '%d month', '%d months', $i, 'creavi-booking-service' ), 221 $i 222 ) 223 ); 224 ?> 227 225 </option> 226 227 228 228 <?php endfor; ?> 229 229 </select> … … 266 266 <?php for ($i = 1; $i <= 12; $i++): ?> 267 267 <option value="<?php echo esc_attr($i); ?>"> 268 <?php echo esc_html($i . ' Month' . ($i > 1 ? 's' : '') . ' Ahead'); ?> 268 <?php 269 echo esc_html( sprintf( 270 _n( '%d month ahead', '%d months ahead', $i, 'creavi-booking-service' ), 271 $i 272 ) ); ?> 273 269 274 </option> 270 275 <?php endfor; ?> … … 307 312 308 313 wp_nonce_field('creavibc_save_form_fields', 'creavibc_form_fields_nonce'); 309 echo '<p><strong>Enable Default Fields:</strong></p>'; 314 315 echo '<p><strong>' . esc_html__( 'Enable Default Fields:', 'creavi-booking-service' ) . '</strong></p>'; 310 316 311 317 $name_required = !empty($settings['required']['name']); … … 314 320 echo '<div class="creavibc-default-field-row">'; 315 321 echo '<label class="creavibc-checkbox-label">'; 316 echo '<input type="checkbox" name="creavibc_form_defaults[name]" value="1" ' . checked($defaults['name'], true, false) . '> Name';322 echo '<input type="checkbox" name="creavibc_form_defaults[name]" value="1" ' . checked($defaults['name'], true, false) . '> ' . esc_html__( 'Name', 'creavi-booking-service' ); 317 323 echo '</label>'; 318 324 echo '<label class="creavibc-checkbox-label">'; 319 echo '<input type="checkbox" name="creavibc_form_required[name]" value="1" ' . checked($name_required, true, false) . '> Required';325 echo '<input type="checkbox" name="creavibc_form_required[name]" value="1" ' . checked($name_required, true, false) . '> ' . esc_html__( 'Required', 'creavi-booking-service' ); 320 326 echo '</label>'; 321 327 echo '</div>'; … … 323 329 echo '<div class="creavibc-default-field-row">'; 324 330 echo '<label class="creavibc-checkbox-label">'; 325 echo '<input type="checkbox" name="creavibc_form_defaults[email]" value="1" ' . checked($defaults['email'], true, false) . '> Email';331 echo '<input type="checkbox" name="creavibc_form_defaults[email]" value="1" ' . checked($defaults['email'], true, false) . '> ' . esc_html__( 'Email', 'creavi-booking-service' ); 326 332 echo '</label>'; 327 333 echo '<label class="creavibc-checkbox-label">'; 328 echo '<input type="checkbox" name="creavibc_form_required[email]" value="1" ' . checked($email_required, true, false) . '> Required';334 echo '<input type="checkbox" name="creavibc_form_required[email]" value="1" ' . checked($email_required, true, false) . '> ' . esc_html__( 'Required', 'creavi-booking-service' ); 329 335 echo '</label>'; 330 336 echo '</div>'; 331 337 332 338 333 echo '<hr><p><strong> Custom Fields:</strong></p>';339 echo '<hr><p><strong>' . esc_html__( 'Custom Fields:', 'creavi-booking-service' ) . '</strong></p>'; 334 340 echo '<div id="creavibc-custom-fields-container">'; 335 341 … … 340 346 341 347 echo '<div class="creavibc-custom-row">'; 342 echo '<input type="text" name="creavibc_custom_fields[label][]" value="' . esc_attr($label) . '" placeholder=" Field label (e.g. Phone)" style="width: 45%;" />';348 echo '<input type="text" name="creavibc_custom_fields[label][]" value="' . esc_attr($label) . '" placeholder="' . esc_attr__( 'Field label (e.g. Phone)', 'creavi-booking-service' ) . '" style="width: 45%;" />'; 343 349 echo '<select name="creavibc_custom_fields[type][]" style="width: 20%;">'; 344 echo '<option value="text"' . ($type === 'text' ? ' selected' : '') . '> Text</option>';345 echo '<option value="textarea"' . ($type === 'textarea' ? ' selected' : '') . '> Textarea</option>';350 echo '<option value="text"' . ($type === 'text' ? ' selected' : '') . '>' . esc_html__( 'Text', 'creavi-booking-service' ) . '</option>'; 351 echo '<option value="textarea"' . ($type === 'textarea' ? ' selected' : '') . '>' . esc_html__( 'Textarea', 'creavi-booking-service' ) . '</option>'; 346 352 echo '</select>'; 347 echo '<label style="margin-left:10px;"><input type="checkbox" name="creavibc_custom_fields[required][' . esc_attr( $i) . ']" value="1"' . ($required ? 'checked' : '') . '> Required</label>';353 echo '<label style="margin-left:10px;"><input type="checkbox" name="creavibc_custom_fields[required][' . esc_attr( $i ) . ']" value="1"' . ( $required ? ' checked' : '' ) . '> ' . esc_html__( 'Required', 'creavi-booking-service' ) . '</label>'; 348 354 echo '<button type="button" class="button creavibc-remove-field">–</button>'; 349 355 echo '</div>'; … … 351 357 352 358 353 echo '</div><button type="button" class="button" id="creavibc-add-field">+ Add Custom Field</button>';359 echo '</div><button type="button" class="button" id="creavibc-add-field">+ ' . esc_html__( 'Add Custom Field', 'creavi-booking-service' ) . '</button>'; 354 360 } 355 361 … … 362 368 $custom = get_post_meta($post->ID, '_creavibc_booking_custom', true) ?: []; 363 369 364 echo "<p><strong>Date:</strong> " . esc_html($date) . "</p>"; 365 echo "<p><strong>Time:</strong> " . esc_html($time) . "</p>"; 366 echo "<p><strong>Name:</strong> " . esc_html($name) . "</p>"; 367 echo "<p><strong>Email:</strong> " . esc_html($email) . "</p>"; 368 echo "<p><strong>Comment:</strong><br>" . nl2br(esc_html($comment)) . "</p>"; 369 370 if (!empty($custom)) { 371 echo "<hr><p><strong>Custom Fields:</strong></p>"; 370 echo '<p><strong>' . esc_html__( 'Date:', 'creavi-booking-service' ) . '</strong> ' . esc_html( $date ) . '</p>'; 371 echo '<p><strong>' . esc_html__( 'Time:', 'creavi-booking-service' ) . '</strong> ' . esc_html( $time ) . '</p>'; 372 echo '<p><strong>' . esc_html__( 'Name:', 'creavi-booking-service' ) . '</strong> ' . esc_html( $name ) . '</p>'; 373 echo '<p><strong>' . esc_html__( 'Email:', 'creavi-booking-service' ) . '</strong> ' . esc_html( $email ) . '</p>'; 374 echo '<p><strong>' . esc_html__( 'Comment:', 'creavi-booking-service' ) . '</strong><br>' . nl2br( esc_html( $comment ) ) . '</p>'; 375 376 if ( ! empty( $custom ) ) { 377 echo '<hr><p><strong>' . esc_html__( 'Custom Fields:', 'creavi-booking-service' ) . '</strong></p>'; 378 372 379 foreach ($custom as $label => $value) { 373 380 echo "<p><strong>" . esc_html($label) . ":</strong> " . esc_html($value) . "</p>"; … … 380 387 $admin_tz = get_post_meta($post->ID, '_creavibc_admin_timezone', true) ?: date_default_timezone_get(); 381 388 382 echo '<p><strong>Appointment timezone:</strong></p>'; 383 384 echo '<label><input type="radio" name="creavibc_timezone_mode" value="localized" ' . checked($mode, 'localized', false) . '> Localized</label> '; 385 echo '<label><input type="radio" name="creavibc_timezone_mode" value="locked" ' . checked($mode, 'locked', false) . '> Locked</label>'; 389 echo '<p><strong>' . esc_html__( 'Appointment timezone:', 'creavi-booking-service' ) . '</strong></p>'; 390 echo '<label><input type="radio" name="creavibc_timezone_mode" value="localized" ' . checked( $mode, 'localized', false ) . '> ' . esc_html__( 'Localized', 'creavi-booking-service' ) . '</label> '; 391 echo '<label><input type="radio" name="creavibc_timezone_mode" value="locked" ' . checked( $mode, 'locked', false ) . '> ' . esc_html__( 'Locked', 'creavi-booking-service' ) . '</label>'; 386 392 387 393 echo '<p class="creavibc-timezone-description">'; 388 if ($mode === 'locked') { 389 echo 'Your customers will see available appointment times in <strong>' . esc_html($admin_tz) . '</strong>. Recommended for offline meetingss.'; 394 if ( 'locked' === $mode ) { 395 echo sprintf( 396 /* translators: %s: timezone string (e.g. Europe/Paris) */ 397 esc_html__( 'Your customers will see available appointment times in %s. Recommended for offline meetings.', 'creavi-booking-service' ), 398 '<strong>' . esc_html( $admin_tz ) . '</strong>' 399 ); 390 400 } else { 391 echo 'Your customers will see available appointment times in their own timezone. Recommended for online meetings.';401 echo esc_html__( 'Your customers will see available appointment times in their own timezone. Recommended for online meetings.', 'creavi-booking-service' ); 392 402 } 393 403 echo '</p>'; 404 394 405 } 395 406 … … 402 413 403 414 $weekdays = ['monday','tuesday','wednesday','thursday','friday','saturday','sunday']; 415 416 $weekday_labels = [ 417 'monday' => __( 'Monday', 'creavi-booking-service' ), 418 'tuesday' => __( 'Tuesday', 'creavi-booking-service' ), 419 'wednesday' => __( 'Wednesday', 'creavi-booking-service' ), 420 'thursday' => __( 'Thursday', 'creavi-booking-service' ), 421 'friday' => __( 'Friday', 'creavi-booking-service' ), 422 'saturday' => __( 'Saturday', 'creavi-booking-service' ), 423 'sunday' => __( 'Sunday', 'creavi-booking-service' ), 424 ]; 425 426 427 404 428 $times = []; 405 429 for ($h = 8; $h <= 16; $h++) { … … 416 440 ?> 417 441 418 < p><strong>Admin Timezone:</strong></p>442 <?php echo '<p><strong>' . esc_html__( 'Admin Timezone:', 'creavi-booking-service' ) . '</strong></p>'; ?> 419 443 420 444 <div id="creavibc-timezone-wrapper"> 421 445 <p> 422 Detected: <span id="creavibc-admin-tz-label"><?php echo esc_html($tz_value ?: '...'); ?></span> 423 <button type="button" id="creavibc-admin-tz-edit" class="button small">Change</button> 446 <?php echo esc_html__( 'Detected:', 'creavi-booking-service' ); ?> 447 <span id="creavibc-admin-tz-label"><?php echo esc_html( $tz_value ?: '...' ); ?></span> 448 <button type="button" id="creavibc-admin-tz-edit" class="button small"> 449 <?php echo esc_html__( 'Change', 'creavi-booking-service' ); ?> 450 </button> 424 451 </p> 425 426 <!-- 427 <select id="creavibc-admin-tz-select" name="creavibc_admin_timezone" style="display:none; max-width: 300px;"> 428 Populated via JS 429 </select> --> 452 430 453 431 454 <select id="creavibc-admin-tz-select" name="creavibc_admin_timezone" style="display:none; max-width: 300px;"> … … 442 465 <?php creavibc_render_service_timezone_setting($post); ?> 443 466 444 445 446 467 <?php 447 echo '<p><strong> Slot Duration:</strong></p>';468 echo '<p><strong>' . esc_html__( 'Slot Duration:', 'creavi-booking-service' ) . '</strong></p>'; 448 469 echo '<div id="creavibc-slot-duration-options">'; 449 470 foreach (['20','30','60'] as $min) { … … 462 483 ' . esc_html__( 'The weekday columns follow your WordPress “Week Starts On” setting (Settings → General).', 'creavi-booking-service' ) . ' 463 484 </div>'; 464 465 466 echo '<p><strong>Select appointment start times:</strong></p>'; 485 486 echo '<p><strong>' . esc_html__( 'Select appointment start times:', 'creavi-booking-service' ) . '</strong></p>'; 487 467 488 echo '<div id="creavibc-slot-wrapper" style="position:relative;">'; 468 489 echo '<div id="creavibc-slot-grid-container">'; … … 471 492 echo '<thead><tr><th></th>'; 472 493 foreach ($weekdays as $day) { 473 echo '<th>' . esc_html( ucfirst($day)) . '</th>';494 echo '<th>' . esc_html( $weekday_labels[ $day ] ?? ucfirst($day) ) . '</th>'; 474 495 } 475 496 echo '</tr></thead><tbody>'; … … 504 525 505 526 506 echo '<input type="hidden" name="creavibc_grid_slots" id="creavibc_grid_slots" value="' . esc_attr(implode(',', $stored_slots)) . '">'; 507 echo '<p class="description">Click cells to select/deselect time slots.</p>'; 527 echo '<input type="hidden" name="creavibc_grid_slots" id="creavibc_grid_slots" value="' . esc_attr(implode(',', $stored_slots)) . '">'; 528 echo '<p class="description">' . esc_html__( 'Click cells to select/deselect time slots.', 'creavi-booking-service' ) . '</p>'; 529 508 530 } 509 531 … … 531 553 $hover_border_color = get_post_meta($post->ID, '_creavibc_hover_border_color', true) ?: $bg_color; 532 554 533 $button_text = get_post_meta($post->ID, '_creavibc_button_text', true) ?: 'Book Now'; 555 $button_text = get_post_meta( $post->ID, '_creavibc_button_text', true ); 556 if ( empty( $button_text ) ) { 557 $button_text = __( 'Book Now', 'creavi-booking-service' ); 558 } 534 559 535 560 $color = get_post_meta($post->ID, '_creavibc_primary_color', true) ?: '#569FF7'; 536 $thankyou = get_post_meta($post->ID, '_creavibc_thankyou_text', true) ?: 'Thank you for booking! See you soon!'; 537 $admin_email_tpl = get_post_meta($post->ID, '_creavibc_email_admin_template', true) ?: "New booking:\n\nName: {name}\nEmail: {email}\nDate: {date}\nTime: {time}\nService: {service}"; 538 $user_email_tpl = get_post_meta($post->ID, '_creavibc_email_user_template', true) ?: "Hi {name},\n\nThanks for booking {service} on {date} at {time}."; 561 562 $thankyou = get_post_meta( $post->ID, '_creavibc_thankyou_text', true ); 563 if ( empty( $thankyou ) ) { 564 $thankyou = __( 'Thank you for booking! See you soon!', 'creavi-booking-service' ); 565 } 566 567 $admin_email_tpl = get_post_meta( $post->ID, '_creavibc_email_admin_template', true ); 568 if ( empty( $admin_email_tpl ) ) { 569 $admin_email_tpl = __( "New booking:\n\nName: {name}\nEmail: {email}\nDate: {date}\nTime: {time}\nService: {service}", 'creavi-booking-service' ); 570 } 571 572 $user_email_tpl = get_post_meta( $post->ID, '_creavibc_email_user_template', true ); 573 if ( empty( $user_email_tpl ) ) { 574 $user_email_tpl = __( "Hi {name},\n\nThanks for booking {service} on {date} at {time}.", 'creavi-booking-service' ); 575 } 539 576 540 577 wp_nonce_field('creavibc_save_service_options', 'creavibc_service_options_nonce'); 541 542 echo '<p><label for="creavibc_primary_color"><strong>Primary Brand Color:</strong></label><br>'; 578 579 echo '<p><label for="creavibc_primary_color"><strong>' . esc_html__( 'Primary Brand Color:', 'creavi-booking-service' ) . '</strong></label><br>'; 580 543 581 echo '<input type="color" id="creavibc_primary_color" name="creavibc_primary_color" value="' . esc_attr($color) . '" style="width: 100px;"></p>'; 544 582 545 echo '<p><label for="creavibc_button_text"><strong>Booking Button Text:</strong></label><br>'; 583 echo '<p><label for="creavibc_button_text"><strong>' . esc_html__( 'Booking Button Text:', 'creavi-booking-service' ) . '</strong></label><br>'; 584 546 585 echo '<input type="text" id="creavibc_button_text" name="creavibc_button_text" value="' . esc_attr($button_text) . '" style="width: 100%;"></p>'; 547 586 548 echo '<hr><h4 style="margin-top: 30px;"> Booking Button Style</h4>';549 echo '<hr><h4 class="creavibc-subsection">Booking Button Style</h4>';587 echo '<hr><h4 style="margin-top: 30px;">' . esc_html__( 'Booking Button Style', 'creavi-booking-service' ) . '</h4>'; 588 550 589 551 590 $allowed = [ … … 562 601 563 602 echo '<div class="creavibc-style-grid">'; 564 echo wp_kses( creavibc_style_field('Text Color:', 'creavibc_button_text_color', $text_color, 'color'), $allowed );565 echo wp_kses( creavibc_style_field('Background:', 'creavibc_button_bg_color', $bg_color, 'color'), $allowed );566 echo wp_kses( creavibc_style_field('Border Color:', 'creavibc_button_border_color', $border_color, 'color'), $allowed );603 echo wp_kses( creavibc_style_field( __( 'Text Color:', 'creavi-booking-service' ), 'creavibc_button_text_color', $text_color, 'color' ), $allowed ); 604 echo wp_kses( creavibc_style_field( __( 'Background:', 'creavi-booking-service' ), 'creavibc_button_bg_color', $bg_color, 'color' ), $allowed ); 605 echo wp_kses( creavibc_style_field( __( 'Border Color:', 'creavi-booking-service' ), 'creavibc_button_border_color', $border_color, 'color' ), $allowed ); 567 606 echo '</div>'; 568 607 569 608 echo '<div class="creavibc-style-grid">'; 570 echo wp_kses( creavibc_style_field('Border Radius (px):', 'creavibc_button_radius', $radius, 'number'), $allowed );571 echo wp_kses( creavibc_style_field('Font Size (px):', 'creavibc_button_font_size', $font_size, 'number'), $allowed );609 echo wp_kses( creavibc_style_field( __( 'Border Radius (px):', 'creavi-booking-service' ), 'creavibc_button_radius', $radius, 'number' ), $allowed ); 610 echo wp_kses( creavibc_style_field( __( 'Font Size (px):', 'creavi-booking-service' ), 'creavibc_button_font_size', $font_size, 'number' ), $allowed ); 572 611 echo '</div>'; 573 612 574 613 echo '<div class="creavibc-style-grid">'; 575 echo wp_kses( creavibc_style_field('Padding Vertical (px):', 'creavibc_button_padding_vertical', $padding_vertical, 'number'), $allowed );576 echo wp_kses( creavibc_style_field('Padding Horizontal (px):', 'creavibc_button_padding_horizontal', $padding_horizontal, 'number'), $allowed );577 echo '</div>'; 578 579 echo '<h4 class="creavibc-subsection"> Hover Styles</h4>';614 echo wp_kses( creavibc_style_field( __( 'Padding Vertical (px):', 'creavi-booking-service' ), 'creavibc_button_padding_vertical', $padding_vertical, 'number' ), $allowed ); 615 echo wp_kses( creavibc_style_field( __( 'Padding Horizontal (px):', 'creavi-booking-service' ), 'creavibc_button_padding_horizontal', $padding_horizontal, 'number' ), $allowed ); 616 echo '</div>'; 617 618 echo '<h4 class="creavibc-subsection">' . esc_html__( 'Hover Styles', 'creavi-booking-service' ) . '</h4>'; 580 619 echo '<div class="creavibc-style-grid">'; 581 echo wp_kses( creavibc_style_field('Text Color:', 'creavibc_hover_text_color', $hover_text_color, 'color'), $allowed );582 echo wp_kses( creavibc_style_field('Background:', 'creavibc_hover_bg_color', $hover_bg_color, 'color'), $allowed );583 echo wp_kses( creavibc_style_field('Border Color:', 'creavibc_hover_border_color', $hover_border_color, 'color'), $allowed );584 echo '</div>'; 585 586 echo '<hr><h4 class="creavibc-subsection"> Notifications</h4>';587 588 echo '<p><label for="creavibc_thankyou_text"><strong> Thank You Text:</strong></label><br>';620 echo wp_kses( creavibc_style_field( __( 'Text Color:', 'creavi-booking-service' ), 'creavibc_hover_text_color', $hover_text_color, 'color' ), $allowed ); 621 echo wp_kses( creavibc_style_field( __( 'Background:', 'creavi-booking-service' ), 'creavibc_hover_bg_color', $hover_bg_color, 'color' ), $allowed ); 622 echo wp_kses( creavibc_style_field( __( 'Border Color:', 'creavi-booking-service' ), 'creavibc_hover_border_color', $hover_border_color, 'color' ), $allowed ); 623 echo '</div>'; 624 625 echo '<hr><h4 class="creavibc-subsection">' . esc_html__( 'Notifications', 'creavi-booking-service' ) . '</h4>'; 626 627 echo '<p><label for="creavibc_thankyou_text"><strong>' . esc_html__( 'Thank You Text:', 'creavi-booking-service' ) . '</strong></label><br>'; 589 628 echo '<input type="text" id="creavibc_thankyou_text" name="creavibc_thankyou_text" value="' . esc_attr($thankyou) . '" style="width: 100%;"></p>'; 590 629 591 echo '<p><label for="creavibc_email_admin_template"><strong> Admin Email Template:</strong></label><br>';630 echo '<p><label for="creavibc_email_admin_template"><strong>' . esc_html__( 'Admin Email Template:', 'creavi-booking-service' ) . '</strong></label><br>'; 592 631 echo '<textarea name="creavibc_email_admin_template" id="creavibc_email_admin_template" rows="4" style="width: 100%;">' . esc_textarea($admin_email_tpl) . '</textarea></p>'; 593 632 … … 598 637 } 599 638 600 echo '<p><label for="creavibc_gcal_admin_email"><strong> Admin Notification Email:</strong></label><br>';639 echo '<p><label for="creavibc_gcal_admin_email"><strong>' . esc_html__( 'Admin Notification Email:', 'creavi-booking-service' ) . '</strong></label><br>'; 601 640 echo '<input type="email" id="creavibc_gcal_admin_email" name="creavibc_gcal_admin_email" value="' . esc_attr($gcal_admin_email) . '" class="regular-text">'; 602 echo '<br><span class="description">Defaults to the site admin email (' . esc_html(get_option('admin_email')) . ') if not set. Used for notifications and calendar invites.</span></p>'; 603 604 605 echo '<p><label for="creavibc_email_user_template"><strong>User Email Template:</strong></label><br>'; 641 642 echo '<br><span class="description">'; 643 echo sprintf( 644 /* translators: %s: admin email */ 645 esc_html__( 'Defaults to the site admin email (%s) if not set. Used for notifications and calendar invites.', 'creavi-booking-service' ), 646 esc_html( get_option( 'admin_email' ) ) 647 ); 648 echo '</span></p>'; 649 650 echo '<p><label for="creavibc_email_user_template"><strong>' . esc_html__( 'User Email Template:', 'creavi-booking-service' ) . '</strong></label><br>'; 606 651 echo '<textarea name="creavibc_email_user_template" id="creavibc_email_user_template" rows="4" style="width: 100%;">' . esc_textarea($user_email_tpl) . '</textarea></p>'; 607 608 echo '<p class="description"> Available tags: {name}, {email}, {date}, {time}, {service}</p>';652 653 echo '<p class="description">' . esc_html__( 'Available tags:', 'creavi-booking-service' ) . ' {name}, {email}, {date}, {time}, {service}</p>'; 609 654 610 655 // --------------------------- … … 619 664 } 620 665 621 $reminder_subject = get_post_meta( $post->ID, '_creavibc_email_reminder_subject', true ); 666 $reminder_subject = get_post_meta( $post->ID, '_creavibc_email_reminder_subject', true ); 667 668 622 669 if ( empty( $reminder_subject ) ) { 623 $reminder_subject = 'Reminder: {service} on {date} at {time}'; 624 } 625 670 $reminder_subject = __( 'Reminder: {service} on {date} at {time}', 'creavi-booking-service' ); 671 } 626 672 $reminder_tpl = get_post_meta( $post->ID, '_creavibc_email_reminder_template', true ); 627 673 if ( empty( $reminder_tpl ) ) { 628 $reminder_tpl = "Hi {name},\n\nJust a friendly reminder about your upcoming appointment:\n\nService: {service}\nDate: {date}\nTime: {time}\n\nSee you soon!"; 629 } 674 $reminder_tpl = __( "Hi {name},\n\nJust a friendly reminder about your upcoming appointment:\n\nService: {service}\nDate: {date}\nTime: {time}\n\nSee you soon!", 'creavi-booking-service' ); 675 } 676 630 677 631 678 $reminder_options = array( … … 688 735 } 689 736 690 add_filter('manage_creavibc_service_posts_columns', function($columns) { 691 $columns['creavibc_shortcode'] = 'Shortcode'; 737 add_filter('manage_creavibc_service_posts_columns', function($columns) { 738 $columns['creavibc_shortcode'] = __( 'Shortcode', 'creavi-booking-service' ); 739 692 740 return $columns; 693 741 }); -
creavi-booking-service/trunk/readme.txt
r3448790 r3454590 5 5 Tested up to: 6.7 6 6 Requires PHP: 7.4 7 Stable tag: 1.1. 67 Stable tag: 1.1.7 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 49 49 * Bookings stored as custom post types for easy management 50 50 * Custom taxonomy to categorize and filter services 51 * Multilingual & Translation Ready 51 52 52 53 == Installation == … … 85 86 86 87 == Changelog == 88 89 = 1.1.7 = 90 * Added multilingual support for frontend and admin. 91 * Included French (fr_FR) and Danish (da_DK) translations. 87 92 88 93 = 1.1.6 =
Note: See TracChangeset
for help on using the changeset viewer.