diff --git a/.distignore b/.distignore index 44cee3b58..01f67b837 100644 --- a/.distignore +++ b/.distignore @@ -21,4 +21,5 @@ phpunit project.json README.md tsconfig.* -webpack.config.js \ No newline at end of file +webpack.config.js +phpstan.neon \ No newline at end of file diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml new file mode 100644 index 000000000..0de281cac --- /dev/null +++ b/.github/workflows/phpstan.yml @@ -0,0 +1,47 @@ +name: PHPStan + +on: + push: + branches: + - 'master' + - 'release/**' + paths-ignore: + - '**.md' + - '**.txt' + pull_request: + branches: + - 'master' + +jobs: + phpstan: + name: 'WP latest on PHP 8.3' + + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v4 + + # TODO Use the composer action below + - uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + extensions: uopz + + - name: Validate composer.json and composer.lock + run: composer validate + + - name: Install dependencies (other PHP versions) + run: | + composer install --prefer-dist --no-progress --ignore-platform-reqs + + - name: Run static suite + run: | + composer dump-autoload -o + + #- uses: actions/checkout@v4 + #- uses: php-actions/composer@v6 + + - name: PHPStan Static Analysis + uses: php-actions/phpstan@v3 + with: + configuration: phpstan.neon diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist index f05d90274..d471a57ac 100644 --- a/.phpcs.xml.dist +++ b/.phpcs.xml.dist @@ -74,8 +74,12 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https: - - + + + + + + diff --git a/Gruntfile.js b/Gruntfile.js index 499399d5e..277e75aff 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -170,7 +170,10 @@ module.exports = function (grunt) { ], tasks: [ 'dart-sass:adminDev', 'dart-sass:publicDev' - ] + ], + options: { + livereload: true + } }, js: { files: [ diff --git a/assets/admin/css/admin.css b/assets/admin/css/admin.css index 5727a3e16..5aa836dc3 100644 --- a/assets/admin/css/admin.css +++ b/assets/admin/css/admin.css @@ -1,3 +1,4 @@ +@charset "UTF-8"; /* * Admin styles * @@ -3176,7 +3177,7 @@ * */ /* -------------------- Boxes -------------------- */ -.cb-box { +.cb-box, .cb-admin-page .cb-admin-cols div ul li { background: var(--commonsbooking-color-gray-background); overflow: hidden; border-radius: var(--commonsbooking-radius); @@ -3184,7 +3185,7 @@ padding: var(--commonsbooking-spacer-small)/2 var(--commonsbooking-spacer-small); } @media (min-width: 37.5em) { - .cb-box { + .cb-box, .cb-admin-page .cb-admin-cols div ul li { padding: var(--commonsbooking-spacer) var(--commonsbooking-spacer-big); } } @@ -3507,7 +3508,40 @@ a.disabled { display: none; } -/* Booking form */ +/* Map creation */ +/* +* The CPT creation form map + */ +#cmb2-metabox-cb_map-custom-fields .map-organizer .cmb2-metabox-title { + font-size: x-large; +} +#cmb2-metabox-cb_map-custom-fields .map-organizer .cmb2-metabox-title:before { + /* arrow to right */ + content: "→ "; +} +#cmb2-metabox-cb_map-custom-fields .cmb-group-name { + font-size: x-large; + font-weight: bold; +} +#cmb2-metabox-cb_map-custom-fields .cmb-group-name:before { + content: "→ "; +} +#cmb2-metabox-cb_map-custom-fields #shortcode-field { + display: flex; + align-items: center; + flex-wrap: nowrap; + gap: 10px; +} +#cmb2-metabox-cb_map-custom-fields #shortcode-field code { + white-space: nowrap; + margin-right: 10px; +} +#cmb2-metabox-cb_map-custom-fields #shortcode-field .button { + padding: 5px 10px; + line-height: 1.5; +} + +/* Plugin update page */ /** * Plugin list update message * diff --git a/assets/admin/js/admin.js b/assets/admin/js/admin.js index 52c83921c..d5dc4a935 100644 --- a/assets/admin/js/admin.js +++ b/assets/admin/js/admin.js @@ -5,6 +5,14 @@ let startTimeInput = $("#repetition-start_time"); let endTimeInput = $("#repetition-end_time"); let preserveManualCode = false; + let itemInput = $("#item-id"); + let locationInput = $("#location-id"); + let startDateInput = $("#repetition-start_date"); + let bookingCodeInput = $("#_cb_bookingcode"); + let allExist = [ fullDayCheckbox, startTimeInput, endTimeInput, itemInput, locationInput, startDateInput, bookingCodeInput ].every(domElement => domElement.length === 1); + if (!allExist) { + return; + } fullDayCheckbox.on("change", function(event) { if (fullDayCheckbox.is(":checked")) { startTimeInput.val("00:00"); @@ -17,10 +25,6 @@ } }); fullDayCheckbox.trigger("change"); - let itemInput = $("#item-id"); - let locationInput = $("#location-id"); - let startDateInput = $("#repetition-start_date"); - let bookingCodeInput = $("#_cb_bookingcode"); itemInput.on("change", function(event) { let data = { itemID: itemInput.val() @@ -377,6 +381,69 @@ }); })(jQuery); +(function($) { + "use strict"; + $(function() { + const mapSettingsForm = $("#cmb2-metabox-cb_map-custom-fields"); + const hideFieldset = function(set) { + $.each(set, function() { + $(this).parents(".cmb-row").hide(); + }); + }; + const showFieldset = function(set) { + $.each(set, function() { + $(this).parents(".cmb-row").show(); + }); + }; + const copyToClipboard = function(element) { + let code = $(element).find("code")[0]; + let text = code.innerText; + navigator.clipboard.writeText(text).then(function() { + let button = $(element).find(".button"); + let buttonText = button.text(); + button.text("✓"); + button.disabled = true; + setTimeout(function() { + button.text(buttonText); + button.disabled = false; + }, 2e3); + }); + }; + const copyToClipboardButton = $("#shortcode-field").find(".button"); + copyToClipboardButton.on("click", function() { + copyToClipboard($("#shortcode-field")); + }); + function handleCustomFileInput(fileSelectorID, fileInputFields) { + const markerFileSelect = document.querySelector(fileSelectorID); + const handleSelectCustomMarker = function() { + showFieldset(fileInputFields); + if (markerFileSelect.value === "") { + hideFieldset(fileInputFields); + } + }; + handleSelectCustomMarker(); + const observerConfig = { + attributes: true, + childList: false, + subtree: false + }; + const observer = new MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + if (mutation.attributeName === "value") { + handleSelectCustomMarker(); + } + }); + }); + observer.observe(markerFileSelect, observerConfig); + } + if (mapSettingsForm.length) { + handleCustomFileInput("#custom_marker_media", [ $("#marker_icon_width"), $("#marker_icon_height"), $("#marker_icon_anchor_x"), $("#marker_icon_anchor_y") ]); + handleCustomFileInput("#custom_marker_cluster_media", [ $("#marker_cluster_icon_width"), $("#marker_cluster_icon_height") ]); + handleCustomFileInput("#marker_item_draft_media", [ $("#marker_item_draft_icon_width"), $("#marker_item_draft_icon_height"), $("#marker_item_draft_icon_anchor_x"), $("#marker_item_draft_icon_anchor_y") ]); + } + }); +})(jQuery); + (function($) { "use strict"; $(function() { diff --git a/assets/admin/js/admin.min.js b/assets/admin/js/admin.min.js index 3537622d4..bff27d64a 100644 --- a/assets/admin/js/admin.min.js +++ b/assets/admin/js/admin.min.js @@ -1 +1 @@ -!function(d){"use strict";d(function(){let n=d("#full-day"),t=d("#repetition-start_time"),o=d("#repetition-end_time"),i=!1,a=(n.on("change",function(e){n.is(":checked")?(t.val("00:00"),o.val("23:59"),t.hide(),o.hide()):(t.show(),o.show())}),n.trigger("change"),d("#item-id")),r=d("#location-id"),c=d("#repetition-start_date"),s=d("#_cb_bookingcode");a.on("change",function(e){var t={itemID:a.val()};d.post(cb_ajax_get_bookable_location.ajax_url,{_ajax_nonce:cb_ajax_get_bookable_location.nonce,action:"cb_get_bookable_location",data:t},function(e){e.success&&(r.val(e.locationID),n.prop("checked",e.fullDay),n.trigger("change"))}).then(()=>{l()})}),a.trigger("change");const l=()=>{var e;n.is(":checked")&&(e={itemID:a.val(),locationID:r.val(),startDate:c.val()},d.post(cb_ajax_get_booking_code.ajax_url,{_ajax_nonce:cb_ajax_get_booking_code.nonce,action:"cb_get_booking_code",data:e},function(e){e.success?(s.val(e.bookingCode),i=!1):i||s.val("")}))};s.on("keyup",function(e){i=!0}),c.on("change",function(e){l()}),n.on("change",function(e){l()})})}(jQuery),function(R){"use strict";R(function(){function E(){var t=R("#"+T+"_repeat");t.on("cmb2_add_row cmb2_remove_row cmb2_shift_rows_complete",function(){E()});for(let e=0;e{if(t.name==b){if(a.text(t.description),i.width(300),r.show(),c.show(),s.show(),a.show(),t.hasOwnProperty("params")&&0",{value:e,text:n[e]}));_.width(150);var o=cb_applied_booking_rules.filter(e=>e.name==t.name);1===o.length&&_.val(o[0].appliedSelectParam)}else m.hide()}})}}function i(){var t=R("#"+T+"_repeat");t.on("cmb2_add_row cmb2_remove_row cmb2_shift_rows_complete",function(){i()});for(let e=0;e{p.post(cb_ajax_export_timeframes.ajax_url,{_ajax_nonce:cb_ajax_export_timeframes.nonce,action:"cb_export_timeframes",data:e},function(e){var t,n,o;e.success?(d.show(),h.text(e.message),s.hide(),t=new Blob([e.csv]),n=e.filename,(o=document.createElement("a")).href=URL.createObjectURL(t),o.download=n,o.click()):e.error?(u.show(),f.text(e.message),s.hide()):(l.text(e.progress),i(e))})};i(e)})})}(jQuery),function(a){"use strict";a(function(){var e=a("#holiday_load_btn");const o=a("#timeframe_manual_date");var t=a("#cmb2_multiselect_datepicker"),i=e=>{var t=e.getDate(),n=e.getMonth()+1,t=t<=9?"0"+t:t,n=n<=9?"0"+n:n,e=e.getFullYear()+"-"+n+"-"+t;0{e=new Date(e.date);i(e)})})})}(jQuery),function(l){"use strict";l(function(){function e(e){l.each(e,function(){l(this).parents(".cmb-row").hide()})}function t(e){l.each(e,function(){l(this).parents(".cmb-row").show()})}function n(){(c.prop("checked")?t:e)(s)}function o(){r.prop("checked")?(t(c),n()):(e(c),e(s))}function i(){a.prop("checked")?(e(r),e(c),e(s)):(t(r),t(c),n())}const a=l("#_cb_use_global_settings"),r=l("#_cb_allow_lockdays_in_range"),c=l("#_cb_count_lockdays_in_range"),s=l("#_cb_count_lockdays_maximum");n(),c.change(function(){n()}),o(),r.change(function(){o()});i(),a.change(function(){i()})})}(jQuery),function(n){"use strict";n(function(){n("#orphans-migration-start").on("click",function(e){e.preventDefault(),n("#orphans-migration-in-progress").show();e=n(".post-checkboxes:checkbox:checked");let t=[];e.each(function(){t.push(n(this).val())});e=t;n.post(cb_ajax_orphaned_booking_migration.ajax_url,{_ajax_nonce:cb_ajax_orphaned_booking_migration.nonce,action:"cb_orphaned_booking_migration",data:e}).done(function(e){e.success?(n("#orphans-migration-in-progress").hide(),n("#orphans-migration-done").show(),n("#orphans-migration-done span").text(e.message),t.forEach(function(e){n("#row-booking-"+e).remove()})):(n("#orphans-migration-in-progress").hide(),n("#orphans-migration-failed").show(),n("#orphans-migration-failed span").text(e.message))})})})}(jQuery),function(o){"use strict";o(function(){0==o("#upgrade-fields").length&&o(".cmb2-id-upgrade-header").hide(),o("#cmb2-metabox-migration #run-upgrade").on("click",function(e){e.preventDefault(),o("#upgrade-in-progress").show(),o("#run-upgrade").hide();const t=e=>{o.post(cb_ajax_run_upgrade.ajax_url,{_ajax_nonce:cb_ajax_run_upgrade.nonce,action:"cb_run_upgrade",data:e},function(e){e.success?(o("#upgrade-in-progress").hide(),o("#upgrade-done").show()):t(e)})};t({progress:{task:0,page:1}})}),o("#cmb2-metabox-migration #migration-start").on("click",function(e){e.preventDefault(),o("#migration-state").show(),o("#migration-in-progress").show();const t=e=>{o.post(cb_ajax_start_migration.ajax_url,{_ajax_nonce:cb_ajax_start_migration.nonce,action:"cb_start_migration",data:e,geodata:o("#get-geo-locations").is(":checked")},function(e){let n=!0;o.each(e,function(e,t){o("#"+e+"-index").text(t.index),o("#"+e+"-count").text(t.count),"0"==t.complete&&(n=!1)}),n?(o("#migration-in-progress").hide(),o("#migration-done").show()):t(e)})};t(!1)}),o("#cmb2-metabox-migration #booking-update-start").on("click",function(e){e.preventDefault(),o("#booking-migration-in-progress").show(),o.post(cb_ajax_start_migration.ajax_url,{_ajax_nonce:cb_ajax_start_migration.nonce,action:"cb_start_booking_migration"}).done(function(){o("#booking-migration-in-progress").hide(),o("#booking-migration-done").show()}).fail(function(){o("#booking-migration-in-progress").hide(),o("#booking-migration-failed").show()})})})}(jQuery),function(t){"use strict";t(function(){const e=t("input[name=post_type][value=cb_restriction]").parent("form").find("#cb_restriction-custom-fields");e.find("input, select, textarea").on("keyup change paste",function(){e.find("input[name=restriction-send]").prop("disabled",!0)})})}(jQuery),function(o){"use strict";o(function(){if(o("#templates").length){const t=o("#emailtemplates_mail-booking_ics_attach");const n=[o("#emailtemplates_mail-booking_ics_event-title"),o("#emailtemplates_mail-booking_ics_event-description")],e=function(){var e;e=n,o.each(e,function(){o(this).parents(".cmb-row").show()}),t.prop("checked")||(e=n,o.each(e,function(){o(this).parents(".cmb-row").hide()}),t.prop("checked",!1))};e(),t.click(function(){e()})}})}(jQuery),function(X){"use strict";X(function(){const M=function(t,e){var n=[];return jQuery.grep(e,function(e){-1==jQuery.inArray(e,t)&&n.push(e)}),n},i=function(e){X.each(e,function(){X(this).parents(".cmb-row").hide()})},a=function(e){X.each(e,function(){X(this).parents(".cmb-row").show()})};var e=X("#cmb2-metabox-cb_timeframe-custom-fields");const n=X("#timeframe-repetition"),o=X("#location-select"),r=X("#item-select");if(e.length){const n=X("#timeframe-repetition"),s=X("#type"),l=X("#grid"),d=X("#weekdays1");var e=X("#start-time"),t=X("#end-time"),c=X("#title-timeframe-rep-config");const u=X("#repetition-start"),f=X("#repetition-end"),h=X("#full-day"),p=X("#title-timeframe-booking-codes"),m=X("#show-booking-codes"),g=X("#create-booking-codes");var F=X("#booking-codes-download"),B=X("#booking-codes-list"),O=X("#email-booking-codes-list"),U=X("#cron-email-booking-code");const _=X("#timeframe-bookingcodes-sendall"),Y=X("#email-booking-codes-list-all"),$=X("#email-booking-codes-list-current"),J=X("#email-booking-codes-list-next"),b=X(".cmb2-id-location-id"),E=X(".cmb2-id-location-id-list"),T=X(".cmb2-id-item-id"),A=X(".cmb2-id-item-id-list"),v=X(".cmb2-id-location-category-ids"),w=X(".cmb2-id-item-category-ids"),R=X(".cmb2-id--cmb2-holiday");X("#timeframe_manual_date");const x=X("#cmb2_multiselect_datepicker"),I=X(".cmb2-id-timeframe-manual-date");var C=X("#timeframe-max-days"),W=X("#timeframe-advance-booking-days"),P=X("#booking-startday-offset"),Q=X("#title-bookings-config"),K=X("#allowed_user_roles");const k=[c,h,e,t,d,u,f,l],S=[h,e,t,l,u,f],q=[l,e,t],G=[g,B,F,m,O,U],N=[m,B,F,O,U];c=X("input[name=post_type][value=cb_timeframe]").parent("form");const H=[C,W,P,K,Q],y=()=>{var e,t;"3"==s.val()&&((t=T.find("option:selected")).prop("value")&&((e=A.find(`input[value=${t.prop("value")}]`))&&e.prop("checked",!0),t.prop("selected",!1)),(e=b.find("option:selected")).prop("value"))&&((t=E.find(`input[value=${e.prop("value")}]`))&&t.prop("checked",!0),e.prop("selected",!1))},V=(y(),function(){var e=X("option:selected",s).val(),t=X("option:selected",n).val();"2"===e?(a(H),a(p),R.hide()):(i(H),i(p),"3"==e&&"manual"==t?R.show():R.hide()),"3"==e?(r.show(),o.show(),y()):(r.hide(),o.hide())}),L=(V(),s.change(function(){V(),D(),L()}),function(){var e;"3"==X("option:selected",s).val()?(b.hide(),0==(e=X("option:selected",o).val())?(E.show(),v.hide()):1==e?(v.show(),E.hide()):2==e&&(E.hide(),v.hide())):(b.show(),E.hide(),v.hide())}),D=(L(),o.change(function(){L()}),function(){var e;"3"==X("option:selected",s).val()?(T.hide(),0==(e=X("option:selected",r).val())?(A.show(),w.hide()):1==e?(w.show(),A.hide()):2==e&&(A.hide(),w.hide())):(T.show(),A.hide(),w.hide())}),j=(D(),r.change(function(){D()}),function(){X("option:selected",n).val();(h.prop("checked")?(l.prop("selected",!1),i):a)(q)}),Z=(j(),h.change(function(){j()}),function(){var e=X("option:selected",n).val(),t=X("option:selected",s).val();e?("norep"==e?(a(S),i(M(S,k))):(a(k),i(M(k,S))),"manual"===e?(I.show(),x.show(),i(u),i(f),"3"==t?R.show():R.hide()):(I.hide(),x.hide(),a(u),a(f)),"w"===e?d.parents(".cmb-row").show():(d.parents(".cmb-row").hide(),t=X("input[name*=weekdays]"),X.each(t,function(){X(this).prop("checked",!1)})),j()):(i(S),i(k))}),z=(Z(),n.change(function(){Z()}),function(){var e=h.prop("checked"),t=s.val(),n=u.val(),o=f.val();i(G),n&&e&&"2"===t&&(a(G),g.prop("checked")?a(N):(i(N),m.prop("checked",!1)),o?_.show():_.hide())});z(),c.find("input, select, textarea").on("keyup change paste",function(){Y.addClass("disabled"),$.addClass("disabled"),J.addClass("disabled")});e=[u,f,h,s,g];X.each(e,function(e,t){t.change(function(){z()})})}})}(jQuery),function(e){"use strict";e(function(){e(document).tooltip()})}(jQuery),function(e,t){var n,o;"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):(e="undefined"!=typeof globalThis?globalThis:e||self,n=e.feiertagejs,o=e.feiertagejs={},t(o),o.noConflict=function(){return e.feiertagejs=n,o})}(this,function(e){"use strict";const a=["NEUJAHRSTAG","HEILIGEDREIKOENIGE","KARFREITAG","OSTERSONNTAG","OSTERMONTAG","TAG_DER_ARBEIT","CHRISTIHIMMELFAHRT","MARIAHIMMELFAHRT","PFINGSTSONNTAG","PFINGSTMONTAG","FRONLEICHNAM","DEUTSCHEEINHEIT","REFORMATIONSTAG","ALLERHEILIGEN","BUBETAG","ERSTERWEIHNACHTSFEIERTAG","ZWEITERWEIHNACHTSFEIERTAG","WELTKINDERTAG","WELTFRAUENTAG","AUGSBURGER_FRIEDENSFEST"],t=["BW","BY","BE","BB","HB","HE","HH","MV","NI","NW","RP","SL","SN","ST","SH","TH","BUND","AUGSBURG","ALL"];let n="de";const r={de:{NEUJAHRSTAG:"Neujahrstag",HEILIGEDREIKOENIGE:"Heilige Drei Könige",KARFREITAG:"Karfreitag",OSTERSONNTAG:"Ostersonntag",OSTERMONTAG:"Ostermontag",TAG_DER_ARBEIT:"Tag der Arbeit",CHRISTIHIMMELFAHRT:"Christi Himmelfahrt",PFINGSTSONNTAG:"Pfingstsonntag",PFINGSTMONTAG:"Pfingstmontag",FRONLEICHNAM:"Fronleichnam",MARIAHIMMELFAHRT:"Mariä Himmelfahrt",DEUTSCHEEINHEIT:"Tag der Deutschen Einheit",REFORMATIONSTAG:"Reformationstag",ALLERHEILIGEN:"Allerheiligen",BUBETAG:"Buß- und Bettag",ERSTERWEIHNACHTSFEIERTAG:"1. Weihnachtstag",ZWEITERWEIHNACHTSFEIERTAG:"2. Weihnachtstag",WELTKINDERTAG:"Weltkindertag",WELTFRAUENTAG:"Weltfrauentag",AUGSBURGER_FRIEDENSFEST:"Augsburger Friedensfest"}};function o(e,t){i(t);var n=e.getFullYear(),e=f(e);return-1!==function(e,t){e=c(e,t);return e.map(e=>f(e.date))}(n,t).indexOf(e)}function i(e){if(null==e)throw new Error("Region must not be undefined or null");if(-1===t.indexOf(e))throw new Error(`Invalid region: ${e}! Must be one of `+t.toString())}function c(e,t){var n=function(e){var t=Math.floor(e/100),n=e-19*Math.floor(e/19),o=Math.floor((t-17)/25);o=t-Math.floor(t/4)-Math.floor((t-o)/3)+19*n+15,o=(o-=30*Math.floor(o/30))-Math.floor(o/28)*(1-Math.floor(o/28)*Math.floor(29/(1+o))*Math.floor((21-n)/11)),n=e+Math.floor(e/4)+o+2-t+Math.floor(t/4);n-=7*Math.floor(n/7);t=o-n,o=3+Math.floor((40+t)/44),n=28+t-31*Math.floor(o/4);return new Date(e,o-1,n)}(e),o=l(new Date(n.getTime()),-2),i=l(new Date(n.getTime()),1),a=l(new Date(n.getTime()),39),r=l(new Date(n.getTime()),49),c=l(new Date(n.getTime()),50),s=[...[u("NEUJAHRSTAG",d(s=e,1,1)),u("TAG_DER_ARBEIT",d(s,5,1)),u("DEUTSCHEEINHEIT",d(s,10,3)),u("ERSTERWEIHNACHTSFEIERTAG",d(s,12,25)),u("ZWEITERWEIHNACHTSFEIERTAG",d(s,12,26))],u("KARFREITAG",o),u("OSTERMONTAG",i),u("CHRISTIHIMMELFAHRT",a),u("PFINGSTMONTAG",c)];return o=e,i=s,"BW"!==(a=t)&&"BY"!==a&&"AUGSBURG"!==a&&"ST"!==a&&"ALL"!==a||i.push(u("HEILIGEDREIKOENIGE",d(o,1,6))),c=n,a=r,i=s,"BB"!==(o=t)&&"ALL"!==o||i.push(u("OSTERSONNTAG",c),u("PFINGSTSONNTAG",a)),r=n,o=s,"BW"!==(i=t)&&"BY"!==i&&"AUGSBURG"!==i&&"HE"!==i&&"NW"!==i&&"RP"!==i&&"SL"!==i&&"ALL"!==i||(i=l(new Date(r.getTime()),60),o.push(u("FRONLEICHNAM",i))),c=e,a=s,"SL"!==(n=t)&&"BY"!==n&&"AUGSBURG"!==n&&"ALL"!==n||a.push(u("MARIAHIMMELFAHRT",d(c,8,15))),r=t,o=s,2017!==(i=e)&&"NI"!==r&&"BB"!==r&&"HB"!==r&&"HH"!==r&&"MV"!==r&&"SN"!==r&&"ST"!==r&&"TH"!==r&&"SH"!==r&&"ALL"!==r||o.push(u("REFORMATIONSTAG",d(i,10,31))),n=e,a=s,"BW"!==(c=t)&&"BY"!==c&&"AUGSBURG"!==c&&"NW"!==c&&"RP"!==c&&"SL"!==c&&"ALL"!==c||a.push(u("ALLERHEILIGEN",d(n,11,1))),r=e,o=s,"SN"!==(i=t)&&"ALL"!==i||(i=function(e){e=new Date(e,11,25,12,0,0);let t=e.getDay()%7;0===t&&(t=7);var n=t+32;e=new Date(e.getTime());return l(e,-n)}(r),o.push(u("BUBETAG",d(i.getUTCFullYear(),i.getUTCMonth()+1,i.getUTCDate())))),c=t,a=s,2019<=(n=e)&&("TH"===c||"ALL"===c)&&a.push(u("WELTKINDERTAG",d(n,9,20))),r=t,o=s,(i=e)<=2018||("BE"!==r&&"ALL"!==r||o.push(u("WELTFRAUENTAG",d(i,3,8))),"MV"===r&&2023<=i&&o.push(u("WELTFRAUENTAG",d(i,3,8)))),c=e,a=s,"AUGSBURG"===t&&a.push(u("AUGSBURGER_FRIEDENSFEST",d(c,8,8))),s.sort((e,t)=>e.date.getTime()-t.date.getTime())}function l(e,t){var n=new Date(e);return n.setDate(e.getDate()+t),n}function d(e,t,n){return new Date(e,t-1,n)}function u(e,t){return{name:e,date:t,dateString:s(t),trans(e=n){return console.warn('FeiertageJs: You are using "Holiday.trans() method. This will be replaced in the next major version with translate()"'),this.translate(e)},translate(e=n){return null==e?void 0:r[e][this.name]},getNormalizedDate(){return f(this.date)},equals(e){e=s(e);return this.dateString===e}}}function s(e){e=new Date(e.getTime()-60*e.getTimezoneOffset()*1e3);return e.setUTCHours(0,0,0,0),e.toISOString().slice(0,10)}function f(e){e=new Date(e);return e.setHours(0,0,0,0),e.getTime()}e.addTranslation=function(e,t){var e=e.toLowerCase(),n=r.de;let o=!1;for(const i of a)t[i]||(o=!0,t[i]=n[i]);o&&console.warn("[feiertagejs] addTranslation: you did not add all holidays in your translation! Took German as fallback"),r[e]=t},e.getHolidayByDate=function(t,e="ALL"){return i(e),c(t.getFullYear(),e).find(e=>e.equals(t))},e.getHolidays=function(e,t){let n;return n="string"==typeof e?parseInt(e,10):e,i(t),c(n,t)},e.getLanguage=function(){return n},e.isHoliday=o,e.isSpecificHoliday=function(t,e,n="ALL"){i(n);var o=e;if(null==o)throw new TypeError("holidayName must not be null or undefined");if(-1===a.indexOf(o))throw new Error(`feiertage.js: invalid holiday type "${o}"! Must be one of `+a.toString());return!!(o=c(t.getFullYear(),n).find(e=>e.equals(t)))&&o.name===e},e.isSunOrHoliday=function(e,t){return i(t),0===e.getDay()||o(e,t)},e.setLanguage=function(e){var t=e.toLowerCase();if(!r[t])throw new TypeError(`[feiertagejs] tried to set language to ${t} but the translation is missing. Please use addTranslation(isoCode,object) first`);n=e}}); \ No newline at end of file +!function(d){"use strict";d(function(){let n=d("#full-day"),t=d("#repetition-start_time"),o=d("#repetition-end_time"),i=!1,a=d("#item-id"),r=d("#location-id"),c=d("#repetition-start_date"),s=d("#_cb_bookingcode");if(![n,t,o,a,r,c,s].every(e=>1===e.length))return;n.on("change",function(e){n.is(":checked")?(t.val("00:00"),o.val("23:59"),t.hide(),o.hide()):(t.show(),o.show())}),n.trigger("change"),a.on("change",function(e){var t={itemID:a.val()};d.post(cb_ajax_get_bookable_location.ajax_url,{_ajax_nonce:cb_ajax_get_bookable_location.nonce,action:"cb_get_bookable_location",data:t},function(e){e.success&&(r.val(e.locationID),n.prop("checked",e.fullDay),n.trigger("change"))}).then(()=>{l()})}),a.trigger("change");const l=()=>{var e;n.is(":checked")&&(e={itemID:a.val(),locationID:r.val(),startDate:c.val()},d.post(cb_ajax_get_booking_code.ajax_url,{_ajax_nonce:cb_ajax_get_booking_code.nonce,action:"cb_get_booking_code",data:e},function(e){e.success?(s.val(e.bookingCode),i=!1):i||s.val("")}))};s.on("keyup",function(e){i=!0}),c.on("change",function(e){l()}),n.on("change",function(e){l()})})}(jQuery),function(k){"use strict";k(function(){function E(){var t=k("#"+T+"_repeat");t.on("cmb2_add_row cmb2_remove_row cmb2_shift_rows_complete",function(){E()});for(let e=0;e{if(t.name==b){if(a.text(t.description),i.width(300),r.show(),c.show(),s.show(),a.show(),t.hasOwnProperty("params")&&0",{value:e,text:n[e]}));_.width(150);var o=cb_applied_booking_rules.filter(e=>e.name==t.name);1===o.length&&_.val(o[0].appliedSelectParam)}else p.hide()}})}}function i(){var t=k("#"+T+"_repeat");t.on("cmb2_add_row cmb2_remove_row cmb2_shift_rows_complete",function(){i()});for(let e=0;e{m.post(cb_ajax_export_timeframes.ajax_url,{_ajax_nonce:cb_ajax_export_timeframes.nonce,action:"cb_export_timeframes",data:e},function(e){var t,n,o;e.success?(d.show(),h.text(e.message),s.hide(),t=new Blob([e.csv]),n=e.filename,(o=document.createElement("a")).href=URL.createObjectURL(t),o.download=n,o.click()):e.error?(u.show(),f.text(e.message),s.hide()):(l.text(e.progress),i(e))})};i(e)})})}(jQuery),function(a){"use strict";a(function(){var e=a("#holiday_load_btn");const o=a("#timeframe_manual_date");var t=a("#cmb2_multiselect_datepicker"),i=e=>{var t=e.getDate(),n=e.getMonth()+1,t=t<=9?"0"+t:t,n=n<=9?"0"+n:n,e=e.getFullYear()+"-"+n+"-"+t;0{e=new Date(e.date);i(e)})})})}(jQuery),function(l){"use strict";l(function(){function e(e){l.each(e,function(){l(this).parents(".cmb-row").hide()})}function t(e){l.each(e,function(){l(this).parents(".cmb-row").show()})}function n(){(c.prop("checked")?t:e)(s)}function o(){r.prop("checked")?(t(c),n()):(e(c),e(s))}function i(){a.prop("checked")?(e(r),e(c),e(s)):(t(r),t(c),n())}const a=l("#_cb_use_global_settings"),r=l("#_cb_allow_lockdays_in_range"),c=l("#_cb_count_lockdays_in_range"),s=l("#_cb_count_lockdays_maximum");n(),c.change(function(){n()}),o(),r.change(function(){o()});i(),a.change(function(){i()})})}(jQuery),function(i){"use strict";i(function(){var e=i("#cmb2-metabox-cb_map-custom-fields");function t(e,t){function n(){i.each(t,function(){i(this).parents(".cmb-row").show()}),""===o.value&&i.each(t,function(){i(this).parents(".cmb-row").hide()})}const o=document.querySelector(e);n();new MutationObserver(function(e){e.forEach(function(e){"value"===e.attributeName&&n()})}).observe(o,{attributes:!0,childList:!1,subtree:!1})}i("#shortcode-field").find(".button").on("click",function(){var n,e;n=i("#shortcode-field"),e=i(n).find("code")[0].innerText,navigator.clipboard.writeText(e).then(function(){let e=i(n).find(".button"),t=e.text();e.text("✓"),e.disabled=!0,setTimeout(function(){e.text(t),e.disabled=!1},2e3)})}),e.length&&(t("#custom_marker_media",[i("#marker_icon_width"),i("#marker_icon_height"),i("#marker_icon_anchor_x"),i("#marker_icon_anchor_y")]),t("#custom_marker_cluster_media",[i("#marker_cluster_icon_width"),i("#marker_cluster_icon_height")]),t("#marker_item_draft_media",[i("#marker_item_draft_icon_width"),i("#marker_item_draft_icon_height"),i("#marker_item_draft_icon_anchor_x"),i("#marker_item_draft_icon_anchor_y")]))})}(jQuery),function(n){"use strict";n(function(){n("#orphans-migration-start").on("click",function(e){e.preventDefault(),n("#orphans-migration-in-progress").show();e=n(".post-checkboxes:checkbox:checked");let t=[];e.each(function(){t.push(n(this).val())});e=t;n.post(cb_ajax_orphaned_booking_migration.ajax_url,{_ajax_nonce:cb_ajax_orphaned_booking_migration.nonce,action:"cb_orphaned_booking_migration",data:e}).done(function(e){e.success?(n("#orphans-migration-in-progress").hide(),n("#orphans-migration-done").show(),n("#orphans-migration-done span").text(e.message),t.forEach(function(e){n("#row-booking-"+e).remove()})):(n("#orphans-migration-in-progress").hide(),n("#orphans-migration-failed").show(),n("#orphans-migration-failed span").text(e.message))})})})}(jQuery),function(o){"use strict";o(function(){0==o("#upgrade-fields").length&&o(".cmb2-id-upgrade-header").hide(),o("#cmb2-metabox-migration #run-upgrade").on("click",function(e){e.preventDefault(),o("#upgrade-in-progress").show(),o("#run-upgrade").hide();const t=e=>{o.post(cb_ajax_run_upgrade.ajax_url,{_ajax_nonce:cb_ajax_run_upgrade.nonce,action:"cb_run_upgrade",data:e},function(e){e.success?(o("#upgrade-in-progress").hide(),o("#upgrade-done").show()):t(e)})};t({progress:{task:0,page:1}})}),o("#cmb2-metabox-migration #migration-start").on("click",function(e){e.preventDefault(),o("#migration-state").show(),o("#migration-in-progress").show();const t=e=>{o.post(cb_ajax_start_migration.ajax_url,{_ajax_nonce:cb_ajax_start_migration.nonce,action:"cb_start_migration",data:e,geodata:o("#get-geo-locations").is(":checked")},function(e){let n=!0;o.each(e,function(e,t){o("#"+e+"-index").text(t.index),o("#"+e+"-count").text(t.count),"0"==t.complete&&(n=!1)}),n?(o("#migration-in-progress").hide(),o("#migration-done").show()):t(e)})};t(!1)}),o("#cmb2-metabox-migration #booking-update-start").on("click",function(e){e.preventDefault(),o("#booking-migration-in-progress").show(),o.post(cb_ajax_start_migration.ajax_url,{_ajax_nonce:cb_ajax_start_migration.nonce,action:"cb_start_booking_migration"}).done(function(){o("#booking-migration-in-progress").hide(),o("#booking-migration-done").show()}).fail(function(){o("#booking-migration-in-progress").hide(),o("#booking-migration-failed").show()})})})}(jQuery),function(t){"use strict";t(function(){const e=t("input[name=post_type][value=cb_restriction]").parent("form").find("#cb_restriction-custom-fields");e.find("input, select, textarea").on("keyup change paste",function(){e.find("input[name=restriction-send]").prop("disabled",!0)})})}(jQuery),function(o){"use strict";o(function(){if(o("#templates").length){const t=o("#emailtemplates_mail-booking_ics_attach");const n=[o("#emailtemplates_mail-booking_ics_event-title"),o("#emailtemplates_mail-booking_ics_event-description")],e=function(){var e;e=n,o.each(e,function(){o(this).parents(".cmb-row").show()}),t.prop("checked")||(e=n,o.each(e,function(){o(this).parents(".cmb-row").hide()}),t.prop("checked",!1))};e(),t.click(function(){e()})}})}(jQuery),function(X){"use strict";X(function(){const M=function(t,e){var n=[];return jQuery.grep(e,function(e){-1==jQuery.inArray(e,t)&&n.push(e)}),n},i=function(e){X.each(e,function(){X(this).parents(".cmb-row").hide()})},a=function(e){X.each(e,function(){X(this).parents(".cmb-row").show()})};var e=X("#cmb2-metabox-cb_timeframe-custom-fields");const n=X("#timeframe-repetition"),o=X("#location-select"),r=X("#item-select");if(e.length){const n=X("#timeframe-repetition"),s=X("#type"),l=X("#grid"),d=X("#weekdays1");var e=X("#start-time"),t=X("#end-time"),c=X("#title-timeframe-rep-config");const u=X("#repetition-start"),f=X("#repetition-end"),h=X("#full-day"),m=X("#title-timeframe-booking-codes"),p=X("#show-booking-codes"),g=X("#create-booking-codes");var F=X("#booking-codes-download"),B=X("#booking-codes-list"),O=X("#email-booking-codes-list"),U=X("#cron-email-booking-code");const _=X("#timeframe-bookingcodes-sendall"),Y=X("#email-booking-codes-list-all"),$=X("#email-booking-codes-list-current"),q=X("#email-booking-codes-list-next"),b=X(".cmb2-id-location-id"),E=X(".cmb2-id-location-id-list"),T=X(".cmb2-id-item-id"),v=X(".cmb2-id-item-id-list"),w=X(".cmb2-id-location-category-ids"),A=X(".cmb2-id-item-category-ids"),k=X(".cmb2-id--cmb2-holiday");X("#timeframe_manual_date");const x=X("#cmb2_multiselect_datepicker"),R=X(".cmb2-id-timeframe-manual-date");var C=X("#timeframe-max-days"),W=X("#timeframe-advance-booking-days"),P=X("#booking-startday-offset"),Q=X("#title-bookings-config"),K=X("#allowed_user_roles");const I=[c,h,e,t,d,u,f,l],S=[h,e,t,l,u,f],J=[l,e,t],y=[g,B,F,p,O,U],G=[p,B,F,O,U];c=X("input[name=post_type][value=cb_timeframe]").parent("form");const N=[C,W,P,K,Q],H=()=>{var e,t;"3"==s.val()&&((t=T.find("option:selected")).prop("value")&&((e=v.find(`input[value=${t.prop("value")}]`))&&e.prop("checked",!0),t.prop("selected",!1)),(e=b.find("option:selected")).prop("value"))&&((t=E.find(`input[value=${e.prop("value")}]`))&&t.prop("checked",!0),e.prop("selected",!1))},V=(H(),function(){var e=X("option:selected",s).val(),t=X("option:selected",n).val();"2"===e?(a(N),a(m),k.hide()):(i(N),i(m),"3"==e&&"manual"==t?k.show():k.hide()),"3"==e?(r.show(),o.show(),H()):(r.hide(),o.hide())}),L=(V(),s.change(function(){V(),j(),L()}),function(){var e;"3"==X("option:selected",s).val()?(b.hide(),0==(e=X("option:selected",o).val())?(E.show(),w.hide()):1==e?(w.show(),E.hide()):2==e&&(E.hide(),w.hide())):(b.show(),E.hide(),w.hide())}),j=(L(),o.change(function(){L()}),function(){var e;"3"==X("option:selected",s).val()?(T.hide(),0==(e=X("option:selected",r).val())?(v.show(),A.hide()):1==e?(A.show(),v.hide()):2==e&&(v.hide(),A.hide())):(T.show(),v.hide(),A.hide())}),D=(j(),r.change(function(){j()}),function(){X("option:selected",n).val();(h.prop("checked")?(l.prop("selected",!1),i):a)(J)}),Z=(D(),h.change(function(){D()}),function(){var e=X("option:selected",n).val(),t=X("option:selected",s).val();e?("norep"==e?(a(S),i(M(S,I))):(a(I),i(M(I,S))),"manual"===e?(R.show(),x.show(),i(u),i(f),"3"==t?k.show():k.hide()):(R.hide(),x.hide(),a(u),a(f)),"w"===e?d.parents(".cmb-row").show():(d.parents(".cmb-row").hide(),t=X("input[name*=weekdays]"),X.each(t,function(){X(this).prop("checked",!1)})),D()):(i(S),i(I))}),z=(Z(),n.change(function(){Z()}),function(){var e=h.prop("checked"),t=s.val(),n=u.val(),o=f.val();i(y),n&&e&&"2"===t&&(a(y),g.prop("checked")?a(G):(i(G),p.prop("checked",!1)),o?_.show():_.hide())});z(),c.find("input, select, textarea").on("keyup change paste",function(){Y.addClass("disabled"),$.addClass("disabled"),q.addClass("disabled")});e=[u,f,h,s,g];X.each(e,function(e,t){t.change(function(){z()})})}})}(jQuery),function(e){"use strict";e(function(){e(document).tooltip()})}(jQuery),function(e,t){var n,o;"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):(e="undefined"!=typeof globalThis?globalThis:e||self,n=e.feiertagejs,o=e.feiertagejs={},t(o),o.noConflict=function(){return e.feiertagejs=n,o})}(this,function(e){"use strict";const a=["NEUJAHRSTAG","HEILIGEDREIKOENIGE","KARFREITAG","OSTERSONNTAG","OSTERMONTAG","TAG_DER_ARBEIT","CHRISTIHIMMELFAHRT","MARIAHIMMELFAHRT","PFINGSTSONNTAG","PFINGSTMONTAG","FRONLEICHNAM","DEUTSCHEEINHEIT","REFORMATIONSTAG","ALLERHEILIGEN","BUBETAG","ERSTERWEIHNACHTSFEIERTAG","ZWEITERWEIHNACHTSFEIERTAG","WELTKINDERTAG","WELTFRAUENTAG","AUGSBURGER_FRIEDENSFEST"],t=["BW","BY","BE","BB","HB","HE","HH","MV","NI","NW","RP","SL","SN","ST","SH","TH","BUND","AUGSBURG","ALL"];let n="de";const r={de:{NEUJAHRSTAG:"Neujahrstag",HEILIGEDREIKOENIGE:"Heilige Drei Könige",KARFREITAG:"Karfreitag",OSTERSONNTAG:"Ostersonntag",OSTERMONTAG:"Ostermontag",TAG_DER_ARBEIT:"Tag der Arbeit",CHRISTIHIMMELFAHRT:"Christi Himmelfahrt",PFINGSTSONNTAG:"Pfingstsonntag",PFINGSTMONTAG:"Pfingstmontag",FRONLEICHNAM:"Fronleichnam",MARIAHIMMELFAHRT:"Mariä Himmelfahrt",DEUTSCHEEINHEIT:"Tag der Deutschen Einheit",REFORMATIONSTAG:"Reformationstag",ALLERHEILIGEN:"Allerheiligen",BUBETAG:"Buß- und Bettag",ERSTERWEIHNACHTSFEIERTAG:"1. Weihnachtstag",ZWEITERWEIHNACHTSFEIERTAG:"2. Weihnachtstag",WELTKINDERTAG:"Weltkindertag",WELTFRAUENTAG:"Weltfrauentag",AUGSBURGER_FRIEDENSFEST:"Augsburger Friedensfest"}};function o(e,t){i(t);var n=e.getFullYear(),e=f(e);return-1!==function(e,t){e=c(e,t);return e.map(e=>f(e.date))}(n,t).indexOf(e)}function i(e){if(null==e)throw new Error("Region must not be undefined or null");if(-1===t.indexOf(e))throw new Error(`Invalid region: ${e}! Must be one of `+t.toString())}function c(e,t){var n=function(e){var t=Math.floor(e/100),n=e-19*Math.floor(e/19),o=Math.floor((t-17)/25);o=t-Math.floor(t/4)-Math.floor((t-o)/3)+19*n+15,o=(o-=30*Math.floor(o/30))-Math.floor(o/28)*(1-Math.floor(o/28)*Math.floor(29/(1+o))*Math.floor((21-n)/11)),n=e+Math.floor(e/4)+o+2-t+Math.floor(t/4);n-=7*Math.floor(n/7);t=o-n,o=3+Math.floor((40+t)/44),n=28+t-31*Math.floor(o/4);return new Date(e,o-1,n)}(e),o=l(new Date(n.getTime()),-2),i=l(new Date(n.getTime()),1),a=l(new Date(n.getTime()),39),r=l(new Date(n.getTime()),49),c=l(new Date(n.getTime()),50),s=[...[u("NEUJAHRSTAG",d(s=e,1,1)),u("TAG_DER_ARBEIT",d(s,5,1)),u("DEUTSCHEEINHEIT",d(s,10,3)),u("ERSTERWEIHNACHTSFEIERTAG",d(s,12,25)),u("ZWEITERWEIHNACHTSFEIERTAG",d(s,12,26))],u("KARFREITAG",o),u("OSTERMONTAG",i),u("CHRISTIHIMMELFAHRT",a),u("PFINGSTMONTAG",c)];return o=e,i=s,"BW"!==(a=t)&&"BY"!==a&&"AUGSBURG"!==a&&"ST"!==a&&"ALL"!==a||i.push(u("HEILIGEDREIKOENIGE",d(o,1,6))),c=n,a=r,i=s,"BB"!==(o=t)&&"ALL"!==o||i.push(u("OSTERSONNTAG",c),u("PFINGSTSONNTAG",a)),r=n,o=s,"BW"!==(i=t)&&"BY"!==i&&"AUGSBURG"!==i&&"HE"!==i&&"NW"!==i&&"RP"!==i&&"SL"!==i&&"ALL"!==i||(i=l(new Date(r.getTime()),60),o.push(u("FRONLEICHNAM",i))),c=e,a=s,"SL"!==(n=t)&&"BY"!==n&&"AUGSBURG"!==n&&"ALL"!==n||a.push(u("MARIAHIMMELFAHRT",d(c,8,15))),r=t,o=s,2017!==(i=e)&&"NI"!==r&&"BB"!==r&&"HB"!==r&&"HH"!==r&&"MV"!==r&&"SN"!==r&&"ST"!==r&&"TH"!==r&&"SH"!==r&&"ALL"!==r||o.push(u("REFORMATIONSTAG",d(i,10,31))),n=e,a=s,"BW"!==(c=t)&&"BY"!==c&&"AUGSBURG"!==c&&"NW"!==c&&"RP"!==c&&"SL"!==c&&"ALL"!==c||a.push(u("ALLERHEILIGEN",d(n,11,1))),r=e,o=s,"SN"!==(i=t)&&"ALL"!==i||(i=function(e){e=new Date(e,11,25,12,0,0);let t=e.getDay()%7;0===t&&(t=7);var n=t+32;e=new Date(e.getTime());return l(e,-n)}(r),o.push(u("BUBETAG",d(i.getUTCFullYear(),i.getUTCMonth()+1,i.getUTCDate())))),c=t,a=s,2019<=(n=e)&&("TH"===c||"ALL"===c)&&a.push(u("WELTKINDERTAG",d(n,9,20))),r=t,o=s,(i=e)<=2018||("BE"!==r&&"ALL"!==r||o.push(u("WELTFRAUENTAG",d(i,3,8))),"MV"===r&&2023<=i&&o.push(u("WELTFRAUENTAG",d(i,3,8)))),c=e,a=s,"AUGSBURG"===t&&a.push(u("AUGSBURGER_FRIEDENSFEST",d(c,8,8))),s.sort((e,t)=>e.date.getTime()-t.date.getTime())}function l(e,t){var n=new Date(e);return n.setDate(e.getDate()+t),n}function d(e,t,n){return new Date(e,t-1,n)}function u(e,t){return{name:e,date:t,dateString:s(t),trans(e=n){return console.warn('FeiertageJs: You are using "Holiday.trans() method. This will be replaced in the next major version with translate()"'),this.translate(e)},translate(e=n){return null==e?void 0:r[e][this.name]},getNormalizedDate(){return f(this.date)},equals(e){e=s(e);return this.dateString===e}}}function s(e){e=new Date(e.getTime()-60*e.getTimezoneOffset()*1e3);return e.setUTCHours(0,0,0,0),e.toISOString().slice(0,10)}function f(e){e=new Date(e);return e.setHours(0,0,0,0),e.getTime()}e.addTranslation=function(e,t){var e=e.toLowerCase(),n=r.de;let o=!1;for(const i of a)t[i]||(o=!0,t[i]=n[i]);o&&console.warn("[feiertagejs] addTranslation: you did not add all holidays in your translation! Took German as fallback"),r[e]=t},e.getHolidayByDate=function(t,e="ALL"){return i(e),c(t.getFullYear(),e).find(e=>e.equals(t))},e.getHolidays=function(e,t){let n;return n="string"==typeof e?parseInt(e,10):e,i(t),c(n,t)},e.getLanguage=function(){return n},e.isHoliday=o,e.isSpecificHoliday=function(t,e,n="ALL"){i(n);var o=e;if(null==o)throw new TypeError("holidayName must not be null or undefined");if(-1===a.indexOf(o))throw new Error(`feiertage.js: invalid holiday type "${o}"! Must be one of `+a.toString());return!!(o=c(t.getFullYear(),n).find(e=>e.equals(t)))&&o.name===e},e.isSunOrHoliday=function(e,t){return i(t),0===e.getDay()||o(e,t)},e.setLanguage=function(e){var t=e.toLowerCase();if(!r[t])throw new TypeError(`[feiertagejs] tried to set language to ${t} but the translation is missing. Please use addTranslation(isoCode,object) first`);n=e}}); \ No newline at end of file diff --git a/assets/admin/js/src/booking.js b/assets/admin/js/src/booking.js index 950287293..3bb49df00 100644 --- a/assets/admin/js/src/booking.js +++ b/assets/admin/js/src/booking.js @@ -5,6 +5,21 @@ let startTimeInput = $('#repetition-start_time'); let endTimeInput = $('#repetition-end_time'); let preserveManualCode = false; + let itemInput = $('#item-id'); + let locationInput = $('#location-id'); + let startDateInput = $('#repetition-start_date'); + let bookingCodeInput = $('#_cb_bookingcode'); + + // check if this is loaded on right kind of backend page + let allExist = [ + fullDayCheckbox, startTimeInput, endTimeInput, itemInput, locationInput, startDateInput, bookingCodeInput + ].every(domElement => domElement.length === 1); + + if (!allExist) { + // return early to prevent ajax calls with incorrect parameters + return; + } + fullDayCheckbox.on('change', function (event) { if (fullDayCheckbox.is(':checked')) { startTimeInput.val('00:00'); @@ -18,12 +33,6 @@ }); fullDayCheckbox.trigger('change'); - - let itemInput = $('#item-id'); - let locationInput = $('#location-id'); - let startDateInput = $('#repetition-start_date'); - let bookingCodeInput = $('#_cb_bookingcode'); - itemInput.on('change', function (event) { let data = { itemID: itemInput.val(), diff --git a/assets/admin/js/src/map.js b/assets/admin/js/src/map.js new file mode 100644 index 000000000..ded3b3969 --- /dev/null +++ b/assets/admin/js/src/map.js @@ -0,0 +1,91 @@ +(function ($) { + 'use strict'; + $(function () { + const mapSettingsForm = $("#cmb2-metabox-cb_map-custom-fields"); + + const hideFieldset = function (set) { + $.each(set, function () { + $(this).parents('.cmb-row').hide(); + }); + }; + + /** + * Show set-elements. + * @param set + */ + const showFieldset = function (set) { + $.each(set, function () { + $(this).parents('.cmb-row').show(); + }); + }; + + const copyToClipboard = function (element) { + let code = $(element).find('code')[0]; + let text = code.innerText; + navigator.clipboard.writeText(text).then(function () { + let button = $(element).find('.button'); + let buttonText = button.text(); + button.text('✓'); + button.disabled = true; + setTimeout(function () { + button.text(buttonText); + button.disabled = false; + }, 2000); + }); + } + + const copyToClipboardButton = $('#shortcode-field').find('.button'); + copyToClipboardButton.on('click', function () { + copyToClipboard($('#shortcode-field')); + }); + + function handleCustomFileInput(fileSelectorID, fileInputFields) { + const markerFileSelect = document.querySelector(fileSelectorID); + const handleSelectCustomMarker = function () { + showFieldset(fileInputFields); + if (markerFileSelect.value === '') { + hideFieldset(fileInputFields); + } + }; + + handleSelectCustomMarker(); + + const observerConfig = {attributes: true, childList: false, subtree: false}; + const observer = new MutationObserver(function (mutations) { + mutations.forEach(function (mutation) { + if (mutation.attributeName === 'value') { + handleSelectCustomMarker(); + } + }); + }); + observer.observe(markerFileSelect, observerConfig); + } + + if (mapSettingsForm.length) { + handleCustomFileInput( + '#custom_marker_media', + [ + $('#marker_icon_width'), + $('#marker_icon_height'), + $('#marker_icon_anchor_x'), + $('#marker_icon_anchor_y') + ]); + handleCustomFileInput( + '#custom_marker_cluster_media', + [ + $('#marker_cluster_icon_width'), + $('#marker_cluster_icon_height') + ] + ); + handleCustomFileInput( + '#marker_item_draft_media', + [ + $('#marker_item_draft_icon_width'), + $('#marker_item_draft_icon_height'), + $('#marker_item_draft_icon_anchor_x'), + $('#marker_item_draft_icon_anchor_y') + ] + ); + } + }); +})(jQuery); diff --git a/assets/admin/sass/admin.scss b/assets/admin/sass/admin.scss index 4aef72474..2d51074de 100644 --- a/assets/admin/sass/admin.scss +++ b/assets/admin/sass/admin.scss @@ -22,7 +22,10 @@ /* Booking form */ @use "./partials/form-booking"; -/* Booking form */ +/* Map creation */ +@use "./partials/form-map"; + +/* Plugin update page */ @use "./partials/plugin_update"; /* Edit Screens Backend */ diff --git a/assets/admin/sass/partials/_dashboard.scss b/assets/admin/sass/partials/_dashboard.scss index 87fc18de9..86e296248 100644 --- a/assets/admin/sass/partials/_dashboard.scss +++ b/assets/admin/sass/partials/_dashboard.scss @@ -3,6 +3,8 @@ * */ +@use "../../../global/sass/partials/extends"; + .cb-admin-page { .cb-admin-cols { display: flex; @@ -18,7 +20,7 @@ ul { li { margin-top: 15px; - @extend .cb-box !optional; + @extend .cb-box; .cb-summmary-item { font-weight: bold; } diff --git a/assets/admin/sass/partials/_form-map.scss b/assets/admin/sass/partials/_form-map.scss new file mode 100644 index 000000000..79a9a727f --- /dev/null +++ b/assets/admin/sass/partials/_form-map.scss @@ -0,0 +1,41 @@ +/* +* The CPT creation form map + */ + +#cmb2-metabox-cb_map-custom-fields { + .map-organizer { + .cmb2-metabox-title { + font-size: x-large; + } + .cmb2-metabox-title:before { + /* arrow to right */ + content: "\2192 "; + } + } + + .cmb-group-name { + font-size: x-large; + font-weight: bold; + } + + .cmb-group-name:before { + content: "\2192 "; + } + + #shortcode-field { + display: flex; + align-items: center; + flex-wrap: nowrap; + gap: 10px; + } + + #shortcode-field code { + white-space: nowrap; + margin-right: 10px; + } + + #shortcode-field .button { + padding: 5px 10px; + line-height: 1.5; + } +} \ No newline at end of file diff --git a/assets/map/js/cb-map-marker-upload.js b/assets/map/js/cb-map-marker-upload.js deleted file mode 100644 index 4aa92e5e6..000000000 --- a/assets/map/js/cb-map-marker-upload.js +++ /dev/null @@ -1,169 +0,0 @@ -var cb_map_marker_upload = { - translation: {}, - - //based on: https://jeroensormani.com/how-to-include-the-wordpress-media-selector-in-your-plugin/ - init: function($, data) { - // uploading files - var file_frame; - var wp_media_post_id = wp.media.model.settings.post.id; // Store the old id - var set_to_post_id = data.$custom_marker_media_id.val(); - - data.$remove_image_button.on('click', function(event) { - event.preventDefault(); - - data.$custom_marker_media_id.val(''); - data.$image_preview.attr('src', ''); - - data.$marker_icon_width.val(0); - data.$marker_icon_height.val(0); - data.$marker_icon_anchor_x.val(0); - data.$marker_icon_anchor_y.val(0); - - data.$image_preview_settings.hide(); - data.$image_preview_measurements.text(''); - data.$marker_icon_size.hide(); - data.$marker_icon_anchor.hide(); - - }); - - data.$select_image_button.on('click', function(event) { - - event.preventDefault(); - // if the media frame already exists, reopen it. - if ( file_frame ) { - // Set the post ID to what we want - file_frame.uploader.uploader.param( 'post_id', set_to_post_id ); - // Open frame - file_frame.open(); - return; - - } else { - // set the wp.media post id so the uploader grabs the ID we want when initialised - wp.media.model.settings.post.id = set_to_post_id; - } - - // create the media frame - file_frame = wp.media.frames.file_frame = wp.media({ - title: cb_map_marker_upload.translation.SELECT_IMAGE, - button: { - text: cb_map_marker_upload.translation.SAVE, - }, - multiple: false - }); - - // image select callback - file_frame.on( 'select', function() { - var attachment = file_frame.state().get('selection').first().toJSON(); - - // Do something with attachment.id and/or attachment.url here - data.$image_preview.attr( 'src', attachment.url ).css( 'width', 'auto' ); - data.$custom_marker_media_id.val( attachment.id ); - // restore the main post ID - wp.media.model.settings.post.id = wp_media_post_id; - - data.$marker_icon_width.val(0); - data.$marker_icon_height.val(0); - data.$marker_icon_anchor_x.val(0); - data.$marker_icon_anchor_y.val(0); - }); - - // finally, open the modal - file_frame.open(); - }); - - // restore the main ID when the add media button is pressed - $( 'a.add_media' ).on( 'click', function() { - wp.media.model.settings.post.id = wp_media_post_id; - }); - - data.$image_preview.on('load', function() { - - data.$image_preview_settings.show(); - data.$image_preview_measurements.text(cb_map_marker_upload.translation.MARKER_IMAGE_MEASUREMENTS + ': ' + data.$image_preview.width() + ' x ' + data.$image_preview.height() + ' px'); - data.$marker_icon_size.show(); - data.$marker_icon_anchor.show(); - - if(data.$marker_icon_width.val() == 0) { - data.$marker_icon_width.val(data.$image_preview.width()); - } - - if(data.$marker_icon_height.val() == 0) { - data.$marker_icon_height.val(data.$image_preview.height()); - } - - if(data.$marker_icon_anchor_x.val() == 0) { - data.$marker_icon_anchor_x.val(data.$image_preview.width() / 2); - } - - if(data.$marker_icon_anchor_y.val() == 0) { - data.$marker_icon_anchor_y.val(data.$image_preview.height()); - } - - }); - - //if parent details got opened, trigger load for cached images - var $parent_details = data.$image_preview.closest('details'); - $parent_details.on('toggle', function() { - var src = data.$image_preview.attr('src'); - if($parent_details.prop('open') == true && src.length > 0) { - setTimeout(function() { - data.$image_preview.load(); - }, 0); - } - }); - } -} - -jQuery(document).ready(function($) { - - var marker_data = { - $select_image_button: $('#select-marker-image-button'), - $remove_image_button: $('#remove-marker-image-button'), - $custom_marker_media_id: $('input[name="cb_map_options[custom_marker_media_id]"'), - $image_preview: $('#marker-image-preview'), - $marker_icon_width: $('input[name="cb_map_options[marker_icon_width]"'), - $marker_icon_height: $('input[name="cb_map_options[marker_icon_height]"'), - $marker_icon_anchor_x: $('input[name="cb_map_options[marker_icon_anchor_x]"'), - $marker_icon_anchor_y: $('input[name="cb_map_options[marker_icon_anchor_y]"'), - $image_preview_settings: $('#marker-image-preview-settings'), - $image_preview_measurements: $('#marker-image-preview-measurements'), - $marker_icon_size: $('#marker-icon-size'), - $marker_icon_anchor: $('#marker-icon-anchor') - }; - - cb_map_marker_upload.init($, marker_data); - - var marker_cluster_data = { - $select_image_button: $('#select-marker-cluster-image-button'), - $remove_image_button: $('#remove-marker-cluster-image-button'), - $custom_marker_media_id: $('input[name="cb_map_options[custom_marker_cluster_media_id]"'), - $image_preview: $('#marker-cluster-image-preview'), - $marker_icon_width: $('input[name="cb_map_options[marker_cluster_icon_width]"'), - $marker_icon_height: $('input[name="cb_map_options[marker_cluster_icon_height]"'), - $marker_icon_anchor_x: $('input[name="cb_map_options[marker_cluster_icon_anchor_x]"'), - $marker_icon_anchor_y: $('input[name="cb_map_options[marker_cluster_icon_anchor_y]"'), - $image_preview_settings: $('#marker-cluster-image-preview-settings'), - $image_preview_measurements: $('#marker-cluster-image-preview-measurements'), - $marker_icon_size: $('#marker-cluster-icon-size'), - $marker_icon_anchor: $('#marker-cluster-icon-anchor') - }; - - cb_map_marker_upload.init($, marker_cluster_data); - - var marker_item_draft_data = { - $select_image_button: $('#select-marker-item-draft-image-button'), - $remove_image_button: $('#remove-marker-item-draft-image-button'), - $custom_marker_media_id: $('input[name="cb_map_options[marker_item_draft_media_id]"'), - $image_preview: $('#marker-item-draft-image-preview'), - $marker_icon_width: $('input[name="cb_map_options[marker_item_draft_icon_width]"'), - $marker_icon_height: $('input[name="cb_map_options[marker_item_draft_icon_height]"'), - $marker_icon_anchor_x: $('input[name="cb_map_options[marker_item_draft_icon_anchor_x]"'), - $marker_icon_anchor_y: $('input[name="cb_map_options[marker_item_draft_icon_anchor_y]"'), - $image_preview_settings: $('#marker-item-draft-image-preview-settings'), - $image_preview_measurements: $('#marker-item-draft-image-preview-measurements'), - $marker_icon_size: $('#marker-item-draft-icon-size'), - $marker_icon_anchor: $('#marker-item-draft-icon-anchor') - }; - - cb_map_marker_upload.init($, marker_item_draft_data); -}); diff --git a/assets/public/css/public.css b/assets/public/css/public.css index 418a5645d..72a3a8d47 100644 --- a/assets/public/css/public.css +++ b/assets/public/css/public.css @@ -3176,7 +3176,7 @@ * */ /* -------------------- Boxes -------------------- */ -.cb-box { +.cb-box, .cb-items-table, .cb-wrapper .cb-notice, .cb-map-filters.cb-wrapper, .cb-wrapper .cb-action, .cb-wrapper.template-location-single > div:not(.cb-notice), .cb-wrapper.template-item-single > div:not(.cb-notice), .cb-wrapper.template-booking-single > div:not(.cb-notice), .cb-wrapper { background: var(--commonsbooking-color-gray-background); overflow: hidden; border-radius: var(--commonsbooking-radius); @@ -3184,24 +3184,24 @@ padding: var(--commonsbooking-spacer-small)/2 var(--commonsbooking-spacer-small); } @media (min-width: 37.5em) { - .cb-box { + .cb-box, .cb-items-table, .cb-wrapper .cb-notice, .cb-map-filters.cb-wrapper, .cb-wrapper .cb-action, .cb-wrapper.template-location-single > div:not(.cb-notice), .cb-wrapper.template-item-single > div:not(.cb-notice), .cb-wrapper.template-booking-single > div:not(.cb-notice), .cb-wrapper { padding: var(--commonsbooking-spacer) var(--commonsbooking-spacer-big); } } -.cb-box-inner { +.cb-box-inner, .litepicker .container__months, .cb-wrapper #booking-form .time-selection-container > div, .cb-wrapper > .cb-wrapper { background: #FFF; border-radius: var(--commonsbooking-radius); padding: var(--commonsbooking-spacer-small); } @media (min-width: 37.5em) { - .cb-box-inner { + .cb-box-inner, .litepicker .container__months, .cb-wrapper #booking-form .time-selection-container > div, .cb-wrapper > .cb-wrapper { padding: var(--commonsbooking-spacer); } } /* -------------------- Typography -------------------- */ -.cb-big { +.cb-big, .cb-map-filters.cb-wrapper .cb-map-filter-group-label { font-size: var(--commonsbooking-font-size-big); font-weight: bold; } @@ -3211,7 +3211,7 @@ box-shadow: 0px 5px 20px 5px rgba(0, 0, 0, 0.22); } -.shadow-small, .cb-button[disabled=disabled], .cb-button-container a[disabled=disabled], .cb-button:hover, .cb-button-container a:hover, .cb-hover { +.shadow-small, .cb-button[disabled=disabled], .cb-map-filters.cb-wrapper .cb-map-button-wrapper button[disabled=disabled], .cb-wrapper .cb-action input[disabled=disabled], .cb-wrapper #booking-form input[disabled=disabled], .cb-button-container a[disabled=disabled], .cb-button:hover, .cb-map-filters.cb-wrapper .cb-map-button-wrapper button:hover, .cb-wrapper .cb-action input:hover, .cb-wrapper #booking-form input:hover, .cb-button-container a:hover, .cb-hover { box-shadow: 0px 2px 5px 2px rgba(0, 0, 0, 0.1); } @@ -3225,7 +3225,7 @@ } /* -------------------- Buttons -------------------- */ -.cb-button, .cb-button-container a { +.cb-button, .cb-map-filters.cb-wrapper .cb-map-button-wrapper button, .cb-wrapper .cb-action input, .cb-wrapper #booking-form input, .cb-button-container a { border-radius: var(--commonsbooking-radius); font-size: var(--commonsbooking-font-size-normal); line-height: var(--commonsbooking-font-size-normal); @@ -3238,43 +3238,43 @@ padding: var(--commonsbooking-spacer) var(--commonsbooking-spacer-big); font-weight: bold; } -.cb-button.small, .cb-button-container a.small { +.cb-button.small, .cb-map-filters.cb-wrapper .cb-map-button-wrapper button.small, .cb-wrapper .cb-action input.small, .cb-wrapper #booking-form input.small, .cb-button-container a.small { padding: var(--commonsbooking-spacer); font-size: var(--commonsbooking-font-size-small); } -.cb-button:hover, .cb-button-container a:hover { +.cb-button:hover, .cb-map-filters.cb-wrapper .cb-map-button-wrapper button:hover, .cb-wrapper .cb-action input:hover, .cb-wrapper #booking-form input:hover, .cb-button-container a:hover { background: var(--commonsbooking-color-secondary); color: #FFF; /* Various themes fix */ } -.cb-button:visited, .cb-button-container a:visited { +.cb-button:visited, .cb-map-filters.cb-wrapper .cb-map-button-wrapper button:visited, .cb-wrapper .cb-action input:visited, .cb-wrapper #booking-form input:visited, .cb-button-container a:visited { color: #FFF; } -.cb-button.big, .cb-button-container a.big { +.cb-button.big, .cb-map-filters.cb-wrapper .cb-map-button-wrapper button.big, .cb-wrapper .cb-action input.big, .cb-wrapper #booking-form input.big, .cb-button-container a.big { padding: var(--commonsbooking-spacer) var(--commonsbooking-spacer-big); font-size: var(--commonsbooking-font-size-big); line-height: var(--commonsbooking-font-size-big); } -.cb-button.secondary, .cb-button-container a.secondary { +.cb-button.secondary, .cb-map-filters.cb-wrapper .cb-map-button-wrapper button.secondary, .cb-wrapper .cb-action input.secondary, .cb-wrapper #booking-form input.secondary, .cb-button-container a.secondary { background-color: #FFF; color: var(--commonsbooking-color-error); } -.cb-button.cancel, .cb-button-container a.cancel { +.cb-button.cancel, .cb-map-filters.cb-wrapper .cb-map-button-wrapper button.cancel, .cb-wrapper .cb-action input.cancel, .cb-wrapper #booking-form input.cancel, .cb-button-container a.cancel { background-color: var(--commonsbooking-color-error); } -.cb-button.confirm, .cb-button-container a.confirm { +.cb-button.confirm, .cb-map-filters.cb-wrapper .cb-map-button-wrapper button.confirm, .cb-wrapper .cb-action input.confirm, .cb-wrapper #booking-form input.confirm, .cb-button-container a.confirm { background-color: var(--commonsbooking-color-success); } -.cb-button.delete, .cb-button-container a.delete { +.cb-button.delete, .cb-map-filters.cb-wrapper .cb-map-button-wrapper button.delete, .cb-wrapper .cb-action input.delete, .cb-wrapper #booking-form input.delete, .cb-button-container a.delete { background-color: var(--commonsbooking-color-error); } -.cb-button[disabled=disabled], .cb-button-container a[disabled=disabled] { +.cb-button[disabled=disabled], .cb-map-filters.cb-wrapper .cb-map-button-wrapper button[disabled=disabled], .cb-wrapper .cb-action input[disabled=disabled], .cb-wrapper #booking-form input[disabled=disabled], .cb-button-container a[disabled=disabled] { background-color: var(--commonsbooking-color-greyedout); color: var(--commonsbooking-textcolor-light); } -.cb-button.no-right-radius, .cb-button-container a.no-right-radius { +.cb-button.no-right-radius, .cb-map-filters.cb-wrapper .cb-map-button-wrapper button.no-right-radius, .cb-wrapper .cb-action input.no-right-radius, .cb-wrapper #booking-form input.no-right-radius, .cb-button-container a.no-right-radius { border-radius: var(--commonsbooking-radius) 0; } -.cb-button.no-left-radius, .cb-button-container a.no-left-radius { +.cb-button.no-left-radius, .cb-map-filters.cb-wrapper .cb-map-button-wrapper button.no-left-radius, .cb-wrapper .cb-action input.no-left-radius, .cb-wrapper #booking-form input.no-left-radius, .cb-button-container a.no-left-radius { border-radius: 0 var(--commonsbooking-radius); } @@ -3357,69 +3357,92 @@ } } -.cb-col-50-50-filter > div { +.cb-col-50-50-filter > div, .cb-map-filters.cb-wrapper .cb-map-availability-filter .cb-map-filter-group > div, +.cb-map-filters.cb-wrapper .cb-map-distance-filter .cb-map-filter-group > div { margin-bottom: var(--commonsbooking-spacer); width: 100%; display: flex; align-items: center; flex-wrap: nowrap; } -.cb-col-50-50-filter > div label { +.cb-col-50-50-filter > div label, .cb-map-filters.cb-wrapper .cb-map-availability-filter .cb-map-filter-group > div label, +.cb-map-filters.cb-wrapper .cb-map-distance-filter .cb-map-filter-group > div label { flex: 0 0 30%; } -.cb-col-50-50-filter > div input { +.cb-col-50-50-filter > div input, .cb-map-filters.cb-wrapper .cb-map-availability-filter .cb-map-filter-group > div input, +.cb-map-filters.cb-wrapper .cb-map-distance-filter .cb-map-filter-group > div input { flex: 0 1 50%; } @media (min-width: 37.5em) { - .cb-col-50-50-filter { + .cb-col-50-50-filter, .cb-map-filters.cb-wrapper .cb-map-availability-filter .cb-map-filter-group, + .cb-map-filters.cb-wrapper .cb-map-distance-filter .cb-map-filter-group { display: flex; justify-content: space-between; flex-direction: row; align-items: center; flex-wrap: wrap; } - .cb-col-50-50-filter > div { + .cb-col-50-50-filter > div, .cb-map-filters.cb-wrapper .cb-map-availability-filter .cb-map-filter-group > div, + .cb-map-filters.cb-wrapper .cb-map-distance-filter .cb-map-filter-group > div { width: 50%; } } -.cb-col-auto { /* 2 fixed cols, 1 flexible in the middle */ +.cb-col-auto, .cb-wrapper .template-timeframe-withitem, +.cb-wrapper .template-timeframe-withlocation, +.cb-wrapper .template-item-withlocation, .cb-wrapper .cb-list-header { /* 2 fixed cols, 1 flexible in the middle */ display: flex; flex-direction: row; flex-wrap: wrap; } -.cb-col-auto > div.cb-thumbnail { +.cb-col-auto > div.cb-thumbnail, .cb-wrapper .template-timeframe-withitem > div.cb-thumbnail, +.cb-wrapper .template-timeframe-withlocation > div.cb-thumbnail, +.cb-wrapper .template-item-withlocation > div.cb-thumbnail, .cb-wrapper .cb-list-header > div.cb-thumbnail { flex: 0 0 20%; padding-right: var(--commonsbooking-spacer-big); } -.cb-col-auto > div.cb-list-info { +.cb-col-auto > div.cb-list-info, .cb-wrapper .template-timeframe-withitem > div.cb-list-info, +.cb-wrapper .template-timeframe-withlocation > div.cb-list-info, +.cb-wrapper .template-item-withlocation > div.cb-list-info, .cb-wrapper .cb-list-header > div.cb-list-info { flex: 1 0 50%; border: none; } -.cb-col-auto > div.cb-action { /* optional */ +.cb-col-auto > div.cb-action, .cb-wrapper .template-timeframe-withitem > div.cb-action, +.cb-wrapper .template-timeframe-withlocation > div.cb-action, +.cb-wrapper .template-item-withlocation > div.cb-action, .cb-wrapper .cb-list-header > div.cb-action { /* optional */ flex: 0 0 100%; text-align: right; } @media (min-width: 37.5em) { - .cb-col-auto { + .cb-col-auto, .cb-wrapper .template-timeframe-withitem, + .cb-wrapper .template-timeframe-withlocation, + .cb-wrapper .template-item-withlocation, .cb-wrapper .cb-list-header { display: flex; flex-direction: row; justify-content: space-between; flex-wrap: nowrap; align-items: center; } - .cb-col-auto > div.cb-thumbnail { + .cb-col-auto > div.cb-thumbnail, .cb-wrapper .template-timeframe-withitem > div.cb-thumbnail, + .cb-wrapper .template-timeframe-withlocation > div.cb-thumbnail, + .cb-wrapper .template-item-withlocation > div.cb-thumbnail, .cb-wrapper .cb-list-header > div.cb-thumbnail { flex: 0 0 20%; padding-right: var(--commonsbooking-spacer-big); } - .cb-col-auto > div.cb-list-info { + .cb-col-auto > div.cb-list-info, .cb-wrapper .template-timeframe-withitem > div.cb-list-info, + .cb-wrapper .template-timeframe-withlocation > div.cb-list-info, + .cb-wrapper .template-item-withlocation > div.cb-list-info, .cb-wrapper .cb-list-header > div.cb-list-info { flex: 1 1 auto; border: none; } - .cb-col-auto > div.cb-action { + .cb-col-auto > div.cb-action, .cb-wrapper .template-timeframe-withitem > div.cb-action, + .cb-wrapper .template-timeframe-withlocation > div.cb-action, + .cb-wrapper .template-item-withlocation > div.cb-action, .cb-wrapper .cb-list-header > div.cb-action { flex: 1 0 auto; } - .cb-col-auto > div.cb-action a { + .cb-col-auto > div.cb-action a, .cb-wrapper .template-timeframe-withitem > div.cb-action a, + .cb-wrapper .template-timeframe-withlocation > div.cb-action a, + .cb-wrapper .template-item-withlocation > div.cb-action a, .cb-wrapper .cb-list-header > div.cb-action a { width: auto; } } @@ -3445,6 +3468,7 @@ } /* List styles */ +/* Multi-column layouts */ /** * List styling * @@ -4099,6 +4123,7 @@ } /* Map styles */ +/* Multi-column layouts */ /** * Map + Leaflet Filter Styling * diff --git a/assets/public/sass/partials/_calendar.scss b/assets/public/sass/partials/_calendar.scss index 633aa8095..e94ca2bb4 100644 --- a/assets/public/sass/partials/_calendar.scss +++ b/assets/public/sass/partials/_calendar.scss @@ -5,6 +5,7 @@ * */ @use "../mixins/calendar"; +@use "../../../global/sass/partials/extends"; :root { --litepickerBgColor: transparent; @@ -72,7 +73,7 @@ } &__months { - @extend .cb-box-inner !optional; + @extend .cb-box-inner; background: transparent; box-shadow: none; diff --git a/assets/public/sass/partials/_forms.scss b/assets/public/sass/partials/_forms.scss index e3393ed78..bb4b07d60 100644 --- a/assets/public/sass/partials/_forms.scss +++ b/assets/public/sass/partials/_forms.scss @@ -11,6 +11,7 @@ */ @use "../../../global/sass/partials/variables"; +@use "../../../global/sass/partials/extends"; .cb-wrapper { @@ -57,12 +58,12 @@ } .cb-action { - @extend .cb-box !optional; + @extend .cb-box; text-align: right; input { - @extend .cb-button !optional; + @extend .cb-button; float: right; } @@ -115,7 +116,7 @@ width: 100%; /* do not extend litepicker width */ color: var(--commonsbooking-textcolor-dark); input { - @extend .cb-button !optional; + @extend .cb-button; float: right; } @@ -131,7 +132,7 @@ display: flex; align-items: center; - @extend .cb-box-inner !optional; + @extend .cb-box-inner; margin-bottom: var(--commonsbooking-spacer); text-align: left; overflow: hidden; @@ -169,7 +170,7 @@ } .cb-notice { - @extend .cb-box !optional; + @extend .cb-box; margin-bottom: var(--commonsbooking-spacer-big); font-size: var(--commonsbooking-font-size-big); vertical-align: middle; diff --git a/assets/public/sass/partials/_lists.scss b/assets/public/sass/partials/_lists.scss index 91f988702..4c69ff3cd 100644 --- a/assets/public/sass/partials/_lists.scss +++ b/assets/public/sass/partials/_lists.scss @@ -11,6 +11,9 @@ * @copyright 2020 wielebenwir */ +@use "../../../global/sass/partials/extends"; +@use "layouts"; + /* main wrapper */ .cb-wrapper { @@ -19,7 +22,7 @@ display: block; margin-top: var(--commonsbooking-spacer-big); color: var(--commonsbooking-textcolor-dark); - @extend .cb-box !optional;; + @extend .cb-box ; .cb-list-content.cb-pickupinstructions div { white-space: pre-wrap; // enable line break in content from meta textfields @@ -56,7 +59,7 @@ /* sub lists wrapper */ > .cb-wrapper { overflow: hidden; - @extend .cb-box-inner !optional;; + @extend .cb-box-inner ; > div { /* sub list items */ @@ -71,10 +74,10 @@ .template-timeframe-withlocation, .template-item-withlocation { - @extend .cb-col-auto !optional;; + @extend .cb-col-auto ; } .cb-list-header { - @extend .cb-col-auto !optional;; + @extend .cb-col-auto ; } .cb-list-header img{ diff --git a/assets/public/sass/partials/_map.scss b/assets/public/sass/partials/_map.scss index 4ef9b0ed3..7c44fdec7 100644 --- a/assets/public/sass/partials/_map.scss +++ b/assets/public/sass/partials/_map.scss @@ -13,6 +13,8 @@ */ @use "../../../global/sass/partials/variables"; +@use "../../../global/sass/partials/extends"; +@use "layouts"; .cb-wrapper { @@ -149,7 +151,7 @@ .cb-map-filters.cb-wrapper { margin-top: var(--commonsbooking-spacer); - @extend .cb-box !optional; + @extend .cb-box; input[type="checkbox"] { margin: 0 var(--commonsbooking-spacer-small) 0 0; @@ -180,7 +182,7 @@ } .cb-map-filter-group-label { - @extend .cb-big !optional; + @extend .cb-big; color: var(--commonsbooking-color-primary); margin-bottom: var(--commonsbooking-spacer-small); } @@ -190,7 +192,7 @@ .cb-map-availability-filter, .cb-map-distance-filter { .cb-map-filter-group { - @extend .cb-col-50-50-filter !optional; + @extend .cb-col-50-50-filter; } } @@ -247,7 +249,7 @@ .cb-map-button-wrapper { text-align: right; button { - @extend .cb-button !optional; + @extend .cb-button; } } } diff --git a/assets/public/sass/partials/_notice.scss b/assets/public/sass/partials/_notice.scss index 5bd50be87..2e99a2aca 100644 --- a/assets/public/sass/partials/_notice.scss +++ b/assets/public/sass/partials/_notice.scss @@ -6,9 +6,11 @@ * */ +@use "../../../global/sass/partials/extends"; + .cb-wrapper { .cb-notice { - @extend .cb-box !optional; + @extend .cb-box; margin-bottom: var(--commonsbooking-spacer-big); font-size: var(--commonsbooking-font-size-big); vertical-align: middle; diff --git a/assets/public/sass/partials/_shortcodeItemsTable.scss b/assets/public/sass/partials/_shortcodeItemsTable.scss index 4cdb4a744..4eb1abdb8 100644 --- a/assets/public/sass/partials/_shortcodeItemsTable.scss +++ b/assets/public/sass/partials/_shortcodeItemsTable.scss @@ -13,6 +13,7 @@ */ @use "../../../global/sass/partials/variables"; +@use "../../../global/sass/partials/extends"; @use "../../../public/sass/mixins/calendar"; .cb-table-scroll { @@ -21,7 +22,7 @@ } .cb-items-table { - @extend .cb-box !optional; + @extend .cb-box; overflow: auto; /* overwriting cb-box standard behaviour */ padding: 0; /* overwriting cb-box standard behaviour */ width: 100%; diff --git a/assets/public/sass/partials/_single.scss b/assets/public/sass/partials/_single.scss index e8307e5fb..4de2109b7 100644 --- a/assets/public/sass/partials/_single.scss +++ b/assets/public/sass/partials/_single.scss @@ -3,6 +3,8 @@ * */ +@use "../../../global/sass/partials/extends"; + .cb-wrapper { /* invert the color scheme from the lists: wrapper has no bg, sub-wrapper colored */ &.template-location-single, @@ -11,7 +13,7 @@ background: transparent; padding: 0; > div:not(.cb-notice) { - @extend .cb-box !optional; + @extend .cb-box; > div { /* sub list items */ &:last-of-type { border-bottom: 0; diff --git a/commonsbooking.php b/commonsbooking.php index cb962aa83..0c6c8d550 100644 --- a/commonsbooking.php +++ b/commonsbooking.php @@ -2,7 +2,7 @@ /** * Plugin Name: Commons Booking - * Version: 2.9.4 + * Version: 2.10.2 * Requires at least: 5.2 * Requires PHP: 7.4 * Plugin URI: https://commonsbooking.org @@ -18,8 +18,8 @@ use CommonsBooking\Plugin; defined('ABSPATH') or die("Thanks for visiting"); -define('COMMONSBOOKING_VERSION', '2.9.4'); -define('COMMONSBOOKING_VERSION_COMMENT', 'master'); // Empty for release - Used to mark development versions +define('COMMONSBOOKING_VERSION', '2.10.2'); +define('COMMONSBOOKING_VERSION_COMMENT', ''); // Empty for release - Used to mark development versions define('COMMONSBOOKING_PLUGIN_SLUG', 'commonsbooking'); define('COMMONSBOOKING_MENU_SLUG', COMMONSBOOKING_PLUGIN_SLUG . '-menu'); define('COMMONSBOOKING_PLUGIN_DIR', wp_normalize_path( plugin_dir_path(__FILE__))); diff --git a/composer.json b/composer.json index 797b4f161..491399e4b 100644 --- a/composer.json +++ b/composer.json @@ -6,9 +6,10 @@ "platform-check": false, "allow-plugins": { "php-http/discovery": true, - "dealerdirect/phpcodesniffer-composer-installer": true + "dealerdirect/phpcodesniffer-composer-installer": true, + "phpstan/extension-installer": true } - }, + }, "autoload": { "psr-4": { "CommonsBooking\\": "src/" @@ -31,7 +32,7 @@ ], "require": { - "php": ">=7.3", + "php": ">=7.4", "cmb2/cmb2": "^2.10.1", "mustardbees/cmb-field-select2": "^3.0.4", "geocoder-php/nominatim-provider": "^5.7", @@ -54,6 +55,9 @@ "phpcompatibility/phpcompatibility-wp": "^2.1.4", "slope-it/clock-mock": "^0.4.0", "phpunit/php-code-coverage": "^9.2.32", - "myclabs/deep-copy": "^1.12.0" + "myclabs/deep-copy": "^1.12.0", + "phpstan/phpstan": "^2.1", + "szepeviktor/phpstan-wordpress": "^2.0", + "phpstan/extension-installer": "^1.4" } } diff --git a/composer.lock b/composer.lock index 239be9349..7057f3bd8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3cef4a58c672b31917fae588e87f7e67", + "content-hash": "86a68c900a7db4caa9242e22f7465c33", "packages": [ { "name": "clue/stream-filter", @@ -74,27 +74,27 @@ }, { "name": "cmb2/cmb2", - "version": "v2.11.0", + "version": "v2.10.1", "source": { "type": "git", "url": "https://github.com/CMB2/CMB2.git", - "reference": "2847828b5cce1b48d09427ee13e6f7c752704468" + "reference": "4afc4bb7b92ab6d93aac2247c9a84af773e42532" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CMB2/CMB2/zipball/2847828b5cce1b48d09427ee13e6f7c752704468", - "reference": "2847828b5cce1b48d09427ee13e6f7c752704468", + "url": "https://api.github.com/repos/CMB2/CMB2/zipball/4afc4bb7b92ab6d93aac2247c9a84af773e42532", + "reference": "4afc4bb7b92ab6d93aac2247c9a84af773e42532", "shasum": "" }, "require": { - "php": ">7.4" + "php": ">5.2.4" }, "require-dev": { "apigen/apigen": "4.1.2", - "awesomemotive/am-cli-tools": ">=1.3.7", + "awesomemotive/am-cli-tools": ">=1.3.1", "nette/utils": "2.5.3", "phpunit/phpunit": "^6.5", - "yoast/phpunit-polyfills": "^1.1" + "yoast/phpunit-polyfills": "^1.0" }, "suggest": { "composer/installers": "~1.0" @@ -129,7 +129,7 @@ "issues": "https://github.com/CMB2/CMB2/issues", "source": "http://wordpress.org/support/plugin/cmb2" }, - "time": "2024-04-02T19:30:07+00:00" + "time": "2022-02-22T14:15:16+00:00" }, { "name": "ed-itsolutions/cmb2-field-ajax-search", @@ -470,16 +470,16 @@ }, { "name": "opis/json-schema", - "version": "2.3.0", + "version": "2.4.1", "source": { "type": "git", "url": "https://github.com/opis/json-schema.git", - "reference": "c48df6d7089a45f01e1c82432348f2d5976f9bfb" + "reference": "712827751c62b465daae6e725bf0cf5ffbf965e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opis/json-schema/zipball/c48df6d7089a45f01e1c82432348f2d5976f9bfb", - "reference": "c48df6d7089a45f01e1c82432348f2d5976f9bfb", + "url": "https://api.github.com/repos/opis/json-schema/zipball/712827751c62b465daae6e725bf0cf5ffbf965e1", + "reference": "712827751c62b465daae6e725bf0cf5ffbf965e1", "shasum": "" }, "require": { @@ -529,22 +529,22 @@ ], "support": { "issues": "https://github.com/opis/json-schema/issues", - "source": "https://github.com/opis/json-schema/tree/2.3.0" + "source": "https://github.com/opis/json-schema/tree/2.4.1" }, - "time": "2022-01-08T20:38:03+00:00" + "time": "2024-12-30T20:20:21+00:00" }, { "name": "opis/string", - "version": "2.0.1", + "version": "2.0.2", "source": { "type": "git", "url": "https://github.com/opis/string.git", - "reference": "9ebf1a1f873f502f6859d11210b25a4bf5d141e7" + "reference": "ba0b9607b9809462b0e28a11e4881a8d77431feb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/opis/string/zipball/9ebf1a1f873f502f6859d11210b25a4bf5d141e7", - "reference": "9ebf1a1f873f502f6859d11210b25a4bf5d141e7", + "url": "https://api.github.com/repos/opis/string/zipball/ba0b9607b9809462b0e28a11e4881a8d77431feb", + "reference": "ba0b9607b9809462b0e28a11e4881a8d77431feb", "shasum": "" }, "require": { @@ -591,9 +591,9 @@ ], "support": { "issues": "https://github.com/opis/string/issues", - "source": "https://github.com/opis/string/tree/2.0.1" + "source": "https://github.com/opis/string/tree/2.0.2" }, - "time": "2022-01-14T15:42:23+00:00" + "time": "2024-12-30T21:43:22+00:00" }, { "name": "opis/uri", @@ -1037,16 +1037,16 @@ }, { "name": "phpmailer/phpmailer", - "version": "v6.9.2", + "version": "v6.9.3", "source": { "type": "git", "url": "https://github.com/PHPMailer/PHPMailer.git", - "reference": "a7b17b42fa4887c92146243f3d2f4ccb962af17c" + "reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/a7b17b42fa4887c92146243f3d2f4ccb962af17c", - "reference": "a7b17b42fa4887c92146243f3d2f4ccb962af17c", + "url": "https://api.github.com/repos/PHPMailer/PHPMailer/zipball/2f5c94fe7493efc213f643c23b1b1c249d40f47e", + "reference": "2f5c94fe7493efc213f643c23b1b1c249d40f47e", "shasum": "" }, "require": { @@ -1106,7 +1106,7 @@ "description": "PHPMailer is a full-featured email creation and transfer class for PHP", "support": { "issues": "https://github.com/PHPMailer/PHPMailer/issues", - "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.2" + "source": "https://github.com/PHPMailer/PHPMailer/tree/v6.9.3" }, "funding": [ { @@ -1114,7 +1114,7 @@ "type": "github" } ], - "time": "2024-10-09T10:07:50+00:00" + "time": "2024-11-24T18:04:13+00:00" }, { "name": "psr/cache", @@ -1505,16 +1505,16 @@ }, { "name": "symfony/cache", - "version": "v5.4.46", + "version": "v5.4.40", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "0fe08ee32cec2748fbfea10c52d3ee02049e0f6b" + "reference": "89005bc368ca02ed0433c592e4d27670d0844a66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/0fe08ee32cec2748fbfea10c52d3ee02049e0f6b", - "reference": "0fe08ee32cec2748fbfea10c52d3ee02049e0f6b", + "url": "https://api.github.com/repos/symfony/cache/zipball/89005bc368ca02ed0433c592e4d27670d0844a66", + "reference": "89005bc368ca02ed0433c592e4d27670d0844a66", "shasum": "" }, "require": { @@ -1582,7 +1582,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v5.4.46" + "source": "https://github.com/symfony/cache/tree/v5.4.40" }, "funding": [ { @@ -1598,7 +1598,7 @@ "type": "tidelift" } ], - "time": "2024-11-04T11:43:55+00:00" + "time": "2024-05-31T14:33:22+00:00" }, { "name": "symfony/cache-contracts", @@ -1681,16 +1681,16 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.3", + "version": "v2.5.4", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "80d075412b557d41002320b96a096ca65aa2c98d" + "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/80d075412b557d41002320b96a096ca65aa2c98d", - "reference": "80d075412b557d41002320b96a096ca65aa2c98d", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/605389f2a7e5625f273b53960dc46aeaf9c62918", + "reference": "605389f2a7e5625f273b53960dc46aeaf9c62918", "shasum": "" }, "require": { @@ -1728,7 +1728,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.3" + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.4" }, "funding": [ { @@ -1744,7 +1744,7 @@ "type": "tidelift" } ], - "time": "2023-01-24T14:02:46+00:00" + "time": "2024-09-25T14:11:13+00:00" }, { "name": "symfony/options-resolver", @@ -1835,8 +1835,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -1911,8 +1911,8 @@ "type": "library", "extra": { "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" } }, "autoload": { @@ -2056,16 +2056,16 @@ }, { "name": "symfony/var-exporter", - "version": "v5.4.45", + "version": "v5.4.40", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "862700068db0ddfd8c5b850671e029a90246ec75" + "reference": "6a13d37336d512927986e09f19a4bed24178baa6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/862700068db0ddfd8c5b850671e029a90246ec75", - "reference": "862700068db0ddfd8c5b850671e029a90246ec75", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/6a13d37336d512927986e09f19a4bed24178baa6", + "reference": "6a13d37336d512927986e09f19a4bed24178baa6", "shasum": "" }, "require": { @@ -2109,7 +2109,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v5.4.45" + "source": "https://github.com/symfony/var-exporter/tree/v5.4.40" }, "funding": [ { @@ -2125,7 +2125,7 @@ "type": "tidelift" } ], - "time": "2024-09-25T14:11:13+00:00" + "time": "2024-05-31T14:33:22+00:00" }, { "name": "willdurand/geocoder", @@ -2535,16 +2535,16 @@ }, { "name": "nikic/php-parser", - "version": "v5.3.1", + "version": "v5.4.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b" + "reference": "447a020a1f875a434d62f2a401f53b82a396e494" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/8eea230464783aa9671db8eea6f8c6ac5285794b", - "reference": "8eea230464783aa9671db8eea6f8c6ac5285794b", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494", "shasum": "" }, "require": { @@ -2587,9 +2587,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.3.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" }, - "time": "2024-10-08T18:51:32+00:00" + "time": "2024-12-30T11:07:19+00:00" }, { "name": "phar-io/manifest", @@ -2709,6 +2709,54 @@ }, "time": "2022-02-21T01:04:05+00:00" }, + { + "name": "php-stubs/wordpress-stubs", + "version": "v6.7.1", + "source": { + "type": "git", + "url": "https://github.com/php-stubs/wordpress-stubs.git", + "reference": "83448e918bf06d1ed3d67ceb6a985fc266a02fd1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-stubs/wordpress-stubs/zipball/83448e918bf06d1ed3d67ceb6a985fc266a02fd1", + "reference": "83448e918bf06d1ed3d67ceb6a985fc266a02fd1", + "shasum": "" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "nikic/php-parser": "^4.13", + "php": "^7.4 || ^8.0", + "php-stubs/generator": "^0.8.3", + "phpdocumentor/reflection-docblock": "^5.4.1", + "phpstan/phpstan": "^1.11", + "phpunit/phpunit": "^9.5", + "szepeviktor/phpcs-psr-12-neutron-hybrid-ruleset": "^1.1.1", + "wp-coding-standards/wpcs": "3.1.0 as 2.3.0" + }, + "suggest": { + "paragonie/sodium_compat": "Pure PHP implementation of libsodium", + "symfony/polyfill-php80": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "szepeviktor/phpstan-wordpress": "WordPress extensions for PHPStan" + }, + "type": "library", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "WordPress function and class declaration stubs for static analysis.", + "homepage": "https://github.com/php-stubs/wordpress-stubs", + "keywords": [ + "PHPStan", + "static analysis", + "wordpress" + ], + "support": { + "issues": "https://github.com/php-stubs/wordpress-stubs/issues", + "source": "https://github.com/php-stubs/wordpress-stubs/tree/v6.7.1" + }, + "time": "2024-11-24T03:57:09+00:00" + }, { "name": "phpcompatibility/php-compatibility", "version": "9.3.5", @@ -3079,6 +3127,112 @@ ], "time": "2024-05-20T13:34:27+00:00" }, + { + "name": "phpstan/extension-installer", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/phpstan/extension-installer.git", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/85e90b3942d06b2326fba0403ec24fe912372936", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0", + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.9.0 || ^2.0" + }, + "require-dev": { + "composer/composer": "^2.0", + "php-parallel-lint/php-parallel-lint": "^1.2.0", + "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPStan\\ExtensionInstaller\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPStan\\ExtensionInstaller\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Composer plugin for automatic installation of PHPStan extensions", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/extension-installer/issues", + "source": "https://github.com/phpstan/extension-installer/tree/1.4.3" + }, + "time": "2024-09-04T20:21:43+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan.git", + "reference": "cd6e973e04b4c2b94c86e8612b5a65f0da0e08e7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/cd6e973e04b4c2b94c86e8612b5a65f0da0e08e7", + "reference": "cd6e973e04b4c2b94c86e8612b5a65f0da0e08e7", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2025-01-05T16:43:48+00:00" + }, { "name": "phpunit/php-code-coverage", "version": "9.2.32", @@ -3400,16 +3554,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.21", + "version": "9.6.22", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa" + "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", - "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f80235cb4d3caa59ae09be3adf1ded27521d1a9c", + "reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c", "shasum": "" }, "require": { @@ -3420,7 +3574,7 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.12.0", + "myclabs/deep-copy": "^1.12.1", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=7.3", @@ -3483,7 +3637,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.21" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.22" }, "funding": [ { @@ -3499,7 +3653,7 @@ "type": "tidelift" } ], - "time": "2024-09-19T10:50:18+00:00" + "time": "2024-12-05T13:48:26+00:00" }, { "name": "sebastian/cli-parser", @@ -4598,6 +4752,68 @@ ], "time": "2024-09-18T10:38:58+00:00" }, + { + "name": "szepeviktor/phpstan-wordpress", + "version": "v2.0.1", + "source": { + "type": "git", + "url": "https://github.com/szepeviktor/phpstan-wordpress.git", + "reference": "f7beb13cd22998e3d913fdb897a1e2553ccd637e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/szepeviktor/phpstan-wordpress/zipball/f7beb13cd22998e3d913fdb897a1e2553ccd637e", + "reference": "f7beb13cd22998e3d913fdb897a1e2553ccd637e", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "php-stubs/wordpress-stubs": "^6.6.2", + "phpstan/phpstan": "^2.0" + }, + "require-dev": { + "composer/composer": "^2.1.14", + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.1", + "phpstan/phpstan-strict-rules": "^2.0", + "phpunit/phpunit": "^9.0", + "szepeviktor/phpcs-psr-12-neutron-hybrid-ruleset": "^1.0", + "wp-coding-standards/wpcs": "3.1.0 as 2.3.0" + }, + "suggest": { + "swissspidy/phpstan-no-private": "Detect usage of internal core functions, classes and methods" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + } + }, + "autoload": { + "psr-4": { + "SzepeViktor\\PHPStan\\WordPress\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "WordPress extensions for PHPStan", + "keywords": [ + "PHPStan", + "code analyse", + "code analysis", + "static analysis", + "wordpress" + ], + "support": { + "issues": "https://github.com/szepeviktor/phpstan-wordpress/issues", + "source": "https://github.com/szepeviktor/phpstan-wordpress/tree/v2.0.1" + }, + "time": "2024-12-01T02:13:05+00:00" + }, { "name": "theseer/tokenizer", "version": "1.2.3", @@ -4716,16 +4932,16 @@ }, { "name": "yoast/phpunit-polyfills", - "version": "3.0.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/Yoast/PHPUnit-Polyfills.git", - "reference": "19e6d5fb8aad31f731f774f9646a10c64a8843d2" + "reference": "e6381c62c4df51677b657fbac79b79dfce7acdab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/19e6d5fb8aad31f731f774f9646a10c64a8843d2", - "reference": "19e6d5fb8aad31f731f774f9646a10c64a8843d2", + "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/e6381c62c4df51677b657fbac79b79dfce7acdab", + "reference": "e6381c62c4df51677b657fbac79b79dfce7acdab", "shasum": "" }, "require": { @@ -4775,7 +4991,7 @@ "security": "https://github.com/Yoast/PHPUnit-Polyfills/security/policy", "source": "https://github.com/Yoast/PHPUnit-Polyfills" }, - "time": "2024-09-07T00:24:25+00:00" + "time": "2025-01-12T08:41:37+00:00" } ], "aliases": [], @@ -4784,7 +5000,7 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=7.3", + "php": ">=7.4", "ext-json": "*" }, "platform-dev": {}, diff --git a/includes/Admin.php b/includes/Admin.php index b030bfb86..2780aa553 100644 --- a/includes/Admin.php +++ b/includes/Admin.php @@ -29,13 +29,6 @@ function commonsbooking_admin() { ); } - // Map marker upload scripts - // TODO needs to be evaluated. Maybe not working on all systems - if ( get_current_screen()->id == 'cb_map' ) { - $script_path = COMMONSBOOKING_MAP_ASSETS_URL . 'js/cb-map-marker-upload.js'; - wp_enqueue_script( 'cb-map-marker-upload_js', $script_path ); - } - // CB 0.X migration wp_localize_script( 'cb-scripts-admin', @@ -287,7 +280,7 @@ function commonsbooking_sanitizeArrayorString( $data, $sanitizeFunction = 'sanit * @param mixed $log can be a string, array or object * @param bool $backtrace if set true the file-path and line of the calling file will be added to the error message * - * @return string logmessage + * @return void */ function commonsbooking_write_log( $log, $backtrace = true ) { @@ -308,6 +301,5 @@ function commonsbooking_write_log( $log, $backtrace = true ) { $logmessage = $file . ':' . $line . ' ' . $logmessage; } - error_log( $logmessage ) ; - + error_log( $logmessage ); } \ No newline at end of file diff --git a/includes/OptionsArray.php b/includes/OptionsArray.php index a49365046..53159de0d 100644 --- a/includes/OptionsArray.php +++ b/includes/OptionsArray.php @@ -672,6 +672,21 @@ ), ) ), + /* field group restriction settings start */ + 'restrictionsettings' => array( + 'title' => commonsbooking_sanitizeHTML( __( 'Restriction settings', 'commonsbooking' ) ), + 'id' => 'restrictionsettings', + 'desc' => commonsbooking_sanitizeHTML( __( 'Settings for restrictions.
More Information in the documentation', 'commonsbooking' ) ), + 'fields' => array( + array( + 'name' => commonsbooking_sanitizeHTML( __( 'Do not cancel bookings on total breakdown', 'commonsbooking' ) ), + 'id' => 'restrictions-no-cancel-on-total-breakdown', + 'type' => 'checkbox', + 'desc' => commonsbooking_sanitizeHTML( __( 'If checked, bookings will not be cancelled if the item has broken down. The user will be notified and once the item becomes available again, the old bookings are still valid.', 'commonsbooking' ) ), + ) + ) + ), + /* field group restriction settings end */ 'bookingRules' => array( 'title' => commonsbooking_sanitizeHTML( __( 'Restrict bookings by booking rules', 'commonsbooking') ), 'desc' => commonsbooking_sanitizeHTML( __( 'You can apply rules to individual items or categories of items/locations, which will restrict how users are able to book and, if violated, abort the booking process')), diff --git a/includes/Template.php b/includes/Template.php index 7b7da8a38..d51fa5476 100644 --- a/includes/Template.php +++ b/includes/Template.php @@ -81,5 +81,6 @@ function commonsbooking_get_template_part( $slug, $name = '', $include = true, $ } else if ( $template && $include === false ) { return $before_html . $template . $after_html; } + return ''; } } diff --git a/includes/TemplateParser.php b/includes/TemplateParser.php index bcebd5049..9e87a7374 100644 --- a/includes/TemplateParser.php +++ b/includes/TemplateParser.php @@ -100,9 +100,9 @@ function commonsbooking_parse_template_callback( $match, array $objects = [], $s /** * Return Custom Post Type postType for template type string * - * @param [type] $type type could be location, booking, item + * @param string $type type could be location, booking, item * - * @return void + * @return string */ function commonsbooking_getCBType( $type ) { if ( $type == 'location' ) { diff --git a/languages/commonsbooking-de_DE.mo b/languages/commonsbooking-de_DE.mo index 786983711..3be6a19b5 100644 Binary files a/languages/commonsbooking-de_DE.mo and b/languages/commonsbooking-de_DE.mo differ diff --git a/languages/commonsbooking-de_DE.po b/languages/commonsbooking-de_DE.po index 4313f4f81..9789fcdbf 100644 --- a/languages/commonsbooking-de_DE.po +++ b/languages/commonsbooking-de_DE.po @@ -8,7 +8,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "POT-Creation-Date: 2023-09-15T04:04:14+02:00\n" -"PO-Revision-Date: 2024-05-22 20:11+0200\n" +"PO-Revision-Date: 2025-01-06 18:35+0100\n" "Language: de_DE\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.4.2\n" @@ -282,7 +282,7 @@ msgid "The title of the attached event" msgstr "Der Titel des angehängten Termins" #: includes/OptionsArray.php:313 -#: includes/OptionsArray.php:1342 +#: includes/OptionsArray.php:1357 msgid "{{item:post_title}} at {{location:post_title}}" msgstr "{{item:post_title}} am Standort {{location:post_title}}." @@ -715,45 +715,45 @@ msgstr "" "

\n" " {{booking:getEmailSignature}}" -#: includes/OptionsArray.php:769 +#: includes/OptionsArray.php:784 msgid "Reminder" msgstr "Erinnerung" -#: includes/OptionsArray.php:775 +#: includes/OptionsArray.php:790 msgid "Booking reminder" msgstr "Buchungserinnerung" -#: includes/OptionsArray.php:777 +#: includes/OptionsArray.php:792 msgid "You can set here whether users should receive a reminder email before the start of a booking.
More Information in the documentation" msgstr "Hier kannst du einstellen, ob Nutzende vor Beginn einer Buchung eine Erinnerungs-E-Mail erhalten sollen.
Weitere Informationen in der Dokumentation" -#: includes/OptionsArray.php:783 -#: includes/OptionsArray.php:880 -#: includes/OptionsArray.php:916 -#: includes/OptionsArray.php:985 +#: includes/OptionsArray.php:798 +#: includes/OptionsArray.php:895 +#: includes/OptionsArray.php:931 +#: includes/OptionsArray.php:1000 msgid "Activate" msgstr "Aktivieren" -#: includes/OptionsArray.php:789 -#: includes/OptionsArray.php:886 -#: includes/OptionsArray.php:923 -#: includes/OptionsArray.php:992 +#: includes/OptionsArray.php:804 +#: includes/OptionsArray.php:901 +#: includes/OptionsArray.php:938 +#: includes/OptionsArray.php:1007 msgid "E-mail subject" msgstr "E-Mail Betreff" -#: includes/OptionsArray.php:792 -#: includes/OptionsArray.php:926 +#: includes/OptionsArray.php:807 +#: includes/OptionsArray.php:941 msgid "Upcoming booking of {{item:post_title}} {{booking:formattedBookingDate}}" msgstr "Bevorstehende Buchung von {{item:post_title}} {{booking:formattedBookingDate}}" -#: includes/OptionsArray.php:795 -#: includes/OptionsArray.php:892 -#: includes/OptionsArray.php:929 -#: includes/OptionsArray.php:998 +#: includes/OptionsArray.php:810 +#: includes/OptionsArray.php:907 +#: includes/OptionsArray.php:944 +#: includes/OptionsArray.php:1013 msgid "email body" msgstr "E-Mail-Text" -#: includes/OptionsArray.php:798 +#: includes/OptionsArray.php:813 msgid "" "

Hi {{user:first_name}},

\n" "

Your booking period for the item {{item:post_title}} will start soon.
\n" @@ -776,31 +776,31 @@ msgstr "" "\n" "{{booking:getEmailSignature}}" -#: includes/OptionsArray.php:812 +#: includes/OptionsArray.php:827 msgid "Sent reminder x days before booking start" msgstr "Sende eine Erinnerung x Tage vor Buchungsbeginn" -#: includes/OptionsArray.php:814 +#: includes/OptionsArray.php:829 msgid "This reminder email will be sent to users x days before the start of the booking. If the booking is made less days before the specified days, no reminder email will be sent" msgstr "Diese Erinnerungs-E-Mail wird x Tage vor Beginn der Buchung an Benutzende gesendet. Wenn die Buchung in weniger als den angegebenen Tagen erfolgt, wird keine Erinnerungs-E-Mail gesendet" -#: includes/OptionsArray.php:828 -#: includes/OptionsArray.php:941 -#: includes/OptionsArray.php:1011 +#: includes/OptionsArray.php:843 +#: includes/OptionsArray.php:956 +#: includes/OptionsArray.php:1026 msgid "Time" msgstr "Uhrzeit" -#: includes/OptionsArray.php:830 -#: includes/OptionsArray.php:943 -#: includes/OptionsArray.php:1013 +#: includes/OptionsArray.php:845 +#: includes/OptionsArray.php:958 +#: includes/OptionsArray.php:1028 msgid "Define when the reminder should be sent. The actual sending may differ from the defined value by a few hours, depending on how your WordPress is configured." msgstr "Lege fest, wann die Erinnerung gesendet werden soll. Der tatsächliche Versand kann um einige Stunden vom definierten Wert abweichen, je nachdem, wie dein WordPress konfiguriert ist." -#: includes/OptionsArray.php:871 +#: includes/OptionsArray.php:886 msgid "email after booking has ended" msgstr "E-Mail nach Ende der Buchung" -#: includes/OptionsArray.php:873 +#: includes/OptionsArray.php:888 msgid "" "Here you can set whether users should receive an additional e-mail after completing a booking. This can be used, for example, to inquire about the users satisfaction or possible problems during the booking.\n" "\t\t\t\t\t
The email will be sent around midnight after the booking day has ended." @@ -808,11 +808,11 @@ msgstr "" "Hier kannst Du du einstellen, ob Nutzende nach Abschluss einer Buchung eine zusätzliche E-Mail erhalten sollen. Dies kann beispielsweise genutzt werden, um sich nach der Zufriedenheit oder möglichen Problemen bei der Buchung zu erkundigen.\n" "Die E-Mail wird um Mitternacht nach Buchungsende gesendet." -#: includes/OptionsArray.php:889 +#: includes/OptionsArray.php:904 msgid "Your booking of {{item:post_title}} {{booking:formattedBookingDate}} has ended" msgstr "Deine Buchung von {{item:post_title}} {{booking:formattedBookingDate}} ist beendet" -#: includes/OptionsArray.php:895 +#: includes/OptionsArray.php:910 msgid "" "

Hi {{user:first_name}},

\n" "

Your booking of {{item:post_title}} at {{location:post_title}} has ended.
\n" @@ -825,63 +825,64 @@ msgstr "" "

Deine Buchung von {{item:post_title}} am Standort {{location:post_title}} ist beendet.
Wir hoffen, dass alles wie erwartet funktioniert hat.
Bitte lass uns uns wissen, wenn Probleme aufgetreten sind.
\n" "{{booking:getEmailSignature}}" -#: includes/OptionsArray.php:1052 +#: includes/OptionsArray.php:1067 msgid "Migration" msgstr "Migration" -#: includes/OptionsArray.php:1070 +#: includes/OptionsArray.php:1085 msgid "Migrate from Commons Booking Version 0.X" msgstr "Migriere von Commons Booking Version 0.X" -#: includes/OptionsArray.php:1072 +#: includes/OptionsArray.php:1087 msgid "Migrate data from CommonsBooking Version 0.X.
The migration includes: locations, items, timeframes and bookings.
If you have clicked \"Migrate\" before, starting the migration again will overwrite any changes you made to locations, items, timeframes and bookings.
Please read the documentation How to migrate from version 0.9.x to 2.x.x before you start migration." msgstr "Migriere Daten aus CommonsBooking Version 0.X.
Die Migration umfasst: Standorte, Artikel, Zeitrahmen und Buchungen.
Wenn du bereits zuvor \"Migrieren\" geklickt hast, startet die Migration erneut und wird alle Änderungen an Standorten, Artikeln, Zeitrahmen oder Buchungen, die du in der Zwischenzeit gemacht hast, überschreiben.
Bitte lies die Dokumentation auf Migration von Version 0.9.x auf 2.x.x., bevor Du mit der Migration beginnst." -#: includes/OptionsArray.php:1075 +#: includes/OptionsArray.php:1090 #: src/View/Migration.php:73 msgid "Start Migration" msgstr "Migration starten" -#: includes/OptionsArray.php:1086 +#: includes/OptionsArray.php:1101 msgid "CommonsBooking Version 0.X profile fields" msgstr "CommonsBooking Version 0.X Nutzerprofil-Felder" -#: includes/OptionsArray.php:1088 +#: includes/OptionsArray.php:1103 msgid "Enable the following legacy CommonsBooking Version 0.X user profile fields:" msgstr "Aktiviere die folgenden veralteten Nutzer-Profilfelder aus Commons Booking Version 0.X:" -#: includes/OptionsArray.php:1091 +#: includes/OptionsArray.php:1106 msgid "Enable" msgstr "Aktivieren" -#: includes/OptionsArray.php:1096 +#: includes/OptionsArray.php:1111 msgid "Terms & Services Url" msgstr "Nutzungsbedingungen & Services URL" -#: includes/OptionsArray.php:1105 +#: includes/OptionsArray.php:1120 msgid "Migrate bookings to new version" msgstr "Buchungen auf neue Version migrieren" -#: includes/OptionsArray.php:1107 +#: includes/OptionsArray.php:1122 msgid "Migrate bookings to new format so that they are listed at bookings menu item.
This function is only for special cases during migration. Please use it only in case of problems with migration." msgstr "Migriere Buchungen in ein neues Format, sodass diese unter dem Menüpunkt Buchungen aufgelistet werden.
Diese Funktion gilt nur für Sonderfälle während der Migration. Bitte nur bei Problemen währen der Migration verwenden. " -#: includes/OptionsArray.php:1110 -#: src/View/MassOperations.php:110 +#: includes/OptionsArray.php:1125 +#: src/View/MassOperations.php:109 #: src/View/Migration.php:107 msgid "Migrate bookings" msgstr "Buchungen migrieren" -#: includes/OptionsArray.php:1123 -#: includes/OptionsArray.php:1177 +#: includes/OptionsArray.php:1138 +#: includes/OptionsArray.php:1192 msgid "Export" msgstr "Export" -#: includes/OptionsArray.php:1127 +#: includes/OptionsArray.php:1142 msgid "Download timeframes export" msgstr "Zeitrahmen-Export herunterladen" -#: includes/OptionsArray.php:1131 +#: includes/OptionsArray.php:1146 +#: src/Wordpress/CustomPostType/Map.php:559 #: src/Wordpress/CustomPostType/Restriction.php:53 #: src/Wordpress/CustomPostType/Restriction.php:417 #: src/Wordpress/CustomPostType/Timeframe.php:100 @@ -889,205 +890,205 @@ msgstr "Zeitrahmen-Export herunterladen" msgid "Type" msgstr "Typ" -#: includes/OptionsArray.php:1132 +#: includes/OptionsArray.php:1147 msgid "Select Type of this timeframe (e.g. bookable, repair, holidays, booking). See Documentation for detailed information." msgstr "Wähle den Typ dieses Zeitrahmens (z.B. buchbar, Reparatur, Urlaub, Buchung). Ausführliche Informationen findest Du in der Dokumentation." -#: includes/OptionsArray.php:1138 +#: includes/OptionsArray.php:1153 msgid "Location-Fields" msgstr "Standort-Felder" -#: includes/OptionsArray.php:1139 -#: includes/OptionsArray.php:1146 +#: includes/OptionsArray.php:1154 +#: includes/OptionsArray.php:1161 msgid "Just add field names, no matter if its a post- or a meta-field. Comma separated list. Beside the standard post fields and standard postmeta-fields, the following custom meta fields are available. Copy only the values in [] in the field without the brackets. %s" msgstr "Fügen weitere Feldnamen hinzu, egal ob es sich um ein Post- oder ein Metafelder handelt. Kommagetrennte Liste. Neben den Standard-Postfeldern und Standard-Postmeta-Feldern stehen die folgenden benutzerdefinierten Metafelder zur Verfügung. Kopieren nur die Werte in [] in das Feld ohne die Klammern. %s" -#: includes/OptionsArray.php:1145 +#: includes/OptionsArray.php:1160 msgid "Item-Fields" msgstr "Artikel-Felder" -#: includes/OptionsArray.php:1152 +#: includes/OptionsArray.php:1167 msgid "User-Fields" msgstr "User-Felder" -#: includes/OptionsArray.php:1153 +#: includes/OptionsArray.php:1168 msgid "Just add field names, no matter if its a userfield or a meta-field. Comma separated list." msgstr "Fügen Sie einfach Feldnamen hinzu, egal ob es sich um ein Benutzerfeld oder ein Metafeld handelt. Kommagetrennte Liste." -#: includes/OptionsArray.php:1158 +#: includes/OptionsArray.php:1173 msgid "Export start date" msgstr "Export Startdatum" -#: includes/OptionsArray.php:1168 +#: includes/OptionsArray.php:1183 msgid "Export end date" msgstr "Export-Enddatum" -#: includes/OptionsArray.php:1185 +#: includes/OptionsArray.php:1200 msgid "Cron settings for timeframes export" msgstr "Cron-Einstellungen für den Zeitrahmenexport" -#: includes/OptionsArray.php:1189 +#: includes/OptionsArray.php:1204 msgid "Run as cronjob" msgstr "Als Cronjob anlegen" -#: includes/OptionsArray.php:1194 +#: includes/OptionsArray.php:1209 msgid "Export interval" msgstr "Exportintervall" -#: includes/OptionsArray.php:1198 -#: includes/OptionsArray.php:1199 +#: includes/OptionsArray.php:1213 +#: includes/OptionsArray.php:1214 msgid "minutes" msgstr "Minuten" -#: includes/OptionsArray.php:1200 +#: includes/OptionsArray.php:1215 msgid "daily" msgstr "täglich" -#: includes/OptionsArray.php:1204 +#: includes/OptionsArray.php:1219 msgid "Export timerange" msgstr "Export-Zeitbereich" -#: includes/OptionsArray.php:1205 +#: includes/OptionsArray.php:1220 msgid "Export timerange in days." msgstr "Exportiere diesen Zeitraum (in Tagen)" -#: includes/OptionsArray.php:1214 +#: includes/OptionsArray.php:1229 msgid "Filepath" msgstr "Dateipfad" -#: includes/OptionsArray.php:1215 +#: includes/OptionsArray.php:1230 msgid "Absolute path on your webserver (including trailing slash) where export file will be saved to." msgstr "Absoluter Pfad auf deinem Webserver (einschließlich abschließender Schrägstrich), in dem die Exportdatei gespeichert wird." -#: includes/OptionsArray.php:1227 -#: includes/OptionsArray.php:1255 +#: includes/OptionsArray.php:1242 +#: includes/OptionsArray.php:1270 msgid "API" msgstr "Schnittstelle" -#: includes/OptionsArray.php:1231 +#: includes/OptionsArray.php:1246 msgid "Configure API Access" msgstr "Konfigurieren des API-Zugriffs" -#: includes/OptionsArray.php:1235 +#: includes/OptionsArray.php:1250 msgid "Activate API" msgstr "API aktivieren" -#: includes/OptionsArray.php:1236 +#: includes/OptionsArray.php:1251 msgid "If selected, the API is enabled. See more information in the documentation: API documentation" msgstr "Wenn diese Option ausgewählt ist, ist die API aktiviert. Weitere Informationen in der Dokumentation: API-Dokumentation" -#: includes/OptionsArray.php:1241 +#: includes/OptionsArray.php:1256 msgid "Enable API Access without API-Key" msgstr "Aktiviert den API-Zugang ohne API-Schlüssel" -#: includes/OptionsArray.php:1242 +#: includes/OptionsArray.php:1257 msgid "If selected, the API is accessible without an API-Key. For details see: API documentation" msgstr "Wenn diese Option ausgewählt ist, ist die API ohne API-Schlüssel zugänglich. Weitere Informationen findest du unter: API-Dokumentation" -#: includes/OptionsArray.php:1249 +#: includes/OptionsArray.php:1264 msgid "API shares" msgstr "API Freigaben" -#: includes/OptionsArray.php:1250 +#: includes/OptionsArray.php:1265 msgid "You can define on or more API shares. Read the documentation for more information about API shares and configuration API documentation" msgstr "Du kannst ein oder mehrere API-Freigaben definieren. Weitere Informationen zu API-Freigaben und zur Konfiguration findest du in der API-Dokumentation" -#: includes/OptionsArray.php:1256 +#: includes/OptionsArray.php:1271 msgid "Add Another API" msgstr "Weitere API hinzufügen" -#: includes/OptionsArray.php:1257 +#: includes/OptionsArray.php:1272 msgid "Remove API" msgstr "API entfernen" -#: includes/OptionsArray.php:1264 +#: includes/OptionsArray.php:1279 msgid "API name" msgstr "Schnittstellen Name" -#: includes/OptionsArray.php:1265 +#: includes/OptionsArray.php:1280 msgid "Internal name for this API share" msgstr "Interner Name für diese API-Freigabe" -#: includes/OptionsArray.php:1270 +#: includes/OptionsArray.php:1285 msgid "API enabled" msgstr "Schnittelle aktiviert" -#: includes/OptionsArray.php:1271 +#: includes/OptionsArray.php:1286 msgid "If checked this API share is enabled" msgstr "Wenn ausgewählt, ist diese API-Freigabe aktiviert" -#: includes/OptionsArray.php:1276 +#: includes/OptionsArray.php:1291 msgid "Push URL" msgstr "Push URL" -#: includes/OptionsArray.php:1277 +#: includes/OptionsArray.php:1292 msgid "URL that gets push information everytime there was a change on CommonsBooking data" msgstr "URL, welche eine Push-Information bekommt, sobald es Änderungen den CommonsBooking Daten gibt" -#: includes/OptionsArray.php:1282 +#: includes/OptionsArray.php:1297 msgid "API Key" msgstr "API Schlüssel" -#: includes/OptionsArray.php:1285 +#: includes/OptionsArray.php:1300 msgid " You must set an API-Key. The API key should consist of alphanumeric characters and be at least 24 characters long." msgstr " Du musst einen API-Key setzen. Der API-Schlüssel sollte aus alphanumerischen Zeichen bestehen und mindestens 24 Zeichen lang sein." -#: includes/OptionsArray.php:1288 +#: includes/OptionsArray.php:1303 msgid "API Owner" msgstr "API-Besitzer" -#: includes/OptionsArray.php:1289 +#: includes/OptionsArray.php:1304 msgid "The owner value is provided by the API. It is set to the blog name by default in this version. In future versions you may be able to change this information" msgstr "Der API-Besitzer wird von der API bereitgestellt. In dieser Version ist standardmäßig der Blogname festgelegt. In zukünftigen Versionen können diese Informationen möglicherweise selbst geändert werden" -#: includes/OptionsArray.php:1309 +#: includes/OptionsArray.php:1324 msgid "Advanced Options" msgstr "Erweiterte Optionen" -#: includes/OptionsArray.php:1313 +#: includes/OptionsArray.php:1328 msgid "Set Custom metadata to locations and items" msgstr "Festlegen von benutzerdefinierten Metadaten für Standorte und Artikel" -#: includes/OptionsArray.php:1314 +#: includes/OptionsArray.php:1329 msgid "This is an advanced feature and should only be used if you are experienced or instructed how to set it up properly. In future versions we will add more detailed information and documentation." msgstr "Dies ist eine erweiterte Funktion und sollte nur verwendet werden, wenn du erfahren oder in der Konfiguration unterwiesen wurdest . In zukünftigen Versionen werden wir detailliertere Informationen und Dokumentationen hinzufügen." -#: includes/OptionsArray.php:1320 +#: includes/OptionsArray.php:1335 msgid "Meta Data" msgstr "Metadaten" -#: includes/OptionsArray.php:1321 +#: includes/OptionsArray.php:1336 msgid "" "Use only this format, separated by semicolon and each entry in a new line:
post_type(item/location);field-name;label(english),type(checkbox,number,text),description(in english)
\n" " Example: item;waterproof;Waterproof material;checkbox;\"This item is waterproof and can be used in heavy rain\" " msgstr "Verwende nur dieses Format, getrennt durch Semikolon und jeden Eintrag in einer neuen Zeile:
post_type(item/location);field-name;label(english),type(checkbox,number,text),description(in english)
Beispiel: item;wasserdicht; Wasserdichtes Material;Checkbox;\" Dieser Artikel ist wasserdicht und kann bei starkem Regen verwendet werden\" " -#: includes/OptionsArray.php:1329 +#: includes/OptionsArray.php:1344 msgid "iCalendar Feed" msgstr "iCalendar Feed" -#: includes/OptionsArray.php:1330 +#: includes/OptionsArray.php:1345 msgid "Enables users to copy a url for a dynamic iCalendar feed into their own digital calendars. This feature is experimental." msgstr "Erlaubt Nutzenden eine URL für einen dynamischen iCalendar in ihre eigenen digitalen Kalender zu kopieren. Dieses Feature ist experimentell." -#: includes/OptionsArray.php:1335 +#: includes/OptionsArray.php:1350 msgid "Enable iCalendar feed" msgstr "iCalendar Feed aktivieren" -#: includes/OptionsArray.php:1340 +#: includes/OptionsArray.php:1355 msgid "Event title" msgstr "Termin Titel" -#: includes/OptionsArray.php:1341 -#: includes/OptionsArray.php:1349 +#: includes/OptionsArray.php:1356 +#: includes/OptionsArray.php:1364 msgid "You can use template tags here as well" msgstr "Hier können auch Template Tags verwendet werden" -#: includes/OptionsArray.php:1348 +#: includes/OptionsArray.php:1363 msgid "Event description" msgstr "Terminbeschreibung" -#: includes/OptionsArray.php:1350 +#: includes/OptionsArray.php:1365 msgid "" "\n" "Pick up: {{booking:pickupDatetime}}\n" @@ -1101,32 +1102,32 @@ msgstr "" "{{location:formattedPickupInstructions}}\n" "{{booking:formattedBookingCode}} " -#: includes/OptionsArray.php:1362 +#: includes/OptionsArray.php:1377 msgid "Advanced caching settings" msgstr "Erweiterte Cachingoptionen" -#: includes/OptionsArray.php:1365 +#: includes/OptionsArray.php:1380 msgid "Allows you to change options regarding the caching system" msgstr "Erlaubt die Anpassung der Optionen für das Caching-System" -#: includes/OptionsArray.php:1374 +#: includes/OptionsArray.php:1389 msgid "Filesystem cache path" msgstr "Dateisystem-Cache Pfad" -#: includes/OptionsArray.php:1375 +#: includes/OptionsArray.php:1390 msgid "Where the filesystem cache should be created. Only change when filesystem caching is not working." msgstr "Wo der Dateisystem-Cache angelegt werden soll. Nur ändern, wenn das Dateisystem-Caching nicht funktioniert." -#: includes/OptionsArray.php:1381 -#: includes/OptionsArray.php:1398 +#: includes/OptionsArray.php:1396 +#: includes/OptionsArray.php:1413 msgid "Current connection status" msgstr "Aktueller Verbindungsstatus" -#: includes/OptionsArray.php:1387 +#: includes/OptionsArray.php:1402 msgid "Enable REDIS Caching (experimental)" msgstr "REDIS-Caching aktivieren (experimentell)" -#: includes/OptionsArray.php:1392 +#: includes/OptionsArray.php:1407 msgid "REDIS DSN (REDIS Server URL)" msgstr "REDIS DSN (REDIS-Server-URL)" @@ -1155,7 +1156,7 @@ msgid "Please enter your phone number" msgstr "Bitte gib Deine Telefonnummer ein" #: src/CB/CB1UserFields.php:90 -#: src/CB/CB1UserFields.php:280 +#: src/CB/CB1UserFields.php:281 #: src/Wordpress/CustomPostType/Location.php:219 #: templates/booking-single.php:77 msgid "Address" @@ -1182,46 +1183,22 @@ msgstr "Bitte akzeptiere die Nutzungsbedingungen" msgid "Read the terms and services" msgstr "Lies die Nutzungsbedingungen" -#: src/CB/CB1UserFields.php:268 +#: src/CB/CB1UserFields.php:269 msgid "Extra Fields" msgstr "Zusatzfelder" -#: src/CB/CB1UserFields.php:272 +#: src/CB/CB1UserFields.php:273 msgid "Phone number" msgstr "Telefonnummer" -#: src/CB/CB1UserFields.php:288 +#: src/CB/CB1UserFields.php:289 msgid "Terms and conditions" msgstr "Nutzungsbedingungen" -#: src/CB/CB1UserFields.php:294 +#: src/CB/CB1UserFields.php:295 msgid "Accepted Terms & Conditions" msgstr "Nutzungsbedingungen akzeptiert" -#: src/Map/MapAdmin.php:138 -msgid "Map Configuration" -msgstr "Karten Einstellungen" - -#: src/Map/MapAdmin.php:472 -msgid "Select an image" -msgstr "Bild auswählen" - -#: src/Map/MapAdmin.php:473 -msgid "save" -msgstr "speichern" - -#: src/Map/MapAdmin.php:474 -msgid "measurements" -msgstr "Bildmaße" - -#: src/Map/MapSettings.php:68 -msgid "Settings for Commons Booking Map" -msgstr "Einstellungen für Commons Booking Karten" - -#: src/Map/MapSettings.php:69 -msgid "Commons Booking Map" -msgstr "CommonsBooking Karte" - #: src/Map/BaseShortcode.php:36 msgid "map is not published" msgstr "Karte ist nicht veröffentlicht" @@ -1231,68 +1208,67 @@ msgstr "Karte ist nicht veröffentlicht" msgid "no valid map id provided" msgstr "keine gültige Karten-ID angegeben" -#: src/Map/MapShortcode.php:43 -#: templates/map-admin-page-template.php:230 -#: templates/map-admin-page-template.php:249 +#: src/Map/MapShortcode.php:49 msgid "opening hours" msgstr "Öffnungszeiten" -#: src/Map/MapShortcode.php:44 +#: src/Map/MapShortcode.php:50 msgid "contact" msgstr "Kontakt" -#: src/Map/MapShortcode.php:45 +#: src/Map/MapShortcode.php:51 msgid "from" msgstr "von" -#: src/Map/MapShortcode.php:46 +#: src/Map/MapShortcode.php:52 msgid "until" msgstr "bis %s" -#: src/Map/MapShortcode.php:47 +#: src/Map/MapShortcode.php:53 msgid "for at least" msgstr "mindestens" -#: src/Map/MapShortcode.php:48 +#: src/Map/MapShortcode.php:54 msgid "day(s)" msgstr "Tag(e)" -#: src/Map/MapShortcode.php:49 +#: src/Map/MapShortcode.php:55 msgid "Sorry, no locations found." msgstr "Leider wurden keine Standorte gefunden." -#: src/Map/MapShortcode.php:50 +#: src/Map/MapShortcode.php:56 +#: src/Wordpress/CustomPostType/Map.php:535 msgid "filter" msgstr "Filter" -#: src/Map/MapShortcode.php:51 -#: templates/map-admin-page-template.php:600 +#: src/Map/MapShortcode.php:57 +#: src/Wordpress/CustomPostType/Map.php:517 msgid "availability" msgstr "Verfügbarkeit" -#: src/Map/MapShortcode.php:52 -#: templates/map-admin-page-template.php:610 +#: src/Map/MapShortcode.php:58 +#: src/Wordpress/CustomPostType/Map.php:526 msgid "categories" msgstr "Kategorien" -#: src/Map/MapShortcode.php:53 -#: templates/map-admin-page-template.php:547 +#: src/Map/MapShortcode.php:59 +#: src/Wordpress/CustomPostType/Map.php:478 msgid "distance" msgstr "Entfernung" -#: src/Map/MapShortcode.php:54 +#: src/Map/MapShortcode.php:60 msgid "address" msgstr "Adresse" -#: src/Map/MapShortcode.php:55 +#: src/Map/MapShortcode.php:61 msgid "Sorry, an error occured during your request. Please try again later." msgstr "Es ist leider ein Fehler während der Anfrage aufgetreten. Versuche es später erneut." -#: src/Map/MapShortcode.php:56 +#: src/Map/MapShortcode.php:62 msgid "The service is currently not available. Please try again later." msgstr "Der Dienst ist derzeit nicht verfügbar. Versuche später erneut." -#: src/Map/MapShortcode.php:57 +#: src/Map/MapShortcode.php:63 msgid "comming soon" msgstr "Bald verfügbar" @@ -1391,42 +1367,43 @@ msgid "Location Categories" msgstr "Standort-Kategorien" #: src/Plugin.php:435 +#: src/Plugin.php:467 msgid "Item Category" msgstr "Artikel-Kategorie" -#: src/Plugin.php:467 +#: src/Plugin.php:497 msgid "Location Category" msgstr "Standort-Kategorie" -#: src/Repository/BookingCodes.php:330 +#: src/Repository/BookingCodes.php:332 msgid "No booking codes could be created because there were no booking codes to choose from. Please set some booking codes in the CommonsBooking settings." msgstr "Es konnten keine Buchungscodes erstellt werden, da keine Buchungscodes zur Auswahl standen. Bitte lege einige Buchungscodes in den CommonsBooking-Einstellungen fest." -#: src/Repository/BookingCodes.php:337 +#: src/Repository/BookingCodes.php:339 msgid "No booking codes could be created because the location of the timeframe could not be found." msgstr "Es konnten keine Buchungscodes erstellt werden, da der Standort nicht gefunden wurde." -#: src/Repository/BookingCodes.php:343 +#: src/Repository/BookingCodes.php:345 msgid "No booking codes could be created because the item of the timeframe could not be found." msgstr "Es konnten keine Buchungscodes erstellt werden, da der Artikel nicht gefunden wurde." -#: src/Service/Cache.php:302 +#: src/Service/Cache.php:303 msgid "Connection status:" msgstr "Aktueller Verbindungsstatus:" -#: src/Service/Cache.php:309 +#: src/Service/Cache.php:310 msgid "Successfully connected to REDIS database!" msgstr "Erfolgreich mit REDIS-Datenbank verbunden!" -#: src/Service/Cache.php:320 +#: src/Service/Cache.php:321 msgid "REDIS database not enabled" msgstr "REDIS-Datenbank nicht aktiviert" -#: src/Service/Cache.php:346 +#: src/Service/Cache.php:347 msgid "Directory %s is writeable." msgstr "Der Ordner %s ist beschreibbar." -#: src/Service/Cache.php:351 +#: src/Service/Cache.php:352 msgid "Directory %s could not be written to." msgstr "Der Ordner %s ist nicht beschreibbar." @@ -1462,7 +1439,7 @@ msgid "Not available" msgstr "Nicht verfügbar" #: src/View/Booking.php:193 -#: src/View/MassOperations.php:39 +#: src/View/MassOperations.php:38 #: src/Wordpress/CustomPostType/Booking.php:441 #: src/Wordpress/CustomPostType/Timeframe.php:99 #: templates/shortcode-bookings.php:73 @@ -1470,7 +1447,7 @@ msgid "User" msgstr "Nutzende*r" #: src/View/Booking.php:197 -#: src/View/MassOperations.php:43 +#: src/View/MassOperations.php:42 #: src/Wordpress/CustomPostType/Booking.php:959 #: src/Wordpress/CustomPostType/Restriction.php:472 msgid "Status" @@ -1530,19 +1507,19 @@ msgstr "Keine Buchungen im Papierkorb gefunden." msgid "No locations found." msgstr "Leider wurden keine Standorte gefunden." -#: src/View/Map.php:36 +#: src/View/Map.php:35 msgid "Set / Update GPS Coordinates" msgstr "GPS-Koordinaten abrufen / aktualisieren" -#: src/View/Map.php:40 +#: src/View/Map.php:39 msgid "Set / update GPS coordinates from address" msgstr "GPS-Koordinaten von Adresse abrufen / aktualisieren" -#: src/View/Map.php:43 +#: src/View/Map.php:42 msgid "Click this button to automatically set the GPS coordinates based on the given address and set the marker on the map.
Save or update this location after setting the gps data." msgstr "Klicke auf diese Schaltfläche, um die GPS-Koordinaten basierend auf der angegebenen Adresse automatisch abzurufen und die Markierung auf der Karte festzulegen.
Speichere oder aktualisiere diesen Standort-Eintrag, nachdem die GPS-Daten aktualisiert wurden." -#: src/View/Map.php:46 +#: src/View/Map.php:45 msgid "No GPS data could be found for the address entered.
Please check if the address is written correctly.
Alternatively, you can enter the GPS data manually into the corresponding fields." msgstr "Für die eingegebene Adresse konnten keine GPS-Daten gefunden werden.
Bitte überprüfe, ob die Adresse korrekt geschrieben ist.
Alternativ kannst du die GPS-Daten auch manuell in die entsprechenden Felder eingeben." @@ -1590,7 +1567,7 @@ msgstr " Optionen aktualisiert / gespeichert" msgid "migration in process .. please wait ...
This could take several minutes. Do not close this browser tab" msgstr "Migration wird durchgeführt .. Bitte warten...
Dies kann einige Minuten dauern. Browserfenster bitte nicht schließen" -#: src/View/MassOperations.php:100 +#: src/View/MassOperations.php:99 #: src/View/Migration.php:53 #: src/View/Migration.php:98 msgid "Migration finished" @@ -1604,12 +1581,12 @@ msgstr "Abrufen von Standort-Geokoordinaten." msgid "If this option is enabled, CommonsBooking will try to derive the matching geo-coordinates from the address data of the locations during import. We use an interface to a GeoCoder service (Nominatim) for this task. This service allows only one query per second, so the runtime of the migration is increased by 1 second per location. The geo-coordinates are needed to use the location map integrated in CommonsBooking." msgstr "Wenn diese Option aktiviert ist, versucht CommonsBooking beim Import die passenden Geo-Koordinaten aus den Adressdaten der Standorte abzuleiten. Für diese Aufgabe verwenden wir eine Schnittstelle zu einem GeoCoder-Dienst (Nominatim). Dieser Dienst erlaubt nur eine Abfrage pro Sekunde, so dass sich die Laufzeit der Migration um 1 Sekunde pro Standort erhöht. Die Geokoordinaten werden benötigt, um die in CommonsBooking integrierte Standortkarte zu nutzen." -#: src/View/MassOperations.php:95 +#: src/View/MassOperations.php:94 #: src/View/Migration.php:93 msgid "migration in process .. please wait ..." msgstr "Migration wird durchgeführt … bitte warten ..." -#: src/View/MassOperations.php:105 +#: src/View/MassOperations.php:104 #: src/View/Migration.php:103 msgid "Migration failed" msgstr "Migration fehlgeschlagen" @@ -1630,7 +1607,7 @@ msgstr "CSV Herunterladen" msgid "Download Export" msgstr "Download Export" -#: src/Model/Booking.php:998 +#: src/Model/Booking.php:1028 #: src/Service/TimeframeExport.php:523 #: src/Service/TimeframeExport.php:533 #: src/Service/TimeframeExport.php:539 @@ -2139,49 +2116,49 @@ msgstr "Wenn ausgewählt, können nicht aktivierte Tagen bei der Buchung überbu msgid "Location Meta-Data" msgstr "Standort-Metadaten" -#: src/Wordpress/CustomPostType/Map.php:369 +#: src/Wordpress/CustomPostType/Map.php:618 #: templates/dashboard-index.php:55 msgid "Maps" msgstr "Karten" -#: src/Wordpress/CustomPostType/Map.php:370 +#: src/Wordpress/CustomPostType/Map.php:619 msgid "Map" msgstr "Karte" -#: src/Wordpress/CustomPostType/Map.php:371 -#: src/Wordpress/CustomPostType/Map.php:374 +#: src/Wordpress/CustomPostType/Map.php:620 +#: src/Wordpress/CustomPostType/Map.php:623 msgid "create CB map" msgstr "CB-Karte erstellen" -#: src/Wordpress/CustomPostType/Map.php:372 +#: src/Wordpress/CustomPostType/Map.php:621 msgid "create Commons Booking map" msgstr "Commons Booking Karte erstellen" -#: src/Wordpress/CustomPostType/Map.php:373 +#: src/Wordpress/CustomPostType/Map.php:622 msgid "edit Commons Booking map" msgstr "CommonsBooking Karte bearbeiten" -#: src/Wordpress/CustomPostType/Map.php:375 +#: src/Wordpress/CustomPostType/Map.php:624 msgid "view CB map" msgstr "CB-Karte anzeigen" -#: src/Wordpress/CustomPostType/Map.php:376 +#: src/Wordpress/CustomPostType/Map.php:625 msgid "search CB maps" msgstr "CB-Karten suchen" -#: src/Wordpress/CustomPostType/Map.php:377 +#: src/Wordpress/CustomPostType/Map.php:626 msgid "no Commons Booking map found" msgstr "Keine Commons Booking Karte gefunden" -#: src/Wordpress/CustomPostType/Map.php:378 +#: src/Wordpress/CustomPostType/Map.php:627 msgid "no Commons Booking map found in the trash" msgstr "Keine Commons Booking Karte im Papierkorb gefunden" -#: src/Wordpress/CustomPostType/Map.php:379 +#: src/Wordpress/CustomPostType/Map.php:628 msgid "parent CB maps" msgstr "Übergeordnete CB-Karten" -#: src/Wordpress/CustomPostType/Map.php:408 +#: src/Wordpress/CustomPostType/Map.php:657 msgid "Maps to show Commons Booking Locations and their Items" msgstr "Karten, um CommonsBooking Standorte und deren Artikel anzuzeigen" @@ -2333,7 +2310,7 @@ msgstr "Benachrichtigungs-E-Mails an Nutzende senden" #: src/Wordpress/CustomPostType/Restriction.php:486 msgid "Important: Please save this restriction before clicking the send-button. Dependent of the status of the restriction, the appropriate notifications are sent to all affected users and location admins. You can configure the e-mail templates via Options -> Commonsbooking -> Tab Restrictions" -msgstr "Wichtig: Bitte speicher diese Einschränkung, bevor du auf den Senden-Button klickst. Abhängig vom Status der Einschränkung werden die entsprechenden Benachrichtigungen an alle betroffenen Nutzenden und Standortadministratrierende gesendet. Du kannst die E-Mail-Vorlagen über Optionen -> Commonsbooking -> Tab-Einschränkungen konfigurieren" +msgstr "Wichtig: Bitte speichere diese Einschränkung, bevor du auf den Senden-Button klickst. Abhängig vom Status der Einschränkung werden die entsprechenden Benachrichtigungen an alle betroffenen Nutzenden und Standortadministrierenden gesendet. Du kannst die E-Mail-Vorlagen über Optionen -> CommonsBooking -> Einschränkungen konfigurieren" #: src/Wordpress/CustomPostType/Restriction.php:504 msgid "Total breakdown" @@ -2824,452 +2801,319 @@ msgstr "Adresse" msgid "Location contact" msgstr "Standort-Kontakt" -#: templates/map-admin-page-template.php:9 -msgid "These settings help you to configure the usage and appearance of Commons Booking Map." -msgstr "Diese Einstellungen helfen Dir, die Verwendung und das Erscheinungsbild der CommonsBooking Karten zu konfigurieren." - -#: templates/map-admin-page-template.php:13 -msgid "Map Presentation" -msgstr "Kartendarstellung" - -#: templates/map-admin-page-template.php:17 -msgid "shortcode" -msgstr "Shortcode" - -#: templates/map-admin-page-template.php:19 -msgid "with this shortcode the map can be included in posts or pages" -msgstr "Mit diesem Shortcode kann die Karte in Beiträge oder Seiten eingebunden werden" - -#: templates/map-admin-page-template.php:25 +#: src/Wordpress/CustomPostType/Map.php:76 msgid "base map" msgstr "Basiskarte" -#: templates/map-admin-page-template.php:27 +#: src/Wordpress/CustomPostType/Map.php:77 msgid "the base map defines the rendering style of the map tiles" msgstr "Die Grundkarte definiert den Rendering-Stil der Kartenkacheln" -#: templates/map-admin-page-template.php:32 +#: src/Wordpress/CustomPostType/Map.php:81 msgid "OSM - mapnik" msgstr "OSM - mapnik" -#: templates/map-admin-page-template.php:33 +#: src/Wordpress/CustomPostType/Map.php:82 msgid "OSM - german style" msgstr "OSM - deutscher Stil" -#: templates/map-admin-page-template.php:42 +#: src/Wordpress/CustomPostType/Map.php:92 msgid "show scale" msgstr "Maßstab anzeigen" -#: templates/map-admin-page-template.php:44 -msgid "show the current scale in the left bottom corner of the map" -msgstr "Zeigen Sie den aktuellen Maßstab in der linken unteren Ecke der Karte" - -#: templates/map-admin-page-template.php:52 +#: src/Wordpress/CustomPostType/Map.php:98 msgid "map height" msgstr "Kartenhöhe" -#: templates/map-admin-page-template.php:54 +#: src/Wordpress/CustomPostType/Map.php:99 msgid "the height the map is rendered with - the width is the same as of the parent element" msgstr "Die Höhe, mit der die Karte gerendert wird - die Breite ist die gleiche wie beim übergeordneten Element" -#: templates/map-admin-page-template.php:63 +#: src/Wordpress/CustomPostType/Map.php:109 msgid "no locations message" msgstr "Meldung, wenn keine Standorte gefunden wurden" -#: templates/map-admin-page-template.php:65 +#: src/Wordpress/CustomPostType/Map.php:110 msgid "in case a user filters locations and gets no result, a message is shown - here the text can be customized" msgstr "Falls ein Benutzer Standorte filtert und kein Ergebnis erhält, wird eine Meldung angezeigt - hier kann der Text angepasst werden" -#: templates/map-admin-page-template.php:73 +#: src/Wordpress/CustomPostType/Map.php:116 msgid "enable data export" msgstr "Datenexport aktivieren" -#: templates/map-admin-page-template.php:75 +#: src/Wordpress/CustomPostType/Map.php:117 msgid "activate to enable a button that allows the export of map data (geojson format)" msgstr "Aktiviere, um eine Schaltfläche zu aktivieren, die den Export von Kartendaten ermöglicht (Geojson-Format)" -#: templates/map-admin-page-template.php:86 +#: src/Wordpress/CustomPostType/Map.php:123 msgid "Zoom" msgstr "Zoom" -#: templates/map-admin-page-template.php:90 +#: src/Wordpress/CustomPostType/Map.php:129 msgid "min. zoom level" msgstr "min. Zoomstufe" -#: templates/map-admin-page-template.php:92 +#: src/Wordpress/CustomPostType/Map.php:130 msgid "the minimal zoom level a user can choose" msgstr "die minimale Zoomstufe, die ein*e Benutzer*in auswählen kann" -#: templates/map-admin-page-template.php:100 +#: src/Wordpress/CustomPostType/Map.php:142 msgid "max. zoom level" msgstr "max. Zoomstufe" -#: templates/map-admin-page-template.php:102 +#: src/Wordpress/CustomPostType/Map.php:143 msgid "the maximal zoom level a user can choose" msgstr "die maximale Zoomstufe, die ein*e Benutzer*in auswählen kann" -#: templates/map-admin-page-template.php:110 +#: src/Wordpress/CustomPostType/Map.php:155 msgid "start zoom level" msgstr "Initiale Zoomstufe" -#: templates/map-admin-page-template.php:112 +#: src/Wordpress/CustomPostType/Map.php:156 msgid "the zoom level that will be set when the map is loaded" msgstr "die Zoomstufe, die beim Laden der Karte festgelegt wird" -#: templates/map-admin-page-template.php:120 +#: src/Wordpress/CustomPostType/Map.php:168 msgid "enable scroll wheel zoom" msgstr "Scrollradzoom aktivieren" -#: templates/map-admin-page-template.php:122 +#: src/Wordpress/CustomPostType/Map.php:169 msgid "when activated users can zoom the map using the scroll wheel" msgstr "Wenn aktiviert, können Benutzende die Karte mit dem Scrollrad zoomen" -#: templates/map-admin-page-template.php:133 -msgid "Map Positioning (center) at Intialization" -msgstr "Kartenpositionierung (Mitte) bei Initialisierung" - -#: templates/map-admin-page-template.php:137 +#: src/Wordpress/CustomPostType/Map.php:183 msgid "start latitude" msgstr "Start-Breitengrad" -#: templates/map-admin-page-template.php:139 +#: src/Wordpress/CustomPostType/Map.php:184 msgid "the latitude of the map center when the map is loaded" msgstr "der Breitengrad des Kartenzentrums, wenn die Karte geladen wird" -#: templates/map-admin-page-template.php:147 +#: src/Wordpress/CustomPostType/Map.php:190 msgid "start longitude" msgstr "Initialer Längengrad" -#: templates/map-admin-page-template.php:149 +#: src/Wordpress/CustomPostType/Map.php:191 msgid "the longitude of the map center when the map is loaded" msgstr "der Breitengrad des Kartenzentrums, wenn die Karte geladen wird" -#: templates/map-admin-page-template.php:160 -msgid "Adaptive Map Section" -msgstr "Adaptiver Kartenabschnitt" - -#: templates/map-admin-page-template.php:164 +#: src/Wordpress/CustomPostType/Map.php:197 msgid "initial adjustment to marker bounds" msgstr "anfängliche Anpassung an Markergrenzen" -#: templates/map-admin-page-template.php:166 +#: src/Wordpress/CustomPostType/Map.php:198 msgid "adjust map section to bounds of shown markers automatically when map is loaded" msgstr "Kartenabschnitt automatisch an Grenzen der angezeigten Marker anpassen, wenn die Karte geladen wird" -#: templates/map-admin-page-template.php:175 +#: src/Wordpress/CustomPostType/Map.php:204 msgid "adjustment to marker bounds on filter" msgstr "Anpassung an Markergrenzen am Filter" -#: templates/map-admin-page-template.php:177 +#: src/Wordpress/CustomPostType/Map.php:205 msgid "adjust map section to bounds of shown markers automatically when filtered by users" msgstr "Kartenabschnitt automatisch an die Grenzen der angezeigten Marker anpassen, wenn sie von Benutzern gefiltert werden" -#: templates/map-admin-page-template.php:190 +#: src/Wordpress/CustomPostType/Map.php:213 msgid "Marker Tooltip" msgstr "Kartenmarker Tooltip" -#: templates/map-admin-page-template.php:195 -msgid "show permanently" -msgstr "permanent anzeigen" - -#: templates/map-admin-page-template.php:197 +#: src/Wordpress/CustomPostType/Map.php:220 msgid "activate to show the marker tooltips permanently" msgstr "aktivieren, um die Marker-Tooltips dauerhaft anzuzeigen" -#: templates/map-admin-page-template.php:207 +#: src/Wordpress/CustomPostType/Map.php:227 msgid "Marker Popup" msgstr "Marker Popup" -#: templates/map-admin-page-template.php:215 -msgid "show location opening hours" -msgstr "zeige Standort-Öffnungszeiten" - -#: templates/map-admin-page-template.php:217 -msgid "activate to show the opening hours of locations in the marker popup" -msgstr "aktivieren, um die Öffnungszeiten der Standorte im Marker-Popup anzuzeigen" - -#: templates/map-admin-page-template.php:224 -#: templates/map-admin-page-template.php:244 -msgid "label for opening hours" -msgstr "Bezeichnung für Öffnungszeiten" - -#: templates/map-admin-page-template.php:227 -msgid "alternative label for the opening hours of locations in the marker popup" -msgstr "alternative Bezeichnung für die Öffnungszeiten der Standorte im Marker-Popup" - -#: templates/map-admin-page-template.php:235 -msgid "show location contact" -msgstr "zeige Standort-Kontakt" - -#: templates/map-admin-page-template.php:237 -msgid "activate to show the location contact details in the marker popup" -msgstr "aktivieren, um die Standortkontaktdetails im Marker-Popup anzuzeigen" - -#: templates/map-admin-page-template.php:246 -msgid "alternative label for the contact information of locations in the marker popup" -msgstr "alternative Bezeichnung für die Kontaktinformationen von Standorten im Marker-Popup" - -#: templates/map-admin-page-template.php:255 +#: src/Wordpress/CustomPostType/Map.php:233 msgid "show item availability" msgstr "Artikelverfügbarkeit anzeigen" -#: templates/map-admin-page-template.php:257 +#: src/Wordpress/CustomPostType/Map.php:234 msgid "activate to show the item availability in the marker popup" msgstr "aktivieren, um die Artikelverfügbarkeit im Marker-Popup anzuzeigen" -#: templates/map-admin-page-template.php:266 +#: src/Wordpress/CustomPostType/Map.php:239 msgid "Max. available days in popup" msgstr "Max. Anzahl verfügbare Tage im Popup" -#: templates/map-admin-page-template.php:271 +#: src/Wordpress/CustomPostType/Map.php:240 msgid "Set how many days are displayed on the popup (starting from today)" msgstr "Lege fest, wie viele Tage im Popup angezeigt werden (ab heute)" -#: templates/map-admin-page-template.php:284 +#: src/Wordpress/CustomPostType/Map.php:251 msgid "Maximum days to choose in map availabilty filter " msgstr "Maximal Anzahl an Tagen, die im Verfügbarkeitsfilter gewählt werden können " -#: templates/map-admin-page-template.php:289 +#: src/Wordpress/CustomPostType/Map.php:252 msgid "Notice: Defines the maximun days a user can choose in the availabilty filter in frontend map" msgstr "Hinweis: Definiert die maximalen Tage, die ein Benutzer im Verfügbarkeitsfilter in der Frontend-Karte auswählen kann" -#: templates/map-admin-page-template.php:303 +#: src/Wordpress/CustomPostType/Map.php:264 msgid "Custom Marker" msgstr "Benutzerdefinierter Marker" -#: templates/map-admin-page-template.php:307 -#: templates/map-admin-page-template.php:393 -#: templates/map-admin-page-template.php:468 +#: src/Wordpress/CustomPostType/Map.php:270 msgid "image file" msgstr "Bilddatei" -#: templates/map-admin-page-template.php:309 -#: templates/map-admin-page-template.php:395 -#: templates/map-admin-page-template.php:470 +#: src/Wordpress/CustomPostType/Map.php:271 +#: src/Wordpress/CustomPostType/Map.php:348 +#: src/Wordpress/CustomPostType/Map.php:404 msgid "the default marker icon can be replaced by a custom image" msgstr "Das Standardmarkersymbol kann durch ein benutzerdefiniertes Bild ersetzt werden" -#: templates/map-admin-page-template.php:313 -#: templates/map-admin-page-template.php:399 -#: templates/map-admin-page-template.php:474 -msgid "select" -msgstr "auswählen" - -#: templates/map-admin-page-template.php:315 -#: templates/map-admin-page-template.php:401 -#: templates/map-admin-page-template.php:476 -msgid "remove" -msgstr "entfernen" - -#: templates/map-admin-page-template.php:334 -#: templates/map-admin-page-template.php:420 -#: templates/map-admin-page-template.php:495 -msgid "icon size" -msgstr "Symbolgröße" - -#: templates/map-admin-page-template.php:336 -#: templates/map-admin-page-template.php:422 -#: templates/map-admin-page-template.php:497 +#: src/Wordpress/CustomPostType/Map.php:285 +#: src/Wordpress/CustomPostType/Map.php:296 +#: src/Wordpress/CustomPostType/Map.php:362 +#: src/Wordpress/CustomPostType/Map.php:373 +#: src/Wordpress/CustomPostType/Map.php:418 +#: src/Wordpress/CustomPostType/Map.php:429 msgid "the size of the custom marker icon image as it is shown on the map" msgstr "die Größe des benutzerdefinierten Markersymbolbildes, wie es auf der Karte angezeigt wird" -#: templates/map-admin-page-template.php:350 -#: templates/map-admin-page-template.php:510 +#: src/Wordpress/CustomPostType/Map.php:306 +#: src/Wordpress/CustomPostType/Map.php:316 +#: src/Wordpress/CustomPostType/Map.php:439 +#: src/Wordpress/CustomPostType/Map.php:449 msgid "anchor point" msgstr "Ankerpunkt" -#: templates/map-admin-page-template.php:352 -#: templates/map-admin-page-template.php:512 +#: src/Wordpress/CustomPostType/Map.php:307 +#: src/Wordpress/CustomPostType/Map.php:317 +#: src/Wordpress/CustomPostType/Map.php:440 +#: src/Wordpress/CustomPostType/Map.php:450 msgid "the position of the anchor point of the icon image, seen from the left top corner of the icon, often it is half of the width and full height of the icon size - this point is used to place the marker on the geo coordinates" msgstr "die Position des Ankerpunkts des Symbolbildes, von der linken oberen Ecke des Symbols aus gesehen, oft ist es die Hälfte der Breite und der vollen Höhe der Symbolgröße - dieser Punkt wird verwendet, um den Marker auf den Geo-Koordinaten zu platzieren" -#: templates/map-admin-page-template.php:369 +#: src/Wordpress/CustomPostType/Map.php:328 msgid "Cluster" msgstr "Cluster" -#: templates/map-admin-page-template.php:373 +#: src/Wordpress/CustomPostType/Map.php:334 msgid "max. cluster radius" msgstr "max. Clusterradius" -#: templates/map-admin-page-template.php:375 +#: src/Wordpress/CustomPostType/Map.php:335 msgid "combine markers to a cluster within given radius - 0 for deactivation" msgstr "Marker zu einem Cluster innerhalb eines bestimmten Radius kombinieren - 0 für die Deaktivierung" -#: templates/map-admin-page-template.php:388 +#: src/Wordpress/CustomPostType/Map.php:347 msgid "Custom Cluster Marker" msgstr "Benutzerdefinierte Cluster-Marker" -#: templates/map-admin-page-template.php:440 +#: src/Wordpress/CustomPostType/Map.php:385 msgid "Appearance by Item Status" msgstr "Darstellung nach Artikelstatus" -#: templates/map-admin-page-template.php:445 +#: src/Wordpress/CustomPostType/Map.php:391 msgid "appearance" msgstr "Erscheinen" -#: templates/map-admin-page-template.php:447 +#: src/Wordpress/CustomPostType/Map.php:392 msgid "how locations with items that are in draft status should be handled" msgstr "Wie Standorte mit Artikeln, die sich im Entwurfsstatus befinden, behandelt werden sollen" -#: templates/map-admin-page-template.php:452 +#: src/Wordpress/CustomPostType/Map.php:396 msgid "don't show drafts" msgstr "Entwürfe nicht anzeigen" -#: templates/map-admin-page-template.php:453 +#: src/Wordpress/CustomPostType/Map.php:397 msgid "show only drafts" msgstr "Nur Entwürfe anzeigen" -#: templates/map-admin-page-template.php:454 +#: src/Wordpress/CustomPostType/Map.php:398 msgid "show all together" msgstr "Alle anzeigen" -#: templates/map-admin-page-template.php:464 +#: src/Wordpress/CustomPostType/Map.php:403 msgid "Custom Item Draft Marker" msgstr "Benutzerdefinierte Artikel-Entwurfsmarkierung" -#: templates/map-admin-page-template.php:529 +#: src/Wordpress/CustomPostType/Map.php:461 msgid "Filter for Users" msgstr "Filter für Benutzer" -#: templates/map-admin-page-template.php:533 +#: src/Wordpress/CustomPostType/Map.php:467 msgid "show location distance filter" msgstr "Filter für Standort-Entfernung anzeigen" -#: templates/map-admin-page-template.php:535 +#: src/Wordpress/CustomPostType/Map.php:468 msgid "activate to show the location distance filter" msgstr "aktivieren, um den Standortentfernungsfilter anzuzeigen" -#: templates/map-admin-page-template.php:542 +#: src/Wordpress/CustomPostType/Map.php:473 msgid "label for location distance filter" msgstr "Bezeichnung für Standortentfernungsfilter" -#: templates/map-admin-page-template.php:544 +#: src/Wordpress/CustomPostType/Map.php:474 msgid "alternative label for the location distance filter" msgstr "alternative Bezeichnung für den Positionsentfernungsfilter" -#: templates/map-admin-page-template.php:552 +#: src/Wordpress/CustomPostType/Map.php:482 +#: src/Wordpress/CustomPostType/Map.php:488 msgid "address search bounds - left bottom" msgstr "Begrenzung Adresssuche - links unten" -#: templates/map-admin-page-template.php:554 -msgid "the bottom left corner of the address search bounds" -msgstr "die linke untere Ecke des Bereichs, in dem Adressen in Geokoordinaten aufgelöst werden" - -#: templates/map-admin-page-template.php:558 -#: templates/map-admin-page-template.php:575 +#: src/Wordpress/CustomPostType/Map.php:482 +#: src/Wordpress/CustomPostType/Map.php:494 msgid "longitude" msgstr "Längengrad" -#: templates/map-admin-page-template.php:562 -#: templates/map-admin-page-template.php:579 +#: src/Wordpress/CustomPostType/Map.php:488 +#: src/Wordpress/CustomPostType/Map.php:500 msgid "latitude" msgstr "Breitengrad" -#: templates/map-admin-page-template.php:569 +#: src/Wordpress/CustomPostType/Map.php:494 +#: src/Wordpress/CustomPostType/Map.php:500 msgid "address search bounds - right top" msgstr "Begrenzung Adresssuche - rechts oben" -#: templates/map-admin-page-template.php:571 -msgid "the top right corner of the address search bounds" -msgstr "die obere rechte Ecke der Adresssuchgrenzen" - -#: templates/map-admin-page-template.php:586 +#: src/Wordpress/CustomPostType/Map.php:506 msgid "show item availability filter" msgstr "Artikelverfügbarkeitsfilter anzeigen" -#: templates/map-admin-page-template.php:588 +#: src/Wordpress/CustomPostType/Map.php:507 msgid "activate to show the item availability filter" msgstr "aktivieren, um den Artikelverfügbarkeitsfilter anzuzeigen" -#: templates/map-admin-page-template.php:595 +#: src/Wordpress/CustomPostType/Map.php:512 msgid "label for item availability filter" msgstr "Bezeichnung für Artikelverfügbarkeitsfilter" -#: templates/map-admin-page-template.php:597 +#: src/Wordpress/CustomPostType/Map.php:513 msgid "alternative label for the item availability filter" msgstr "alternative Bezeichnung für den Artikelverfügbarkeitsfilter" -#: templates/map-admin-page-template.php:605 +#: src/Wordpress/CustomPostType/Map.php:521 msgid "label for item category filter" msgstr "Bezeichnung für Artikelkategoriefilter" -#: templates/map-admin-page-template.php:607 +#: src/Wordpress/CustomPostType/Map.php:522 msgid "alternative label for the item category filter" msgstr "Alternative Bezeichnung für den Artikelkategoriefilter" -#: templates/map-admin-page-template.php:616 +#: src/Wordpress/CustomPostType/Map.php:530 msgid "custom text for filter button" msgstr "Benutzerdefinierter Text für Filterschaltfläche" -#: templates/map-admin-page-template.php:618 +#: src/Wordpress/CustomPostType/Map.php:531 msgid "the text for the button used for filtering" msgstr "Der Text für die zum Filtern verwendete Schaltfläche" -#: templates/map-admin-page-template.php:626 -msgid "available categories" -msgstr "verfügbare Kategorien" - -#: templates/map-admin-page-template.php:628 -msgid "select the categories that are presented the users to filter items - none for no filters" -msgstr "Wählen Sie die Kategorien aus, die den Benutzern zum Filtern von Elementen angezeigt werden - keine für keine Filter" - -#: templates/map-admin-page-template.php:642 -msgid "grouping of and custom markup for filters" -msgstr "Gruppieren von und benutzerdefiniertem Markup für Filter" - -#: templates/map-admin-page-template.php:645 -msgid "add filter group" -msgstr "Filtergruppe hinzufügen" - -#: templates/map-admin-page-template.php:654 +#: src/Wordpress/CustomPostType/Map.php:593 msgid "Filter Item Presets" msgstr "Vorfiltern nach Artikel-Kategorie" -#: templates/map-admin-page-template.php:658 -#: templates/map-admin-page-template.php:680 -msgid "preset categories" -msgstr "voreingestellte Kategorien" - -#: templates/map-admin-page-template.php:660 +#: src/Wordpress/CustomPostType/Map.php:594 msgid "select the categories that are used to prefilter the items that are shown on the map - none for all items" msgstr "Wähle die Kategorien, die benutzt werden um die Artikel, die auf der Karte angezeigt werden, vorzufiltern - leer lassen, um alle Artikel anzuzeigen" -#: templates/map-admin-page-template.php:676 +#: src/Wordpress/CustomPostType/Map.php:601 msgid "Filter Location Presets" msgstr "Vorfiltern nach Standort-Kategorien" -#: templates/map-admin-page-template.php:682 -msgid "select the categories that are used to prefilter the location categories that are shown on the map - none for all locations" -msgstr "Wähle die Standort-Kategorien, die benutzt werden um die Artikel, die auf der Karte angezeigt werden, vorzufiltern - leer lassen, um alle Artikel anzuzeigen" - -#: templates/map-admin-page-template.php:741 -msgid "filter group" -msgstr "Filter-Gruppe" - -#: templates/map-admin-page-template.php:741 -msgid "group name" -msgstr "Filter-Gruppe" - -#: templates/map-admin-page-template.php:744 -msgid "remove filter group" -msgstr "Filter-Gruppe entfernen" - -#: templates/map-settings-page-template.php:9 -msgid "Settings for the Map" -msgstr "Karten-Einstellungen" - -#: templates/map-settings-page-template.php:11 -msgid "general settings regarding the behaviour of the Map" -msgstr "Allgemeine Einstellungen zum Verhalten der Karte" - -#: templates/map-settings-page-template.php:22 -msgid "replace map link on booking page" -msgstr "Kartenlink auf Buchungsseite ersetzen" - -#: templates/map-settings-page-template.php:23 -msgid "set the target of the map link on booking page to openstreetmap" -msgstr "Lege das Ziel des Kartenlinks auf der Buchungsseite auf openstreetmap fest" - #: templates/shortcode-bookings.php:18 msgid "No bookings available." msgstr "Keine Buchungen vorhanden." @@ -3352,7 +3196,7 @@ msgstr "Buchungen sind auf maximal %1$s Tage im Voraus beschränkt." msgid "It is not possible to access this timeframe on frontend. Please edit timeframe in backend. If you want to check the result of your timeframe settings visit the item or location in frontend to see the booking calender" msgstr "Es ist nicht möglich, diesen Zeitrahmen im Frontend abzurufen. Bitte bearbeite den Zeitrahmen im Backend. Wenn du das Ergebnis deiner Zeitrahmeneinstellungen überprüfen möchtest, rufe den Artikel oder Standort im Frontend auf, um den Buchungskalender zu sehen" -#: src/Model/Booking.php:996 +#: src/Model/Booking.php:1026 msgid "Cancelled" msgstr "Storniert" @@ -3360,8 +3204,8 @@ msgstr "Storniert" msgid "The start- and end-time of the timeframe can not be the same. Please check the full-day checkbox if you want users to be able to book the full day." msgstr "Die Start- und Endzeit des Zeitrahmens dürfen nicht gleich sein. Wenn der gesamte Tag buchbar sein soll muss die Option \"Ganzer Tag\" angewählt sein." -#: src/Plugin.php:679 -#: src/Plugin.php:694 +#: src/Plugin.php:709 +#: src/Plugin.php:724 #: src/Wordpress/CustomPostType/Booking.php:922 msgid "CommonsBooking Bookings" msgstr "CommonsBooking Buchungen" @@ -3394,11 +3238,11 @@ msgstr "Storniert am" msgid "Admin booking by" msgstr "Adminbuchung von" -#: src/Service/Upgrade.php:297 +#: src/Service/Upgrade.php:302 msgid "New features and changes: Please backup your site before upgrading!" msgstr "Neue Funktionen und Änderungen: Bitte die Website vor dem Upgrade sichern!" -#: src/Service/Upgrade.php:304 +#: src/Service/Upgrade.php:309 msgid "" "\n" "\t\t\t\t\tThis CommonsBooking update has a lot of new features and changes on some templates.
\n" @@ -3646,7 +3490,7 @@ msgstr "E-Mail mit Buchungscodes für den nächsten Monat senden" #: src/View/BookingCodes.php:316 msgid "The codes of the next month will be sent to all the location email(s), given in bold below." -msgstr "Die Codes des nächsten Monats werden an alle fettgedruckten E-Mail-Adressen der Standorte gesendet" +msgstr "Die Codes des nächsten Monats werden an alle fettgedruckten E-Mail-Adressen der Standorte gesendet." #: src/View/BookingCodes.php:318 msgid "Currently configured location email(s): " @@ -3702,7 +3546,7 @@ msgstr "Automatisches Versenden von Buchungscodes per E-Mail aktivieren" #: src/Wordpress/CustomPostType/Timeframe.php:767 msgid "First day to send Codes (List starts at next month)
(Same day will be used for subsequent messages) " -msgstr "Starttag für das regelmäßige Versenden von Codes (Liste startet im nächsten Monat)
(Der gleiche Tag wird für die folgenden Nachrichten genutzt werden)" +msgstr "Starttag für das regelmäßige Versenden von Codes (Liste startet im nächsten Monat)
(Der gleiche Tag wird für die folgenden Nachrichten genutzt werden) " #: src/Wordpress/CustomPostType/Timeframe.php:770 msgid "Months to send" @@ -3720,12 +3564,12 @@ msgstr "Nächste E-Mail geplant am: " msgid "(not planned)" msgstr "(nichts geplant)" -#: includes/OptionsArray.php:1368 -#: src/Service/Cache.php:369 +#: includes/OptionsArray.php:1383 +#: src/Service/Cache.php:370 msgid "Clear Cache" msgstr "Cache leeren" -#: src/Service/Cache.php:364 +#: src/Service/Cache.php:365 msgid "Clear all cache items" msgstr "Alle Cache-Elemente löschen" @@ -3774,67 +3618,67 @@ msgctxt "territory" msgid "State" msgstr "Bundesland" -#: includes/OptionsArray.php:676 +#: includes/OptionsArray.php:691 msgid "Restrict bookings by booking rules" msgstr "Buchungen durch Buchungsregeln beschränken" -#: includes/OptionsArray.php:681 +#: includes/OptionsArray.php:696 msgid "Count cancelled bookings towards quota" msgstr "Stornierte Buchungen mitzählen" -#: includes/OptionsArray.php:682 +#: includes/OptionsArray.php:697 msgid "Check if bookings that have been cancelled in the booking period shall be counted towards the amount of booked days for the user. More info in the documentation" msgstr "Prüft, ob die Buchungen die während der Buchungsperiode storniert wurden zu den maximal buchbaren Tagen eines Nutzenden angerechnet werden sollen. Mehr Infos dazu in der Dokumentation." -#: includes/OptionsArray.php:691 +#: includes/OptionsArray.php:706 msgid "Rule " msgstr "Regel " -#: includes/OptionsArray.php:692 +#: includes/OptionsArray.php:707 msgid "Add another rule" msgstr "Weitere Regel hinzufügen" -#: includes/OptionsArray.php:693 +#: includes/OptionsArray.php:708 msgid "Remove rule" msgstr "Regel entfernen" -#: includes/OptionsArray.php:697 +#: includes/OptionsArray.php:712 msgid "Rule type" msgstr "Regeltyp" -#: includes/OptionsArray.php:698 +#: includes/OptionsArray.php:713 msgid "Select the kind of rule" msgstr "Regel auswählen" -#: includes/OptionsArray.php:708 +#: includes/OptionsArray.php:723 msgid "Rule description" msgstr "Regelbeschreibung" -#: includes/OptionsArray.php:726 +#: includes/OptionsArray.php:741 msgid "Select an option" msgstr "Wähle eine Option" -#: includes/OptionsArray.php:732 +#: includes/OptionsArray.php:747 msgid "Applies to all" msgstr "Auf alle anwenden" -#: includes/OptionsArray.php:733 +#: includes/OptionsArray.php:748 msgid "Check if this rule applies to all items" msgstr "Wähle, ob diese Regel für alle Artikel gelten soll" -#: includes/OptionsArray.php:738 +#: includes/OptionsArray.php:753 msgid "Applies to categories" msgstr "Auf Kategorien anwenden" -#: includes/OptionsArray.php:739 +#: includes/OptionsArray.php:754 msgid "Check the categories that these rules apply to" msgstr "Wähle die Kategorien für die diese Regel gelten soll" -#: includes/OptionsArray.php:749 +#: includes/OptionsArray.php:764 msgid "Groups exempt from rule" msgstr "Befreite Nutzergruppen" -#: includes/OptionsArray.php:750 +#: includes/OptionsArray.php:765 msgid "Here you can define if the rule should not apply to a specific user group. Will apply to all groups if left empty (Administrators and item / location admins are always excluded)." msgstr "Hier kannst du festlegen, ob diese Regel NICHT für eine bestimmte Nutzendengruppe gelten soll. Die Regel gilt für alle Gruppen, wenn dieses Feld leer gelassen wird (Administratoren und Artikel/Standort Admins sind immer von der Regel ausgenommen)" @@ -3844,7 +3688,7 @@ msgstr "Gleichzeitige Buchungen unterbinden" #: src/Service/BookingRule.php:213 msgid "Users can no longer book two items on the same day." -msgstr "Nutzende können nicht mehr als einen Artikel am gleichen Tag buchen" +msgstr "Nutzende können nicht mehr als einen Artikel am gleichen Tag buchen." #: src/Service/BookingRule.php:214 msgid "You can not book more than one item at a time." @@ -3908,11 +3752,11 @@ msgstr "Maximal buchbare Tage im Zeitraum" #: src/Service/BookingRule.php:263 msgid "Allow x booked days over the period of y days for user." -msgstr "Nutzende können x Tage über einen Zeitraum von y Tagen buchen" +msgstr "Nutzende können x Tage über einen Zeitraum von y Tagen buchen." #: src/Service/BookingRule.php:264 msgid "Booking limit exceeded. " -msgstr "Buchungslimit erschöpft." +msgstr "Buchungslimit erschöpft. " #: src/Service/BookingRule.php:268 msgid "Allow x booked days" @@ -3978,7 +3822,7 @@ msgstr "Du kannst maximal %1$s Buchungen pro Monat tätigen. Bitte versuche es n #: src/Service/BookingRuleApplied.php:59 msgid "You need to specify a category, if the rule does not apply to all items" -msgstr "Du musst eine Kategorie festlegen, wenn diese Regel nicht für alle Artikel gilt." +msgstr "Du musst eine Kategorie festlegen, wenn diese Regel nicht für alle Artikel gilt" #: src/Service/BookingRuleApplied.php:79 msgid "Booking rules: Not enough parameters specified." @@ -4004,20 +3848,20 @@ msgstr "Buchungsregeln: Kein Regeltyp festgelegt." msgid "Your data" msgstr "Deine Daten" -#: includes/OptionsArray.php:908 +#: includes/OptionsArray.php:923 msgid "Reminder for locations before booking starts" msgstr "Erinnerung für Standorte vor Buchungsbeginn" -#: includes/OptionsArray.php:910 +#: includes/OptionsArray.php:925 msgid "You can set here whether locations should receive a reminder email before the start of a booking.
More Information in the documentation" msgstr "Hier kannst du einstellen, ob Standorte vor Beginn einer Buchung eine Erinnerungsmail erhalten sollen.
Weitere Informationen in der Dokumentation" -#: includes/OptionsArray.php:919 -#: includes/OptionsArray.php:988 +#: includes/OptionsArray.php:934 +#: includes/OptionsArray.php:1003 msgid "The reminders need to be enabled for all locations individually. This is only the main on/off switch." msgstr "Die Erinnerungsfunktion muss für alle Standorte einzeln aktiviert werden. Dies ist nur der Hauptschalter zum Ein- und Ausschalten." -#: includes/OptionsArray.php:932 +#: includes/OptionsArray.php:947 msgid "" "

Hi,

\n" "

The booking period for the item {{item:post_title}} at {{location:post_title}} will start soon.
\n" @@ -4033,38 +3877,38 @@ msgstr "" "\n" "{{booking:getEmailSignature}}" -#: includes/OptionsArray.php:958 -#: includes/OptionsArray.php:1029 +#: includes/OptionsArray.php:973 +#: includes/OptionsArray.php:1044 msgid "Bookings of" msgstr "Buchungen von" -#: includes/OptionsArray.php:960 +#: includes/OptionsArray.php:975 msgid "Define for which booking start day the notifications should be sent" msgstr "Definiert an welchem Tag nach vor Buchungsbeginn die Benachrichtigungen gesendet werden sollen" -#: includes/OptionsArray.php:967 -#: includes/OptionsArray.php:1038 +#: includes/OptionsArray.php:982 +#: includes/OptionsArray.php:1053 msgid "current day" msgstr "Gleicher Tag" -#: includes/OptionsArray.php:968 -#: includes/OptionsArray.php:1039 +#: includes/OptionsArray.php:983 +#: includes/OptionsArray.php:1054 msgid "next day" msgstr "Nächstem Tag" -#: includes/OptionsArray.php:977 +#: includes/OptionsArray.php:992 msgid "Reminder for locations before booking ends" msgstr "Erinnerung für Standorte vor Buchungsende" -#: includes/OptionsArray.php:979 +#: includes/OptionsArray.php:994 msgid "You can set here whether locations should receive a reminder email before the end of a booking.
More Information in the documentation" msgstr "Hier kannst du einstellen, ob Standorte vor dem Ende einer Buchung eine Erinnerungs-E-Mail erhalten sollen.
Mehr Informationen in der Dokumentation" -#: includes/OptionsArray.php:995 +#: includes/OptionsArray.php:1010 msgid "Booking of {{item:post_title}} {{booking:formattedBookingDate}}" msgstr "Buchung von {{item:post_title}} {{booking:formattedBookingDate}}" -#: includes/OptionsArray.php:1001 +#: includes/OptionsArray.php:1016 msgid "" "

Hi,

\n" "

The booking period for the item {{item:post_title}} at {{location:post_title}} will end soon.
\n" @@ -4082,7 +3926,7 @@ msgstr "" "\n" "{{booking:getEmailSignature}}" -#: includes/OptionsArray.php:1031 +#: includes/OptionsArray.php:1046 msgid "Define for which booking end day the notifications should be sent" msgstr "Definiert an welchem Tag nach Buchungsendes die Benachrichtigungen gesendet werden sollen" @@ -4127,147 +3971,139 @@ msgstr "Bitte melde dich an , um deine Buchungen zu sehe msgid "A WordPress plugin for the management and booking of common goods." msgstr "Ein WordPress-Plugin für die Verwaltung und Buchung von Gemeingütern." -#: src/Model/Booking.php:994 -#~ msgid "Unconfirmed" -#~ msgstr "Unbestätigt" - -#: src/Model/Booking.php:992 -#~ msgid "Confirmed" -#~ msgstr "Bestätigt" - #: src/Wordpress/CustomPostType/Booking.php:269 msgid "Your reservation has expired, please try to book again" -msgstr "" +msgstr "Deine Reservierung ist abgelaufen, bitte versuche erneut zu buchen" -#: includes/OptionsArray.php:1056 +#: includes/OptionsArray.php:1071 msgid "Finish upgrade to latest version" -msgstr "" +msgstr "Upgrade auf aktuelle Version beenden" -#: includes/OptionsArray.php:1058 +#: includes/OptionsArray.php:1073 msgid "Click here to finish the upgrade to the latest version.
This needs to be done after updating the plugin to a new version.
If you do not do this, the plugin may not work correctly." -msgstr "" +msgstr "Hier klicken, um das Upgrade auf die neueste Version fertig zu stellen.
Dies ist erforderlich, nachdem das Plug-in auf eine neue Version aktualisiert wurde.
Ansonsten kann es sein, dass das Plugin nicht richtig funktioniert." -#: includes/OptionsArray.php:1061 +#: includes/OptionsArray.php:1076 msgid "Finish upgrade" -msgstr "" +msgstr "Upgrade fertigstellen" -#: src/Service/Upgrade.php:133 +#: src/Service/Upgrade.php:138 msgid "There are some tasks that need to be run to complete the update process.
This needs to be done so that the plugin can function correctly." -msgstr "" +msgstr "Es gibt einige Aufgaben, die ausgeführt werden müssen, um den Aktualisierungsprozess abzuschließen.
Das ist notwendig, um die korrekte Funktionsweise des Plugins zu gewährleisten." -#: src/Service/Upgrade.php:136 +#: src/Service/Upgrade.php:141 msgid "Click here to run the upgrade tasks." -msgstr "" +msgstr "Hier klicken, um die Upgrade-Aufgaben auszuführen." #: src/View/Migration.php:120 msgid "upgrade in process .. please wait ..." -msgstr "" +msgstr "Upgrade wird durchgeführt ... bitte warten ..." #: src/View/Migration.php:125 msgid "Upgrade finished" -msgstr "" +msgstr "Upgrade beendet" #: src/View/Migration.php:129 msgid "Start Upgrade" -msgstr "" +msgstr "Upgrade starten" #: src/Service/TimeframeExport.php:89 msgid "Invalid start date" -msgstr "" +msgstr "Ungültiges Startdatum" #: src/Service/TimeframeExport.php:93 msgid "Invalid end date" -msgstr "" +msgstr "Ungültiges Enddatum" #: src/Service/TimeframeExport.php:96 msgid "Start date must not be after the end date." -msgstr "" +msgstr "Das Startdatum darf nicht nach dem Enddatum liegen." #: src/Service/TimeframeExport.php:164 #: src/View/TimeframeExport.php:39 msgid "Export finished" -msgstr "" +msgstr "Export beendet" #: src/Service/TimeframeExport.php:254 msgid "Export data is not complete. Please complete the process before trying to export." -msgstr "" +msgstr "Exportdaten konnten nicht vollständig gesammelt werden. Bitte den Vorgang abschließen, bevor der Export versucht wird." #: src/Service/TimeframeExport.php:258 msgid "No data was found for the selected time period" -msgstr "" +msgstr "Es wurden keine Daten für den gewählten Zeitraum gefunden" #: src/Service/TimeframeExport.php:263 msgid "You need to set an export path to execute the export" -msgstr "" +msgstr "Es muss ein Exportpfad angegeben werden, um den Export ausführen zu können" #: src/Service/TimeframeExport.php:364 msgid "Processed %d of %d bookings" -msgstr "" +msgstr "%d von %d Buchungen bearbeitet" #: src/View/TimeframeExport.php:32 msgid "preparing export .. please wait ..." -msgstr "" +msgstr "Export wird vorbereitet .. bitte warten ..." #: src/View/TimeframeExport.php:46 msgid "Export failed" -msgstr "" +msgstr "Export fehlgeschlagen" #: src/Exception/TimeframeInvalidException.php:12 msgid "Booking is saved as draft." -msgstr "" +msgstr "Buchung wurde als Entwurf gespeichert." #: src/Exception/TimeframeInvalidException.php:15 msgid "Timeframe is saved as draft." -msgstr "" +msgstr "Zeitrahmen wurde als Entwurf gespeichert." #: src/Model/Booking.php:613 msgid "Item not found" -msgstr "" +msgstr "Artikel nicht gefunden" #: src/Model/Booking.php:622 msgid "Location not found" -msgstr "" +msgstr "Standort nicht gefunden" #: src/Model/Booking.php:627 msgid "There is no timeframe for this booking. Please create a timeframe first." -msgstr "" +msgstr "Es existiert kein Zeitrahmen für diese Buchung. Bitte zuerst einen Zeitrahmen erstellen." #: src/Model/Booking.php:648 msgid "There are one ore more overlapping bookings within the chosen timerange" -msgstr "" +msgstr "Es gibt eine oder mehrere sich überlappende Buchungen innerhalb des gewählten Zeitraums" #: src/Model/Booking.php:649 msgid "Please adjust the start- or end-date." -msgstr "" +msgstr "Bitte passe das Start- oder Enddatum an." #: src/Model/Booking.php:650 msgid "Affected Bookings: %s" -msgstr "" +msgstr "Betroffene Buchungen: %s" #: src/Model/Timeframe.php:556 msgid "Could not get item or location. Please set a valid item and location." -msgstr "" +msgstr "Artikel oder Standort konnte nicht gefunden werden. Bitte wähle einen gültigen Artikel oder Standort." #: src/Model/Timeframe.php:563 msgid "Item or location is missing. Please set item and location." -msgstr "" +msgstr "Artikel oder Standort fehlen. Bitte Artikel und Standort festlegen." #: src/Model/Timeframe.php:574 msgid "No dates selected. Please select at least one date." -msgstr "" +msgstr "Kein Datum ausgewählt. Bitte mindestens ein Datum auswählen." #: src/Model/Timeframe.php:582 msgid "The same date was selected multiple times. Please select each date only once." -msgstr "" +msgstr "Das gleiche Datum wurde mehrere Male ausgewählt. Bitte ein Datum nur einmal auswählen." #: src/Model/Timeframe.php:591 msgid "Startdate is missing. Please enter a start date to publish this timeframe." -msgstr "" +msgstr "Das Startdatum fehlt. Ein Startdatum muss eingegeben werden, damit der Zeitrahmen veröffentlicht werden kann." #: src/View/Booking.php:538 #: src/Wordpress/CustomPostType/Booking.php:854 msgid "Submit booking" -msgstr "" +msgstr "Buchung abschicken" #: src/Wordpress/CustomPostType/Booking.php:735 msgid "" @@ -4280,18 +4116,26 @@ msgid "" "

\n" "\t\t\t\t" msgstr "" +"

Achtung

In dieser Ansicht kannst du als Administrator*in Buchungen erstellen oder ändern. Bitte nutze die Möglichkeit mit Vorsicht.
\n" +"\t\t\t\t

    \n" +"
  • Klicke auf die Vorschau-Schaltfläche auf der rechten Seite, um weitere Buchungsdetails zu sehen und die Buchung über die Schaltfläche „Stornieren“ zu stornieren.
  • \n" +"
  • Klicke auf den Buchung abschicken Knopf am Ende der Seite um die Buchung zu bestätigen.
  • \n" +"
\n" +"\t\t\t\tBitte beachte: Es werden nur grundlegende Überprüfungen gegen bestehende Buchungen durchgeführt. Bitte prüfe, ob es keine Buchungskonflikte mit anderen Buchungen gibt. \n" +"

\n" +"\t\t\t\t" #: src/Wordpress/CustomPostType/Booking.php:763 msgid "Book full day" -msgstr "" +msgstr "Ganztägig buchen" #: src/Wordpress/CustomPostType/Booking.php:766 msgid "The booking should apply to the entire day(s)" -msgstr "" +msgstr "Die Buchung soll auf den gesamten Tag / die gesamten Tage angewendet werden" #: src/Wordpress/CustomPostType/Booking.php:806 msgid "Valid booking code will be automatically retrieved for bookings that apply to the full day." -msgstr "" +msgstr "Ein gültiger Buchungscode wird automatisch für Buchungen, die sich auf den ganzen Tag beziehen, generiert." #: src/Wordpress/CustomPostType/Booking.php:815 msgid "" @@ -4299,60 +4143,224 @@ msgid "" " If the booking was made by a user via frontend booking process, the user will be shown in this field.\n" "
Notice:The user will receive a booking confirmation as soon as the booking is submitted." msgstr "" +"Wähle hier den/die Benutzende/n aus, für den/die die Buchung vorgenommen wird.
\n" +" Wenn die Buchung von einem/einer Nutzenden über den Frontend-Buchungsprozess vorgenommen wurde, wird der/die Nutzende in diesem Feld angezeigt.\n" +"
Hinweis: Der/die Nutzende erhält eine Buchungsbestätigung, sobald die Buchung abgeschickt wurde." #: src/Wordpress/CustomPostType/Booking.php:855 msgid "This will create the specified booking and send out the booking confirmation email." -msgstr "" +msgstr "Dadurch wird die angegebene Buchung erstellt und die Buchungsbestätigung per E-Mail verschickt." #: src/Plugin.php:329 #: src/Plugin.php:330 msgid "Mass Operations" -msgstr "" +msgstr "Massenverarbeitung" -#: src/Service/MassOperations.php:43 +#: src/Service/MassOperations.php:52 msgid "No bookings to move selected." -msgstr "" +msgstr "Keine Buchungen zum Umzug ausgewählt." -#: src/Service/MassOperations.php:68 +#: src/Service/MassOperations.php:28 msgid "All selected orphaned bookings have been migrated." -msgstr "" +msgstr "Alle ausgewählten verwaisten Buchungen sind migriert worden." -#: src/View/MassOperations.php:38 +#: src/View/MassOperations.php:37 msgid "ID" -msgstr "" +msgstr "ID" -#: src/View/MassOperations.php:40 +#: src/View/MassOperations.php:39 msgid "Item name" -msgstr "" +msgstr "Artikelname" -#: src/View/MassOperations.php:41 +#: src/View/MassOperations.php:40 msgid "Start-date" -msgstr "" +msgstr "Startdatum" -#: src/View/MassOperations.php:42 +#: src/View/MassOperations.php:41 msgid "End-date" -msgstr "" +msgstr "Enddatum" -#: src/View/MassOperations.php:44 +#: src/View/MassOperations.php:43 msgid "Location name" -msgstr "" +msgstr "Standortname" -#: src/View/MassOperations.php:45 +#: src/View/MassOperations.php:44 msgid "New location name" -msgstr "" +msgstr "Name des neuen Standorts" #: src/Wordpress/CustomPostType/Timeframe.php:932 msgid "Orphaned bookings found, can migrate. Click here to migrate " -msgstr "" +msgstr "Verwaiste Buchungen gefunden, können migriert werden. Hier klicken um zu migrieren " #: templates/massoperations-index.php:7 msgid "Migrate orphaned bookings" -msgstr "" +msgstr "Verwaiste Buchungen migrieren" -#: src/Service/MassOperations.php:62 +#: src/Service/MassOperations.php:64 +#: src/Service/MassOperations.php:67 msgid "New location not found for booking with ID %s" -msgstr "" +msgstr "Neuer Standort für Buchung mit ID %s konnte nicht gefunden werden" #: src/Wordpress/Options/OptionsTab.php:175 msgid "Error while clearing the cache." -msgstr "" +msgstr "Fehler beim Leeren des Caches." + +#: includes/OptionsArray.php:677 +msgid "Restriction settings" +msgstr "Einstellungen für Einschränkungen" + +#: includes/OptionsArray.php:679 +msgid "Settings for restrictions.
More Information in the documentation" +msgstr "Einstellungen für Einschränkungen.
Mehr Informationen in der Dokumentation" + +#: includes/OptionsArray.php:682 +msgid "Do not cancel bookings on total breakdown" +msgstr "Buchungen bei Totalausfall nicht stornieren" + +#: includes/OptionsArray.php:685 +msgid "If checked, bookings will not be cancelled if the item has broken down. The user will be notified and once the item becomes available again, the old bookings are still valid." +msgstr "Wenn ausgewählt, werden Buchungen nicht storniert, wenn ein Totalausfall für den Artikel gesetzt ist. Der / die Benutzer*in wird benachrichtigt und sobald der Artikel wieder verfügbar ist, sind die alten Buchungen weiterhin gültig." + +#: src/Plugin.php:476 +msgid "Add custom title for filter" +msgstr "Benutzerdefinierten Titel für Filtergruppe hinzufügen" + +#: src/Plugin.php:479 +msgid "Define name that should be used for the category if it is displayed in the map as a filter group. You can also use this to add custom HTML to the category name. When left empty, the defined name of the category will be used." +msgstr "Legt den Namen fest, der für die Kategorie verwendet werden soll, wenn sie in der Karte als Teil der Filtergruppe angezeigt wird. Hier kann auch benutzerdefinierter HTML-Code zum Kategorienamen hinzugefügt werden. Bleibt der Eintrag leer, wird der Standard Name der Kategorie verwendet." + +#: src/Wordpress/CustomPostType/Map.php:45 +msgid "Map settings" +msgstr "Karteneinstellungen" + +#: src/Wordpress/CustomPostType/Map.php:59 +msgid "These settings help you to configure the usage and appearance of Commons Booking Map" +msgstr "Mit diesen Einstellungen kann die Handhabung und das Aussehen der Commons Booking Karte konfiguriert werden" + +#: src/Wordpress/CustomPostType/Map.php:70 +msgid "Presentation" +msgstr "Darstellung" + +#: src/Wordpress/CustomPostType/Map.php:93 +msgid "show the current scale in the bottom left corner of the map" +msgstr "den aktuellen Maßstab in der unteren linken Ecke der Karte anzeigen" + +#: src/Wordpress/CustomPostType/Map.php:113 +msgid "No locations found" +msgstr "Keine Standorte gefunden" + +#: src/Wordpress/CustomPostType/Map.php:177 +msgid "Positioning" +msgstr "Positionierung" + +#: src/Wordpress/CustomPostType/Map.php:219 +msgid "Show marker tooltip permanently" +msgstr "Marker-Tooltip dauerhaft anzeigen" + +#: src/Wordpress/CustomPostType/Map.php:284 +#: src/Wordpress/CustomPostType/Map.php:361 +#: src/Wordpress/CustomPostType/Map.php:417 +msgid "icon width" +msgstr "Icon-Breite" + +#: src/Wordpress/CustomPostType/Map.php:295 +#: src/Wordpress/CustomPostType/Map.php:372 +#: src/Wordpress/CustomPostType/Map.php:428 +msgid "icon height" +msgstr "Icon-Höhe" + +#: src/Wordpress/CustomPostType/Map.php:483 +msgid "defines the bounds of the address search - set the longitude of the left bottom corner of the bounding box" +msgstr "definiert die Grenzen der Adressensuche - legt den Längengrad der linken unteren Ecke des Begrenzungsrahmens fest" + +#: src/Wordpress/CustomPostType/Map.php:489 +msgid "defines the bounds of the address search - set the bottom left corner of the bounding box" +msgstr "definiert die Grenzen der Adressensuche - legt die linke untere Ecke des Begrenzungsrahmens fest" + +#: src/Wordpress/CustomPostType/Map.php:495 +msgid "defines the bounds of the address search - set the longitude of the right top corner of the bounding box" +msgstr "definiert die Grenzen der Adressensuche - legt den Längengrad der rechten oberen Ecke des Begrenzungsrahmens fest" + +#: src/Wordpress/CustomPostType/Map.php:501 +msgid "defines the bounds of the address search - set the latitude of the right top corner of the bounding box" +msgstr "definiert die Grenzen der Adressensuche - legt den Breitengrad der rechten oberen Ecke des Begrenzungsrahmens fest" + +#: src/Wordpress/CustomPostType/Map.php:539 +msgid "Filter groups" +msgstr "Filtergruppen" + +#: src/Wordpress/CustomPostType/Map.php:540 +msgid "Filter groups can group item or location categories together to allow for filtering in the map." +msgstr "Filtergruppen können Artikel- oder Standortkategorien gruppieren, um eine Filterung auf der Karte zu ermöglichen." + +#: src/Wordpress/CustomPostType/Map.php:545 +msgid "Filter group {#}" +msgstr "Filtergruppe {#}" + +#: src/Wordpress/CustomPostType/Map.php:546 +msgid "Add another filter group" +msgstr "Weitere Filtergruppe hinzufügen" + +#: src/Wordpress/CustomPostType/Map.php:547 +msgid "Remove filter group" +msgstr "Filtergruppe entfernen" + +#: src/Wordpress/CustomPostType/Map.php:552 +msgid "Name" +msgstr "Name" + +#: src/Wordpress/CustomPostType/Map.php:555 +msgid "The name of the filter group" +msgstr "Der Name der Filtergruppe" + +#: src/Wordpress/CustomPostType/Map.php:562 +msgid "This is not available yet. Which data source should be used for the filter group. Taxonomy stands for the assigned categories, post-meta can be individually configured custom fields for item posts. When this item field contains data, it will be included. If it does not contain data or does not exist, the item will be excluded." +msgstr "Das ist noch nicht verfügbar. Welche Datenquelle soll für die Filtergruppe verwendet werden. Taxonomie steht für die zugeordneten Kategorien, Post-Meta können individuell konfigurierte benutzerdefinierte Felder für Artikel-Posts sein. Wenn dieses Feld des Artikels Daten enthält, wird es einbezogen. Wenn es keine Daten enthält oder nicht vorhanden ist, wird der Artikel ausgeschlossen." + +#: src/Wordpress/CustomPostType/Map.php:564 +msgid "Taxonomy" +msgstr "Taxonomie" + +#: src/Wordpress/CustomPostType/Map.php:565 +msgid "Post-meta" +msgstr "Post-Meta" + +#: src/Wordpress/CustomPostType/Map.php:574 +msgid "Exclusive selection" +msgstr "Ausschließende Auswahl" + +#: src/Wordpress/CustomPostType/Map.php:577 +msgid "WARNING: This feature is only available for the cb_search shortcode, not for cb_map. If checked, only one category can be selected in this filter group. If unchecked, multiple categories can be selected." +msgstr "WARNUNG: Diese Funktion ist nur für den Shortcode cb_search verfügbar, nicht für cb_map. Wenn diese Funktion aktiviert ist, kann nur eine Kategorie in dieser Filtergruppe ausgewählt werden. Wenn sie nicht markiert ist, können mehrere Kategorien ausgewählt werden." + +#: src/Wordpress/CustomPostType/Map.php:580 +msgid "Categories" +msgstr "Kategorien" + +#: src/Wordpress/CustomPostType/Map.php:583 +msgid "The categories to be included in the filter group" +msgstr "Die Kategorien, die in die Filtergruppe aufgenommen werden sollen" + +#: src/Wordpress/CustomPostType/Map.php:602 +msgid "select the categories that are used to prefilter the locations that are shown on the map - none for all locations" +msgstr "wähle die Kategorie, nach der die auf der Karte angezeigten Standorte vorgefiltert werden sollen - leer lassen für alle Standorte" + +#: src/Wordpress/CustomPostType/Map.php:680 +msgid "Copy to clipboard" +msgstr "In Zwischenablage kopieren" + +#: src/Service/MassOperations.php:33 +msgid "An error occurred while moving bookings." +msgstr "Beim Umziehen der Buchungen ist ein Fehler aufgetreten." + +#: src/Service/MassOperations.php:70 +msgid "There is already a booking on the new location during the timeframe of booking with ID %s." +msgstr "Es existiert bereits eine Buchung für den Standort in dem Zeitraum der existierenden Buchung mit der ID %s." + +#: src/Model/Booking.php:1024 +#~ msgid "Unconfirmed" +#~ msgstr "Unbestätigt" + +#: src/Model/Booking.php:1022 +#~ msgid "Confirmed" +#~ msgstr "Bestätigt" diff --git a/languages/commonsbooking.pot b/languages/commonsbooking.pot index 26cfcf107..18adf4322 100644 --- a/languages/commonsbooking.pot +++ b/languages/commonsbooking.pot @@ -1,15 +1,15 @@ -# Copyright (C) 2024 wielebenwir e.V. +# Copyright (C) 2025 wielebenwir e.V. # This file is distributed under the GPL v2 or later. msgid "" msgstr "" -"Project-Id-Version: Commons Booking 2.9.4\n" +"Project-Id-Version: Commons Booking 2.10.2\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/commonsbooking\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2024-12-02T14:15:17+00:00\n" +"POT-Creation-Date: 2025-01-14T16:53:50+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.11.0\n" "X-Domain: commonsbooking\n" @@ -315,7 +315,7 @@ msgid "The title of the attached event" msgstr "" #: includes/OptionsArray.php:313 -#: includes/OptionsArray.php:1342 +#: includes/OptionsArray.php:1357 msgid "{{item:post_title}} at {{location:post_title}}" msgstr "" @@ -697,109 +697,125 @@ msgid "" " {{booking:getEmailSignature}}" msgstr "" -#: includes/OptionsArray.php:676 +#: includes/OptionsArray.php:677 +msgid "Restriction settings" +msgstr "" + +#: includes/OptionsArray.php:679 +msgid "Settings for restrictions.
More Information in the documentation" +msgstr "" + +#: includes/OptionsArray.php:682 +msgid "Do not cancel bookings on total breakdown" +msgstr "" + +#: includes/OptionsArray.php:685 +msgid "If checked, bookings will not be cancelled if the item has broken down. The user will be notified and once the item becomes available again, the old bookings are still valid." +msgstr "" + +#: includes/OptionsArray.php:691 msgid "Restrict bookings by booking rules" msgstr "" -#: includes/OptionsArray.php:681 +#: includes/OptionsArray.php:696 msgid "Count cancelled bookings towards quota" msgstr "" -#: includes/OptionsArray.php:682 +#: includes/OptionsArray.php:697 msgid "Check if bookings that have been cancelled in the booking period shall be counted towards the amount of booked days for the user. More info in the documentation" msgstr "" -#: includes/OptionsArray.php:691 +#: includes/OptionsArray.php:706 msgid "Rule " msgstr "" -#: includes/OptionsArray.php:692 +#: includes/OptionsArray.php:707 msgid "Add another rule" msgstr "" -#: includes/OptionsArray.php:693 +#: includes/OptionsArray.php:708 msgid "Remove rule" msgstr "" -#: includes/OptionsArray.php:697 +#: includes/OptionsArray.php:712 msgid "Rule type" msgstr "" -#: includes/OptionsArray.php:698 +#: includes/OptionsArray.php:713 msgid "Select the kind of rule" msgstr "" -#: includes/OptionsArray.php:708 +#: includes/OptionsArray.php:723 msgid "Rule description" msgstr "" -#: includes/OptionsArray.php:726 +#: includes/OptionsArray.php:741 msgid "Select an option" msgstr "" -#: includes/OptionsArray.php:732 +#: includes/OptionsArray.php:747 msgid "Applies to all" msgstr "" -#: includes/OptionsArray.php:733 +#: includes/OptionsArray.php:748 msgid "Check if this rule applies to all items" msgstr "" -#: includes/OptionsArray.php:738 +#: includes/OptionsArray.php:753 msgid "Applies to categories" msgstr "" -#: includes/OptionsArray.php:739 +#: includes/OptionsArray.php:754 msgid "Check the categories that these rules apply to" msgstr "" -#: includes/OptionsArray.php:749 +#: includes/OptionsArray.php:764 msgid "Groups exempt from rule" msgstr "" -#: includes/OptionsArray.php:750 +#: includes/OptionsArray.php:765 msgid "Here you can define if the rule should not apply to a specific user group. Will apply to all groups if left empty (Administrators and item / location admins are always excluded)." msgstr "" -#: includes/OptionsArray.php:769 +#: includes/OptionsArray.php:784 msgid "Reminder" msgstr "" -#: includes/OptionsArray.php:775 +#: includes/OptionsArray.php:790 msgid "Booking reminder" msgstr "" -#: includes/OptionsArray.php:777 +#: includes/OptionsArray.php:792 msgid "You can set here whether users should receive a reminder email before the start of a booking.
More Information in the documentation" msgstr "" -#: includes/OptionsArray.php:783 -#: includes/OptionsArray.php:880 -#: includes/OptionsArray.php:916 -#: includes/OptionsArray.php:985 +#: includes/OptionsArray.php:798 +#: includes/OptionsArray.php:895 +#: includes/OptionsArray.php:931 +#: includes/OptionsArray.php:1000 msgid "Activate" msgstr "" -#: includes/OptionsArray.php:789 -#: includes/OptionsArray.php:886 -#: includes/OptionsArray.php:923 -#: includes/OptionsArray.php:992 +#: includes/OptionsArray.php:804 +#: includes/OptionsArray.php:901 +#: includes/OptionsArray.php:938 +#: includes/OptionsArray.php:1007 msgid "E-mail subject" msgstr "" -#: includes/OptionsArray.php:792 -#: includes/OptionsArray.php:926 +#: includes/OptionsArray.php:807 +#: includes/OptionsArray.php:941 msgid "Upcoming booking of {{item:post_title}} {{booking:formattedBookingDate}}" msgstr "" -#: includes/OptionsArray.php:795 -#: includes/OptionsArray.php:892 -#: includes/OptionsArray.php:929 -#: includes/OptionsArray.php:998 +#: includes/OptionsArray.php:810 +#: includes/OptionsArray.php:907 +#: includes/OptionsArray.php:944 +#: includes/OptionsArray.php:1013 msgid "email body" msgstr "" -#: includes/OptionsArray.php:798 +#: includes/OptionsArray.php:813 msgid "" "

Hi {{user:first_name}},

\n" "

Your booking period for the item {{item:post_title}} will start soon.
\n" @@ -813,41 +829,41 @@ msgid "" "{{booking:getEmailSignature}}" msgstr "" -#: includes/OptionsArray.php:812 +#: includes/OptionsArray.php:827 msgid "Sent reminder x days before booking start" msgstr "" -#: includes/OptionsArray.php:814 +#: includes/OptionsArray.php:829 msgid "This reminder email will be sent to users x days before the start of the booking. If the booking is made less days before the specified days, no reminder email will be sent" msgstr "" -#: includes/OptionsArray.php:828 -#: includes/OptionsArray.php:941 -#: includes/OptionsArray.php:1011 +#: includes/OptionsArray.php:843 +#: includes/OptionsArray.php:956 +#: includes/OptionsArray.php:1026 msgid "Time" msgstr "" -#: includes/OptionsArray.php:830 -#: includes/OptionsArray.php:943 -#: includes/OptionsArray.php:1013 +#: includes/OptionsArray.php:845 +#: includes/OptionsArray.php:958 +#: includes/OptionsArray.php:1028 msgid "Define when the reminder should be sent. The actual sending may differ from the defined value by a few hours, depending on how your WordPress is configured." msgstr "" -#: includes/OptionsArray.php:871 +#: includes/OptionsArray.php:886 msgid "email after booking has ended" msgstr "" -#: includes/OptionsArray.php:873 +#: includes/OptionsArray.php:888 msgid "" "Here you can set whether users should receive an additional e-mail after completing a booking. This can be used, for example, to inquire about the users satisfaction or possible problems during the booking.\n" "\t\t\t\t\t
The email will be sent around midnight after the booking day has ended." msgstr "" -#: includes/OptionsArray.php:889 +#: includes/OptionsArray.php:904 msgid "Your booking of {{item:post_title}} {{booking:formattedBookingDate}} has ended" msgstr "" -#: includes/OptionsArray.php:895 +#: includes/OptionsArray.php:910 msgid "" "

Hi {{user:first_name}},

\n" "

Your booking of {{item:post_title}} at {{location:post_title}} has ended.
\n" @@ -857,20 +873,20 @@ msgid "" "{{booking:getEmailSignature}}" msgstr "" -#: includes/OptionsArray.php:908 +#: includes/OptionsArray.php:923 msgid "Reminder for locations before booking starts" msgstr "" -#: includes/OptionsArray.php:910 +#: includes/OptionsArray.php:925 msgid "You can set here whether locations should receive a reminder email before the start of a booking.
More Information in the documentation" msgstr "" -#: includes/OptionsArray.php:919 -#: includes/OptionsArray.php:988 +#: includes/OptionsArray.php:934 +#: includes/OptionsArray.php:1003 msgid "The reminders need to be enabled for all locations individually. This is only the main on/off switch." msgstr "" -#: includes/OptionsArray.php:932 +#: includes/OptionsArray.php:947 msgid "" "

Hi,

\n" "

The booking period for the item {{item:post_title}} at {{location:post_title}} will start soon.
\n" @@ -880,38 +896,38 @@ msgid "" "{{booking:getEmailSignature}}" msgstr "" -#: includes/OptionsArray.php:958 -#: includes/OptionsArray.php:1029 +#: includes/OptionsArray.php:973 +#: includes/OptionsArray.php:1044 msgid "Bookings of" msgstr "" -#: includes/OptionsArray.php:960 +#: includes/OptionsArray.php:975 msgid "Define for which booking start day the notifications should be sent" msgstr "" -#: includes/OptionsArray.php:967 -#: includes/OptionsArray.php:1038 +#: includes/OptionsArray.php:982 +#: includes/OptionsArray.php:1053 msgid "current day" msgstr "" -#: includes/OptionsArray.php:968 -#: includes/OptionsArray.php:1039 +#: includes/OptionsArray.php:983 +#: includes/OptionsArray.php:1054 msgid "next day" msgstr "" -#: includes/OptionsArray.php:977 +#: includes/OptionsArray.php:992 msgid "Reminder for locations before booking ends" msgstr "" -#: includes/OptionsArray.php:979 +#: includes/OptionsArray.php:994 msgid "You can set here whether locations should receive a reminder email before the end of a booking.
More Information in the documentation" msgstr "" -#: includes/OptionsArray.php:995 +#: includes/OptionsArray.php:1010 msgid "Booking of {{item:post_title}} {{booking:formattedBookingDate}}" msgstr "" -#: includes/OptionsArray.php:1001 +#: includes/OptionsArray.php:1016 msgid "" "

Hi,

\n" "

The booking period for the item {{item:post_title}} at {{location:post_title}} will end soon.
\n" @@ -922,79 +938,80 @@ msgid "" "{{booking:getEmailSignature}}" msgstr "" -#: includes/OptionsArray.php:1031 +#: includes/OptionsArray.php:1046 msgid "Define for which booking end day the notifications should be sent" msgstr "" -#: includes/OptionsArray.php:1052 +#: includes/OptionsArray.php:1067 msgid "Migration" msgstr "" -#: includes/OptionsArray.php:1056 +#: includes/OptionsArray.php:1071 msgid "Finish upgrade to latest version" msgstr "" -#: includes/OptionsArray.php:1058 +#: includes/OptionsArray.php:1073 msgid "Click here to finish the upgrade to the latest version.
This needs to be done after updating the plugin to a new version.
If you do not do this, the plugin may not work correctly." msgstr "" -#: includes/OptionsArray.php:1061 +#: includes/OptionsArray.php:1076 msgid "Finish upgrade" msgstr "" -#: includes/OptionsArray.php:1070 +#: includes/OptionsArray.php:1085 msgid "Migrate from Commons Booking Version 0.X" msgstr "" -#: includes/OptionsArray.php:1072 +#: includes/OptionsArray.php:1087 msgid "Migrate data from CommonsBooking Version 0.X.
The migration includes: locations, items, timeframes and bookings.
If you have clicked \"Migrate\" before, starting the migration again will overwrite any changes you made to locations, items, timeframes and bookings.
Please read the documentation How to migrate from version 0.9.x to 2.x.x before you start migration." msgstr "" -#: includes/OptionsArray.php:1075 +#: includes/OptionsArray.php:1090 #: src/View/Migration.php:73 msgid "Start Migration" msgstr "" -#: includes/OptionsArray.php:1086 +#: includes/OptionsArray.php:1101 msgid "CommonsBooking Version 0.X profile fields" msgstr "" -#: includes/OptionsArray.php:1088 +#: includes/OptionsArray.php:1103 msgid "Enable the following legacy CommonsBooking Version 0.X user profile fields:" msgstr "" -#: includes/OptionsArray.php:1091 +#: includes/OptionsArray.php:1106 msgid "Enable" msgstr "" -#: includes/OptionsArray.php:1096 +#: includes/OptionsArray.php:1111 msgid "Terms & Services Url" msgstr "" -#: includes/OptionsArray.php:1105 +#: includes/OptionsArray.php:1120 msgid "Migrate bookings to new version" msgstr "" -#: includes/OptionsArray.php:1107 +#: includes/OptionsArray.php:1122 msgid "Migrate bookings to new format so that they are listed at bookings menu item.
This function is only for special cases during migration. Please use it only in case of problems with migration." msgstr "" -#: includes/OptionsArray.php:1110 -#: src/View/MassOperations.php:110 +#: includes/OptionsArray.php:1125 +#: src/View/MassOperations.php:109 #: src/View/Migration.php:107 msgid "Migrate bookings" msgstr "" -#: includes/OptionsArray.php:1123 -#: includes/OptionsArray.php:1177 +#: includes/OptionsArray.php:1138 +#: includes/OptionsArray.php:1192 msgid "Export" msgstr "" -#: includes/OptionsArray.php:1127 +#: includes/OptionsArray.php:1142 msgid "Download timeframes export" msgstr "" -#: includes/OptionsArray.php:1131 +#: includes/OptionsArray.php:1146 +#: src/Wordpress/CustomPostType/Map.php:559 #: src/Wordpress/CustomPostType/Restriction.php:53 #: src/Wordpress/CustomPostType/Restriction.php:417 #: src/Wordpress/CustomPostType/Timeframe.php:100 @@ -1002,205 +1019,205 @@ msgstr "" msgid "Type" msgstr "" -#: includes/OptionsArray.php:1132 +#: includes/OptionsArray.php:1147 msgid "Select Type of this timeframe (e.g. bookable, repair, holidays, booking). See Documentation for detailed information." msgstr "" -#: includes/OptionsArray.php:1138 +#: includes/OptionsArray.php:1153 msgid "Location-Fields" msgstr "" -#: includes/OptionsArray.php:1139 -#: includes/OptionsArray.php:1146 +#: includes/OptionsArray.php:1154 +#: includes/OptionsArray.php:1161 msgid "Just add field names, no matter if its a post- or a meta-field. Comma separated list. Beside the standard post fields and standard postmeta-fields, the following custom meta fields are available. Copy only the values in [] in the field without the brackets. %s" msgstr "" -#: includes/OptionsArray.php:1145 +#: includes/OptionsArray.php:1160 msgid "Item-Fields" msgstr "" -#: includes/OptionsArray.php:1152 +#: includes/OptionsArray.php:1167 msgid "User-Fields" msgstr "" -#: includes/OptionsArray.php:1153 +#: includes/OptionsArray.php:1168 msgid "Just add field names, no matter if its a userfield or a meta-field. Comma separated list." msgstr "" -#: includes/OptionsArray.php:1158 +#: includes/OptionsArray.php:1173 msgid "Export start date" msgstr "" -#: includes/OptionsArray.php:1168 +#: includes/OptionsArray.php:1183 msgid "Export end date" msgstr "" -#: includes/OptionsArray.php:1185 +#: includes/OptionsArray.php:1200 msgid "Cron settings for timeframes export" msgstr "" -#: includes/OptionsArray.php:1189 +#: includes/OptionsArray.php:1204 msgid "Run as cronjob" msgstr "" -#: includes/OptionsArray.php:1194 +#: includes/OptionsArray.php:1209 msgid "Export interval" msgstr "" -#: includes/OptionsArray.php:1198 -#: includes/OptionsArray.php:1199 +#: includes/OptionsArray.php:1213 +#: includes/OptionsArray.php:1214 msgid "minutes" msgstr "" -#: includes/OptionsArray.php:1200 +#: includes/OptionsArray.php:1215 msgid "daily" msgstr "" -#: includes/OptionsArray.php:1204 +#: includes/OptionsArray.php:1219 msgid "Export timerange" msgstr "" -#: includes/OptionsArray.php:1205 +#: includes/OptionsArray.php:1220 msgid "Export timerange in days." msgstr "" -#: includes/OptionsArray.php:1214 +#: includes/OptionsArray.php:1229 msgid "Filepath" msgstr "" -#: includes/OptionsArray.php:1215 +#: includes/OptionsArray.php:1230 msgid "Absolute path on your webserver (including trailing slash) where export file will be saved to." msgstr "" -#: includes/OptionsArray.php:1227 -#: includes/OptionsArray.php:1255 +#: includes/OptionsArray.php:1242 +#: includes/OptionsArray.php:1270 msgid "API" msgstr "" -#: includes/OptionsArray.php:1231 +#: includes/OptionsArray.php:1246 msgid "Configure API Access" msgstr "" -#: includes/OptionsArray.php:1235 +#: includes/OptionsArray.php:1250 msgid "Activate API" msgstr "" -#: includes/OptionsArray.php:1236 +#: includes/OptionsArray.php:1251 msgid "If selected, the API is enabled. See more information in the documentation: API documentation" msgstr "" -#: includes/OptionsArray.php:1241 +#: includes/OptionsArray.php:1256 msgid "Enable API Access without API-Key" msgstr "" -#: includes/OptionsArray.php:1242 +#: includes/OptionsArray.php:1257 msgid "If selected, the API is accessible without an API-Key. For details see: API documentation" msgstr "" -#: includes/OptionsArray.php:1249 +#: includes/OptionsArray.php:1264 msgid "API shares" msgstr "" -#: includes/OptionsArray.php:1250 +#: includes/OptionsArray.php:1265 msgid "You can define on or more API shares. Read the documentation for more information about API shares and configuration API documentation" msgstr "" -#: includes/OptionsArray.php:1256 +#: includes/OptionsArray.php:1271 msgid "Add Another API" msgstr "" -#: includes/OptionsArray.php:1257 +#: includes/OptionsArray.php:1272 msgid "Remove API" msgstr "" -#: includes/OptionsArray.php:1264 +#: includes/OptionsArray.php:1279 msgid "API name" msgstr "" -#: includes/OptionsArray.php:1265 +#: includes/OptionsArray.php:1280 msgid "Internal name for this API share" msgstr "" -#: includes/OptionsArray.php:1270 +#: includes/OptionsArray.php:1285 msgid "API enabled" msgstr "" -#: includes/OptionsArray.php:1271 +#: includes/OptionsArray.php:1286 msgid "If checked this API share is enabled" msgstr "" -#: includes/OptionsArray.php:1276 +#: includes/OptionsArray.php:1291 msgid "Push URL" msgstr "" -#: includes/OptionsArray.php:1277 +#: includes/OptionsArray.php:1292 msgid "URL that gets push information everytime there was a change on CommonsBooking data" msgstr "" -#: includes/OptionsArray.php:1282 +#: includes/OptionsArray.php:1297 msgid "API Key" msgstr "" -#: includes/OptionsArray.php:1285 +#: includes/OptionsArray.php:1300 msgid " You must set an API-Key. The API key should consist of alphanumeric characters and be at least 24 characters long." msgstr "" -#: includes/OptionsArray.php:1288 +#: includes/OptionsArray.php:1303 msgid "API Owner" msgstr "" -#: includes/OptionsArray.php:1289 +#: includes/OptionsArray.php:1304 msgid "The owner value is provided by the API. It is set to the blog name by default in this version. In future versions you may be able to change this information" msgstr "" -#: includes/OptionsArray.php:1309 +#: includes/OptionsArray.php:1324 msgid "Advanced Options" msgstr "" -#: includes/OptionsArray.php:1313 +#: includes/OptionsArray.php:1328 msgid "Set Custom metadata to locations and items" msgstr "" -#: includes/OptionsArray.php:1314 +#: includes/OptionsArray.php:1329 msgid "This is an advanced feature and should only be used if you are experienced or instructed how to set it up properly. In future versions we will add more detailed information and documentation." msgstr "" -#: includes/OptionsArray.php:1320 +#: includes/OptionsArray.php:1335 msgid "Meta Data" msgstr "" -#: includes/OptionsArray.php:1321 +#: includes/OptionsArray.php:1336 msgid "" "Use only this format, separated by semicolon and each entry in a new line:
post_type(item/location);field-name;label(english),type(checkbox,number,text),description(in english)
\n" " Example: item;waterproof;Waterproof material;checkbox;\"This item is waterproof and can be used in heavy rain\" " msgstr "" -#: includes/OptionsArray.php:1329 +#: includes/OptionsArray.php:1344 msgid "iCalendar Feed" msgstr "" -#: includes/OptionsArray.php:1330 +#: includes/OptionsArray.php:1345 msgid "Enables users to copy a url for a dynamic iCalendar feed into their own digital calendars. This feature is experimental." msgstr "" -#: includes/OptionsArray.php:1335 +#: includes/OptionsArray.php:1350 msgid "Enable iCalendar feed" msgstr "" -#: includes/OptionsArray.php:1340 +#: includes/OptionsArray.php:1355 msgid "Event title" msgstr "" -#: includes/OptionsArray.php:1341 -#: includes/OptionsArray.php:1349 +#: includes/OptionsArray.php:1356 +#: includes/OptionsArray.php:1364 msgid "You can use template tags here as well" msgstr "" -#: includes/OptionsArray.php:1348 +#: includes/OptionsArray.php:1363 msgid "Event description" msgstr "" -#: includes/OptionsArray.php:1350 +#: includes/OptionsArray.php:1365 msgid "" "\n" "Pick up: {{booking:pickupDatetime}}\n" @@ -1209,37 +1226,37 @@ msgid "" "{{booking:formattedBookingCode}} " msgstr "" -#: includes/OptionsArray.php:1362 +#: includes/OptionsArray.php:1377 msgid "Advanced caching settings" msgstr "" -#: includes/OptionsArray.php:1365 +#: includes/OptionsArray.php:1380 msgid "Allows you to change options regarding the caching system" msgstr "" -#: includes/OptionsArray.php:1368 -#: src/Service/Cache.php:369 +#: includes/OptionsArray.php:1383 +#: src/Service/Cache.php:370 msgid "Clear Cache" msgstr "" -#: includes/OptionsArray.php:1374 +#: includes/OptionsArray.php:1389 msgid "Filesystem cache path" msgstr "" -#: includes/OptionsArray.php:1375 +#: includes/OptionsArray.php:1390 msgid "Where the filesystem cache should be created. Only change when filesystem caching is not working." msgstr "" -#: includes/OptionsArray.php:1381 -#: includes/OptionsArray.php:1398 +#: includes/OptionsArray.php:1396 +#: includes/OptionsArray.php:1413 msgid "Current connection status" msgstr "" -#: includes/OptionsArray.php:1387 +#: includes/OptionsArray.php:1402 msgid "Enable REDIS Caching (experimental)" msgstr "" -#: includes/OptionsArray.php:1392 +#: includes/OptionsArray.php:1407 msgid "REDIS DSN (REDIS Server URL)" msgstr "" @@ -1268,7 +1285,7 @@ msgid "Please enter your phone number" msgstr "" #: src/CB/CB1UserFields.php:90 -#: src/CB/CB1UserFields.php:280 +#: src/CB/CB1UserFields.php:281 #: src/Wordpress/CustomPostType/Location.php:219 #: templates/booking-single.php:77 msgid "Address" @@ -1295,19 +1312,19 @@ msgstr "" msgid "Read the terms and services" msgstr "" -#: src/CB/CB1UserFields.php:268 +#: src/CB/CB1UserFields.php:269 msgid "Extra Fields" msgstr "" -#: src/CB/CB1UserFields.php:272 +#: src/CB/CB1UserFields.php:273 msgid "Phone number" msgstr "" -#: src/CB/CB1UserFields.php:288 +#: src/CB/CB1UserFields.php:289 msgid "Terms and conditions" msgstr "" -#: src/CB/CB1UserFields.php:294 +#: src/CB/CB1UserFields.php:295 msgid "Accepted Terms & Conditions" msgstr "" @@ -1328,92 +1345,67 @@ msgstr "" msgid "map is not published" msgstr "" -#: src/Map/MapAdmin.php:138 -msgid "Map Configuration" -msgstr "" - -#: src/Map/MapAdmin.php:472 -msgid "Select an image" -msgstr "" - -#: src/Map/MapAdmin.php:473 -msgid "save" -msgstr "" - -#: src/Map/MapAdmin.php:474 -msgid "measurements" -msgstr "" - -#: src/Map/MapSettings.php:68 -msgid "Settings for Commons Booking Map" -msgstr "" - -#: src/Map/MapSettings.php:69 -msgid "Commons Booking Map" -msgstr "" - -#: src/Map/MapShortcode.php:43 -#: templates/map-admin-page-template.php:230 -#: templates/map-admin-page-template.php:249 +#: src/Map/MapShortcode.php:49 msgid "opening hours" msgstr "" -#: src/Map/MapShortcode.php:44 +#: src/Map/MapShortcode.php:50 msgid "contact" msgstr "" -#: src/Map/MapShortcode.php:45 +#: src/Map/MapShortcode.php:51 msgid "from" msgstr "" -#: src/Map/MapShortcode.php:46 +#: src/Map/MapShortcode.php:52 msgid "until" msgstr "" -#: src/Map/MapShortcode.php:47 +#: src/Map/MapShortcode.php:53 msgid "for at least" msgstr "" -#: src/Map/MapShortcode.php:48 +#: src/Map/MapShortcode.php:54 msgid "day(s)" msgstr "" -#: src/Map/MapShortcode.php:49 +#: src/Map/MapShortcode.php:55 msgid "Sorry, no locations found." msgstr "" -#: src/Map/MapShortcode.php:50 +#: src/Map/MapShortcode.php:56 +#: src/Wordpress/CustomPostType/Map.php:535 msgid "filter" msgstr "" -#: src/Map/MapShortcode.php:51 -#: templates/map-admin-page-template.php:600 +#: src/Map/MapShortcode.php:57 +#: src/Wordpress/CustomPostType/Map.php:517 msgid "availability" msgstr "" -#: src/Map/MapShortcode.php:52 -#: templates/map-admin-page-template.php:610 +#: src/Map/MapShortcode.php:58 +#: src/Wordpress/CustomPostType/Map.php:526 msgid "categories" msgstr "" -#: src/Map/MapShortcode.php:53 -#: templates/map-admin-page-template.php:547 +#: src/Map/MapShortcode.php:59 +#: src/Wordpress/CustomPostType/Map.php:478 msgid "distance" msgstr "" -#: src/Map/MapShortcode.php:54 +#: src/Map/MapShortcode.php:60 msgid "address" msgstr "" -#: src/Map/MapShortcode.php:55 +#: src/Map/MapShortcode.php:61 msgid "Sorry, an error occured during your request. Please try again later." msgstr "" -#: src/Map/MapShortcode.php:56 +#: src/Map/MapShortcode.php:62 msgid "The service is currently not available. Please try again later." msgstr "" -#: src/Map/MapShortcode.php:57 +#: src/Map/MapShortcode.php:63 msgid "comming soon" msgstr "" @@ -1488,19 +1480,19 @@ msgstr "" msgid "Link to your booking" msgstr "" -#: src/Model/Booking.php:992 +#: src/Model/Booking.php:1022 msgid "Confirmed" msgstr "" -#: src/Model/Booking.php:994 +#: src/Model/Booking.php:1024 msgid "Unconfirmed" msgstr "" -#: src/Model/Booking.php:996 +#: src/Model/Booking.php:1026 msgid "Cancelled" msgstr "" -#: src/Model/Booking.php:998 +#: src/Model/Booking.php:1028 #: src/Service/TimeframeExport.php:523 #: src/Service/TimeframeExport.php:533 #: src/Service/TimeframeExport.php:539 @@ -1624,28 +1616,37 @@ msgid "Mass Operations" msgstr "" #: src/Plugin.php:435 +#: src/Plugin.php:467 msgid "Item Category" msgstr "" -#: src/Plugin.php:467 +#: src/Plugin.php:476 +msgid "Add custom title for filter" +msgstr "" + +#: src/Plugin.php:479 +msgid "Define name that should be used for the category if it is displayed in the map as a filter group. You can also use this to add custom HTML to the category name. When left empty, the defined name of the category will be used." +msgstr "" + +#: src/Plugin.php:497 msgid "Location Category" msgstr "" -#: src/Plugin.php:679 -#: src/Plugin.php:694 +#: src/Plugin.php:709 +#: src/Plugin.php:724 #: src/Wordpress/CustomPostType/Booking.php:922 msgid "CommonsBooking Bookings" msgstr "" -#: src/Repository/BookingCodes.php:330 +#: src/Repository/BookingCodes.php:332 msgid "No booking codes could be created because there were no booking codes to choose from. Please set some booking codes in the CommonsBooking settings." msgstr "" -#: src/Repository/BookingCodes.php:337 +#: src/Repository/BookingCodes.php:339 msgid "No booking codes could be created because the location of the timeframe could not be found." msgstr "" -#: src/Repository/BookingCodes.php:343 +#: src/Repository/BookingCodes.php:345 msgid "No booking codes could be created because the item of the timeframe could not be found." msgstr "" @@ -1815,27 +1816,27 @@ msgstr "" msgid "Booking rules: No rule type specified." msgstr "" -#: src/Service/Cache.php:302 +#: src/Service/Cache.php:303 msgid "Connection status:" msgstr "" -#: src/Service/Cache.php:309 +#: src/Service/Cache.php:310 msgid "Successfully connected to REDIS database!" msgstr "" -#: src/Service/Cache.php:320 +#: src/Service/Cache.php:321 msgid "REDIS database not enabled" msgstr "" -#: src/Service/Cache.php:346 +#: src/Service/Cache.php:347 msgid "Directory %s is writeable." msgstr "" -#: src/Service/Cache.php:351 +#: src/Service/Cache.php:352 msgid "Directory %s could not be written to." msgstr "" -#: src/Service/Cache.php:364 +#: src/Service/Cache.php:365 msgid "Clear all cache items" msgstr "" @@ -1852,16 +1853,25 @@ msgstr "" msgid "Load Holidays" msgstr "" -#: src/Service/MassOperations.php:43 +#: src/Service/MassOperations.php:28 +msgid "All selected orphaned bookings have been migrated." +msgstr "" + +#: src/Service/MassOperations.php:33 +msgid "An error occurred while moving bookings." +msgstr "" + +#: src/Service/MassOperations.php:52 msgid "No bookings to move selected." msgstr "" -#: src/Service/MassOperations.php:62 +#: src/Service/MassOperations.php:64 +#: src/Service/MassOperations.php:67 msgid "New location not found for booking with ID %s" msgstr "" -#: src/Service/MassOperations.php:68 -msgid "All selected orphaned bookings have been migrated." +#: src/Service/MassOperations.php:70 +msgid "There is already a booking on the new location during the timeframe of booking with ID %s." msgstr "" #: src/Service/TimeframeExport.php:89 @@ -1897,19 +1907,19 @@ msgstr "" msgid "Processed %d of %d bookings" msgstr "" -#: src/Service/Upgrade.php:133 +#: src/Service/Upgrade.php:138 msgid "There are some tasks that need to be run to complete the update process.
This needs to be done so that the plugin can function correctly." msgstr "" -#: src/Service/Upgrade.php:136 +#: src/Service/Upgrade.php:141 msgid "Click here to run the upgrade tasks." msgstr "" -#: src/Service/Upgrade.php:297 +#: src/Service/Upgrade.php:302 msgid "New features and changes: Please backup your site before upgrading!" msgstr "" -#: src/Service/Upgrade.php:304 +#: src/Service/Upgrade.php:309 msgid "" "\n" "\t\t\t\t\tThis CommonsBooking update has a lot of new features and changes on some templates.
\n" @@ -1949,7 +1959,7 @@ msgid "Not available" msgstr "" #: src/View/Booking.php:193 -#: src/View/MassOperations.php:39 +#: src/View/MassOperations.php:38 #: src/Wordpress/CustomPostType/Booking.php:441 #: src/Wordpress/CustomPostType/Timeframe.php:99 #: templates/shortcode-bookings.php:73 @@ -1957,7 +1967,7 @@ msgid "User" msgstr "" #: src/View/Booking.php:197 -#: src/View/MassOperations.php:43 +#: src/View/MassOperations.php:42 #: src/Wordpress/CustomPostType/Booking.php:959 #: src/Wordpress/CustomPostType/Restriction.php:472 msgid "Status" @@ -2114,58 +2124,58 @@ msgstr "" msgid "No locations found." msgstr "" -#: src/View/Map.php:36 +#: src/View/Map.php:35 msgid "Set / Update GPS Coordinates" msgstr "" -#: src/View/Map.php:40 +#: src/View/Map.php:39 msgid "Set / update GPS coordinates from address" msgstr "" -#: src/View/Map.php:43 +#: src/View/Map.php:42 msgid "Click this button to automatically set the GPS coordinates based on the given address and set the marker on the map.
Save or update this location after setting the gps data." msgstr "" -#: src/View/Map.php:46 +#: src/View/Map.php:45 msgid "No GPS data could be found for the address entered.
Please check if the address is written correctly.
Alternatively, you can enter the GPS data manually into the corresponding fields." msgstr "" -#: src/View/MassOperations.php:38 +#: src/View/MassOperations.php:37 msgid "ID" msgstr "" -#: src/View/MassOperations.php:40 +#: src/View/MassOperations.php:39 msgid "Item name" msgstr "" -#: src/View/MassOperations.php:41 +#: src/View/MassOperations.php:40 msgid "Start-date" msgstr "" -#: src/View/MassOperations.php:42 +#: src/View/MassOperations.php:41 msgid "End-date" msgstr "" -#: src/View/MassOperations.php:44 +#: src/View/MassOperations.php:43 msgid "Location name" msgstr "" -#: src/View/MassOperations.php:45 +#: src/View/MassOperations.php:44 msgid "New location name" msgstr "" -#: src/View/MassOperations.php:95 +#: src/View/MassOperations.php:94 #: src/View/Migration.php:93 msgid "migration in process .. please wait ..." msgstr "" -#: src/View/MassOperations.php:100 +#: src/View/MassOperations.php:99 #: src/View/Migration.php:53 #: src/View/Migration.php:98 msgid "Migration finished" msgstr "" -#: src/View/MassOperations.php:105 +#: src/View/MassOperations.php:104 #: src/View/Migration.php:103 msgid "Migration failed" msgstr "" @@ -2870,1254 +2880,1241 @@ msgstr "" msgid "Here you can specify, if a connected span of locked days should be counted individually or just use up x amount of the maximum quota the user is allowed to book. If you set this field to 0, every day will be counted individually. If you set this field to 1, all overbooked days, no matter how many, will always count for 1 day. If you set this to 2, they will count a maximum of two days and so on." msgstr "" -#: src/Wordpress/CustomPostType/Map.php:369 -#: templates/dashboard-index.php:55 -msgid "Maps" +#: src/Wordpress/CustomPostType/Map.php:45 +msgid "Map settings" msgstr "" -#: src/Wordpress/CustomPostType/Map.php:370 -msgid "Map" +#: src/Wordpress/CustomPostType/Map.php:59 +msgid "These settings help you to configure the usage and appearance of Commons Booking Map" msgstr "" -#: src/Wordpress/CustomPostType/Map.php:371 -#: src/Wordpress/CustomPostType/Map.php:374 -msgid "create CB map" +#: src/Wordpress/CustomPostType/Map.php:70 +msgid "Presentation" msgstr "" -#: src/Wordpress/CustomPostType/Map.php:372 -msgid "create Commons Booking map" +#: src/Wordpress/CustomPostType/Map.php:76 +msgid "base map" msgstr "" -#: src/Wordpress/CustomPostType/Map.php:373 -msgid "edit Commons Booking map" +#: src/Wordpress/CustomPostType/Map.php:77 +msgid "the base map defines the rendering style of the map tiles" msgstr "" -#: src/Wordpress/CustomPostType/Map.php:375 -msgid "view CB map" +#: src/Wordpress/CustomPostType/Map.php:81 +msgid "OSM - mapnik" msgstr "" -#: src/Wordpress/CustomPostType/Map.php:376 -msgid "search CB maps" +#: src/Wordpress/CustomPostType/Map.php:82 +msgid "OSM - german style" msgstr "" -#: src/Wordpress/CustomPostType/Map.php:377 -msgid "no Commons Booking map found" +#: src/Wordpress/CustomPostType/Map.php:92 +msgid "show scale" msgstr "" -#: src/Wordpress/CustomPostType/Map.php:378 -msgid "no Commons Booking map found in the trash" +#: src/Wordpress/CustomPostType/Map.php:93 +msgid "show the current scale in the bottom left corner of the map" msgstr "" -#: src/Wordpress/CustomPostType/Map.php:379 -msgid "parent CB maps" +#: src/Wordpress/CustomPostType/Map.php:98 +msgid "map height" msgstr "" -#: src/Wordpress/CustomPostType/Map.php:408 -msgid "Maps to show Commons Booking Locations and their Items" +#: src/Wordpress/CustomPostType/Map.php:99 +msgid "the height the map is rendered with - the width is the same as of the parent element" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:58 -msgid "Restriction Status" +#: src/Wordpress/CustomPostType/Map.php:109 +msgid "no locations message" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:75 -#: src/Wordpress/CustomPostType/Timeframe.php:245 -msgid "Filter By Type " +#: src/Wordpress/CustomPostType/Map.php:110 +msgid "in case a user filters locations and gets no result, a message is shown - here the text can be customized" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:101 -#: src/Wordpress/CustomPostType/Timeframe.php:271 -msgid "Filter By Item " +#: src/Wordpress/CustomPostType/Map.php:113 +msgid "No locations found" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:128 -#: src/Wordpress/CustomPostType/Timeframe.php:298 -msgid "Filter By Location " +#: src/Wordpress/CustomPostType/Map.php:116 +msgid "enable data export" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:141 -#: src/Wordpress/CustomPostType/Timeframe.php:316 -msgid "Filter By Status " +#: src/Wordpress/CustomPostType/Map.php:117 +msgid "activate to enable a button that allows the export of map data (geojson format)" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:309 -#: src/Wordpress/CustomPostType/Restriction.php:390 -msgid "Restriction" +#: src/Wordpress/CustomPostType/Map.php:123 +msgid "Zoom" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:311 -#: src/Wordpress/CustomPostType/Restriction.php:313 -msgid "Add new Restriction" +#: src/Wordpress/CustomPostType/Map.php:129 +msgid "min. zoom level" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:312 -msgid "Edit Restriction" +#: src/Wordpress/CustomPostType/Map.php:130 +msgid "the minimal zoom level a user can choose" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:314 -msgid "Show Restriction" +#: src/Wordpress/CustomPostType/Map.php:142 +msgid "max. zoom level" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:315 -msgid "Show Restrictions" +#: src/Wordpress/CustomPostType/Map.php:143 +msgid "the maximal zoom level a user can choose" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:316 -msgid "Search Restrictions" +#: src/Wordpress/CustomPostType/Map.php:155 +msgid "start zoom level" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:317 -msgid "Restrictions not found" +#: src/Wordpress/CustomPostType/Map.php:156 +msgid "the zoom level that will be set when the map is loaded" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:318 -msgid "No Restrictions found in trash" +#: src/Wordpress/CustomPostType/Map.php:168 +msgid "enable scroll wheel zoom" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:319 -msgid "Parent Restrictions:" +#: src/Wordpress/CustomPostType/Map.php:169 +msgid "when activated users can zoom the map using the scroll wheel" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:320 -msgid "All Restrictions" +#: src/Wordpress/CustomPostType/Map.php:177 +msgid "Positioning" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:321 -msgid "Restriction archive" +#: src/Wordpress/CustomPostType/Map.php:183 +msgid "start latitude" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:322 -msgid "Restriction attributes" +#: src/Wordpress/CustomPostType/Map.php:184 +msgid "the latitude of the map center when the map is loaded" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:323 -msgid "Add to Restriction" +#: src/Wordpress/CustomPostType/Map.php:190 +msgid "start longitude" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:324 -msgid "Added to Restriction" +#: src/Wordpress/CustomPostType/Map.php:191 +msgid "the longitude of the map center when the map is loaded" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:325 -msgid "Restriction image" +#: src/Wordpress/CustomPostType/Map.php:197 +msgid "initial adjustment to marker bounds" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:326 -msgid "set Restriction image" +#: src/Wordpress/CustomPostType/Map.php:198 +msgid "adjust map section to bounds of shown markers automatically when map is loaded" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:327 -msgid "remove Restriction image" +#: src/Wordpress/CustomPostType/Map.php:204 +msgid "adjustment to marker bounds on filter" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:328 -msgid "use as Restriction image" +#: src/Wordpress/CustomPostType/Map.php:205 +msgid "adjust map section to bounds of shown markers automatically when filtered by users" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:418 -msgid "" -"Select the type of restriction.
\n" -"\t\t\t\tSelect Notice, the item can still be used and if e.g. only one part is missing or defective.
\n" -"\t\t\t\tSelect total breakdown if the defect means that the item can no longer be used. If you select total breakdown \n" -"\t\t\t\tall affected bookings will be automatically canceled after activating this restriction and after clicking send the information email.\n" -"\t\t\t\t" +#: src/Wordpress/CustomPostType/Map.php:213 +msgid "Marker Tooltip" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:440 -msgid "Hint" +#: src/Wordpress/CustomPostType/Map.php:219 +msgid "Show marker tooltip permanently" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:442 -msgid "Please enter here a short information about the reason and possible effects of the usage restriction.
The explanation will be displayed on the article page and in the notification e-mail." +#: src/Wordpress/CustomPostType/Map.php:220 +msgid "activate to show the marker tooltips permanently" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:447 -msgid "Set the start date and time" +#: src/Wordpress/CustomPostType/Map.php:227 +msgid "Marker Popup" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:457 -msgid "Set the estimated end date and time" +#: src/Wordpress/CustomPostType/Map.php:233 +msgid "show item availability" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:474 -msgid "" -"Choose status of this restriction.
\n" -"\t\t\t\tSet to None if you want to deactivate the restriction.
\n" -"\t\t\t\t\tSet to Active if the restriction is active.
\n" -"Set to Problem Solved, if the restriction is no longer in effect.
\n" -"Depending on the selected status, affected users will receive corresponding notification emails.\n" -"Select the desired status and then click the \"Send\" button to send the e-mail.
" +#: src/Wordpress/CustomPostType/Map.php:234 +msgid "activate to show the item availability in the marker popup" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:485 -msgid "Send notification emails to users" +#: src/Wordpress/CustomPostType/Map.php:239 +msgid "Max. available days in popup" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:486 -msgid "Important: Please save this restriction before clicking the send-button. Dependent of the status of the restriction, the appropriate notifications are sent to all affected users and location admins. You can configure the e-mail templates via Options -> Commonsbooking -> Tab Restrictions" +#: src/Wordpress/CustomPostType/Map.php:240 +msgid "Set how many days are displayed on the popup (starting from today)" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:504 -msgid "Total breakdown" +#: src/Wordpress/CustomPostType/Map.php:251 +msgid "Maximum days to choose in map availabilty filter " msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:505 -msgid "Notice" +#: src/Wordpress/CustomPostType/Map.php:252 +msgid "Notice: Defines the maximun days a user can choose in the availabilty filter in frontend map" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:515 -msgid "Not active" +#: src/Wordpress/CustomPostType/Map.php:264 +msgid "Custom Marker" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:516 -msgid "Active" +#: src/Wordpress/CustomPostType/Map.php:270 +msgid "image file" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:517 -msgid "Problem solved" +#: src/Wordpress/CustomPostType/Map.php:271 +#: src/Wordpress/CustomPostType/Map.php:348 +#: src/Wordpress/CustomPostType/Map.php:404 +msgid "the default marker icon can be replaced by a custom image" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:105 -msgid "Max. Booking Duration" +#: src/Wordpress/CustomPostType/Map.php:284 +#: src/Wordpress/CustomPostType/Map.php:361 +#: src/Wordpress/CustomPostType/Map.php:417 +msgid "icon width" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:124 -msgid "All timeframe types" +#: src/Wordpress/CustomPostType/Map.php:285 +#: src/Wordpress/CustomPostType/Map.php:296 +#: src/Wordpress/CustomPostType/Map.php:362 +#: src/Wordpress/CustomPostType/Map.php:373 +#: src/Wordpress/CustomPostType/Map.php:418 +#: src/Wordpress/CustomPostType/Map.php:429 +msgid "the size of the custom marker icon image as it is shown on the map" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:130 -msgid "Bookable" +#: src/Wordpress/CustomPostType/Map.php:295 +#: src/Wordpress/CustomPostType/Map.php:372 +#: src/Wordpress/CustomPostType/Map.php:428 +msgid "icon height" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:131 -msgid "Holidays or location closed" +#: src/Wordpress/CustomPostType/Map.php:306 +#: src/Wordpress/CustomPostType/Map.php:316 +#: src/Wordpress/CustomPostType/Map.php:439 +#: src/Wordpress/CustomPostType/Map.php:449 +msgid "anchor point" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:134 -msgid "Blocked (not overbookable)" +#: src/Wordpress/CustomPostType/Map.php:307 +#: src/Wordpress/CustomPostType/Map.php:317 +#: src/Wordpress/CustomPostType/Map.php:440 +#: src/Wordpress/CustomPostType/Map.php:450 +msgid "the position of the anchor point of the icon image, seen from the left top corner of the icon, often it is half of the width and full height of the icon size - this point is used to place the marker on the geo coordinates" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:161 -msgid "Select Dates:" +#: src/Wordpress/CustomPostType/Map.php:328 +msgid "Cluster" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:451 -#: src/Wordpress/CustomPostType/Timeframe.php:1145 -msgid "Timeframe" +#: src/Wordpress/CustomPostType/Map.php:334 +msgid "max. cluster radius" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:480 -msgid "This comment is internal for timeframes like bookable, repair, holiday. If timeframe is a booking this comment can be set by users during the booking confirmation process." +#: src/Wordpress/CustomPostType/Map.php:335 +msgid "combine markers to a cluster within given radius - 0 for deactivation" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:487 -msgid "Select Type of this timeframe: Bookable or Location Closed. See Documentation for detailed information." +#: src/Wordpress/CustomPostType/Map.php:347 +msgid "Custom Cluster Marker" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:502 -msgid "Location Category Selection" +#: src/Wordpress/CustomPostType/Map.php:385 +msgid "Appearance by Item Status" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:510 -msgid "Location Selection" +#: src/Wordpress/CustomPostType/Map.php:391 +msgid "appearance" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:513 -#: src/Wordpress/CustomPostType/Timeframe.php:551 -msgid "Please select" +#: src/Wordpress/CustomPostType/Map.php:392 +msgid "how locations with items that are in draft status should be handled" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:518 -msgid "Select one or more locations" +#: src/Wordpress/CustomPostType/Map.php:396 +msgid "don't show drafts" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:525 -msgid "Item Selection" +#: src/Wordpress/CustomPostType/Map.php:397 +msgid "show only drafts" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:533 -msgid "Select one or more items" +#: src/Wordpress/CustomPostType/Map.php:398 +msgid "show all together" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:540 -msgid "Item Category Selection" +#: src/Wordpress/CustomPostType/Map.php:403 +msgid "Custom Item Draft Marker" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:548 -msgid "Item selection" +#: src/Wordpress/CustomPostType/Map.php:461 +msgid "Filter for Users" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:556 -msgid "Configure bookings" +#: src/Wordpress/CustomPostType/Map.php:467 +msgid "show location distance filter" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:561 -msgid "Maximum" +#: src/Wordpress/CustomPostType/Map.php:468 +msgid "activate to show the location distance filter" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:562 -msgid "days in a row" +#: src/Wordpress/CustomPostType/Map.php:473 +msgid "label for location distance filter" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:574 -msgid "Lead time:" +#: src/Wordpress/CustomPostType/Map.php:474 +msgid "alternative label for the location distance filter" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:575 -msgid "Enter the number of days that should be blocked for bookings as a booking lead time (calculated from the current day)." +#: src/Wordpress/CustomPostType/Map.php:482 +#: src/Wordpress/CustomPostType/Map.php:488 +msgid "address search bounds - left bottom" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:587 -msgid "Calendar shows as bookable" +#: src/Wordpress/CustomPostType/Map.php:482 +#: src/Wordpress/CustomPostType/Map.php:494 +msgid "longitude" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:588 -msgid "Select for how many days in advance the calendar should display bookable days. Calculated from the current date." +#: src/Wordpress/CustomPostType/Map.php:483 +msgid "defines the bounds of the address search - set the longitude of the left bottom corner of the bounding box" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:600 -msgid "Allowed for" +#: src/Wordpress/CustomPostType/Map.php:488 +#: src/Wordpress/CustomPostType/Map.php:500 +msgid "latitude" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:602 -msgid "
Select one or more user roles that will be allowed to book the item exclusively.
Leave this blank to allow all users to book the item. " +#: src/Wordpress/CustomPostType/Map.php:489 +msgid "defines the bounds of the address search - set the bottom left corner of the bounding box" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:606 -msgid "User roles" +#: src/Wordpress/CustomPostType/Map.php:494 +#: src/Wordpress/CustomPostType/Map.php:500 +msgid "address search bounds - right top" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:611 -msgid "Configure timeframe" +#: src/Wordpress/CustomPostType/Map.php:495 +msgid "defines the bounds of the address search - set the longitude of the right top corner of the bounding box" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:616 -msgid "Full day" +#: src/Wordpress/CustomPostType/Map.php:501 +msgid "defines the bounds of the address search - set the latitude of the right top corner of the bounding box" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:617 -msgid "If this option is selected, users can choose only whole days for pickup and return. No specific time slots for pickup or return are offered. Select this option if the pickup/return should be arranged personally between the location and the user. " +#: src/Wordpress/CustomPostType/Map.php:506 +msgid "show item availability filter" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:626 -msgid "Grid" +#: src/Wordpress/CustomPostType/Map.php:507 +msgid "activate to show the item availability filter" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:627 -msgid "Choose whether users can only select the entire from/to time period when booking (full slot) or book within the time period in an hourly grid. See the documentation: Manage Booking Timeframes" +#: src/Wordpress/CustomPostType/Map.php:512 +msgid "label for item availability filter" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:634 -msgid "Start time" +#: src/Wordpress/CustomPostType/Map.php:513 +msgid "alternative label for the item availability filter" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:651 -msgid "End time" +#: src/Wordpress/CustomPostType/Map.php:521 +msgid "label for item category filter" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:668 -msgid "Timeframe Repetition" +#: src/Wordpress/CustomPostType/Map.php:522 +msgid "alternative label for the item category filter" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:669 -msgid "Choose whether the time frame should repeat at specific intervals. The repetitions refer to the unit of a day. With the start and end date you define when the repetition interval starts and ends. If you choose \"weekly\", you can select specific days of the week below. Read the documentation for more information and examples." +#: src/Wordpress/CustomPostType/Map.php:530 +msgid "custom text for filter button" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:679 -msgid "Import holidays" +#: src/Wordpress/CustomPostType/Map.php:531 +msgid "the text for the button used for filtering" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:680 -msgid "Select the year and state to import holidays for (as of now only German holidays are supported)" +#: src/Wordpress/CustomPostType/Map.php:539 +msgid "Filter groups" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:687 -msgid "Configure repetition" +#: src/Wordpress/CustomPostType/Map.php:540 +msgid "Filter groups can group item or location categories together to allow for filtering in the map." msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:688 -msgid "Below you can make settings regarding the time frame repetition. " +#: src/Wordpress/CustomPostType/Map.php:545 +msgid "Filter group {#}" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:693 -msgid "Selected manual dates" +#: src/Wordpress/CustomPostType/Map.php:546 +msgid "Add another filter group" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:694 -msgid "Enter the dates in the YYYY-MM-DD format here, the dates are separated by a comma.
Example: 2023-05-24,2023-06-24
You can also use the datepicker above to pick dates for this field." +#: src/Wordpress/CustomPostType/Map.php:547 +msgid "Remove filter group" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:701 -msgid "Set the start date. If you have selected repetition, this is the start date of the interval. " +#: src/Wordpress/CustomPostType/Map.php:552 +msgid "Name" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:709 -msgid "Weekdays" +#: src/Wordpress/CustomPostType/Map.php:555 +msgid "The name of the filter group" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:713 -msgid "Monday" +#: src/Wordpress/CustomPostType/Map.php:562 +msgid "This is not available yet. Which data source should be used for the filter group. Taxonomy stands for the assigned categories, post-meta can be individually configured custom fields for item posts. When this item field contains data, it will be included. If it does not contain data or does not exist, the item will be excluded." msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:714 -msgid "Tuesday" +#: src/Wordpress/CustomPostType/Map.php:564 +msgid "Taxonomy" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:715 -msgid "Wednesday" +#: src/Wordpress/CustomPostType/Map.php:565 +msgid "Post-meta" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:716 -msgid "Thursday" +#: src/Wordpress/CustomPostType/Map.php:574 +msgid "Exclusive selection" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:717 -msgid "Friday" +#: src/Wordpress/CustomPostType/Map.php:577 +msgid "WARNING: This feature is only available for the cb_search shortcode, not for cb_map. If checked, only one category can be selected in this filter group. If unchecked, multiple categories can be selected." msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:718 -msgid "Saturday" +#: src/Wordpress/CustomPostType/Map.php:580 +msgid "Categories" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:719 -msgid "Sunday" +#: src/Wordpress/CustomPostType/Map.php:583 +msgid "The categories to be included in the filter group" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:725 -msgid "" -"Set the end date. If you have selected repetition, this is the end date of the interval. Leave blank if you do not want to set an end date.\n" -"
Notice: If you want to select only one day (e.g. for holidays or blocked days) set the start and the end date to same day." +#: src/Wordpress/CustomPostType/Map.php:593 +msgid "Filter Item Presets" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:734 -#: src/Wordpress/CustomPostType/Timeframe.php:758 -#: src/Wordpress/CustomPostType/Timeframe.php:781 -msgid "Booking Codes" +#: src/Wordpress/CustomPostType/Map.php:594 +msgid "select the categories that are used to prefilter the items that are shown on the map - none for all items" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:735 -msgid "" -"You can automatically generate booking codes. Codes can be generated only with the following settings:
\n" -"\t\t\t\t- Whole day is enabled
\n" -"\t\t\t\t- Timeframe is bookable
\n" -"\t\t\t\tMore Information in the documentation\n" -"\t\t\t\t" +#: src/Wordpress/CustomPostType/Map.php:601 +msgid "Filter Location Presets" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:744 -msgid "Create Booking Codes" +#: src/Wordpress/CustomPostType/Map.php:602 +msgid "select the categories that are used to prefilter the locations that are shown on the map - none for all locations" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:745 -msgid "Select to generate booking codes for each day within the start/end date. The booking codes will be generated after clicking \"Save / Update\"." +#: src/Wordpress/CustomPostType/Map.php:618 +#: templates/dashboard-index.php:55 +msgid "Maps" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:751 -msgid "Show Booking Codes" +#: src/Wordpress/CustomPostType/Map.php:619 +msgid "Map" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:752 -msgid "Select whether users should be shown a booking code when booking." +#: src/Wordpress/CustomPostType/Map.php:620 +#: src/Wordpress/CustomPostType/Map.php:623 +msgid "create CB map" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:764 -msgid "Send booking codes automated by email" +#: src/Wordpress/CustomPostType/Map.php:621 +msgid "create Commons Booking map" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:765 -msgid "Enable automated sending of booking codes by email" +#: src/Wordpress/CustomPostType/Map.php:622 +msgid "edit Commons Booking map" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:767 -msgid "First day to send Codes (List starts at next month)
(Same day will be used for subsequent messages) " +#: src/Wordpress/CustomPostType/Map.php:624 +msgid "view CB map" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:770 -msgid "Months to send" +#: src/Wordpress/CustomPostType/Map.php:625 +msgid "search CB maps" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:771 -msgid "Send booking codes for this amount of month's in one email" +#: src/Wordpress/CustomPostType/Map.php:626 +msgid "no Commons Booking map found" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:773 -msgid "Next email planned for: " +#: src/Wordpress/CustomPostType/Map.php:627 +msgid "no Commons Booking map found in the trash" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:774 -msgid "(not planned)" +#: src/Wordpress/CustomPostType/Map.php:628 +msgid "parent CB maps" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:820 -msgid "Manual selection" +#: src/Wordpress/CustomPostType/Map.php:657 +msgid "Maps to show Commons Booking Locations and their Items" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:821 -msgid "Select by category" +#: src/Wordpress/CustomPostType/Map.php:680 +msgid "Copy to clipboard" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:822 -#: templates/shortcode-bookings.php:54 -msgid "All" +#: src/Wordpress/CustomPostType/Restriction.php:58 +msgid "Restriction Status" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:832 -msgid "Full slot" +#: src/Wordpress/CustomPostType/Restriction.php:75 +#: src/Wordpress/CustomPostType/Timeframe.php:245 +msgid "Filter By Type " msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:833 -msgid "Hourly" +#: src/Wordpress/CustomPostType/Restriction.php:101 +#: src/Wordpress/CustomPostType/Timeframe.php:271 +msgid "Filter By Item " msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:843 -msgid "No repetition" +#: src/Wordpress/CustomPostType/Restriction.php:128 +#: src/Wordpress/CustomPostType/Timeframe.php:298 +msgid "Filter By Location " msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:844 -msgid "Manual repetition" +#: src/Wordpress/CustomPostType/Restriction.php:141 +#: src/Wordpress/CustomPostType/Timeframe.php:316 +msgid "Filter By Status " msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:845 -msgid "Daily" +#: src/Wordpress/CustomPostType/Restriction.php:309 +#: src/Wordpress/CustomPostType/Restriction.php:390 +msgid "Restriction" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:846 -msgid "Weekly" +#: src/Wordpress/CustomPostType/Restriction.php:311 +#: src/Wordpress/CustomPostType/Restriction.php:313 +msgid "Add new Restriction" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:847 -msgid "Monthly" +#: src/Wordpress/CustomPostType/Restriction.php:312 +msgid "Edit Restriction" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:848 -msgid "Yearly" -msgstr "" - -#: src/Wordpress/CustomPostType/Timeframe.php:932 -msgid "Orphaned bookings found, can migrate. Click here to migrate " -msgstr "" - -#: src/Wordpress/CustomPostType/Timeframe.php:1147 -#: src/Wordpress/CustomPostType/Timeframe.php:1149 -msgid "Add new timeframe" -msgstr "" - -#: src/Wordpress/CustomPostType/Timeframe.php:1148 -msgid "Edit timeframe" -msgstr "" - -#: src/Wordpress/CustomPostType/Timeframe.php:1150 -msgid "Show timeframe" +#: src/Wordpress/CustomPostType/Restriction.php:314 +msgid "Show Restriction" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1151 -msgid "Show timeframes" +#: src/Wordpress/CustomPostType/Restriction.php:315 +msgid "Show Restrictions" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1152 -msgid "Search timeframes" +#: src/Wordpress/CustomPostType/Restriction.php:316 +msgid "Search Restrictions" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1153 -msgid "Timeframes not found" +#: src/Wordpress/CustomPostType/Restriction.php:317 +msgid "Restrictions not found" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1154 -msgid "No timeframes found in trash" +#: src/Wordpress/CustomPostType/Restriction.php:318 +msgid "No Restrictions found in trash" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1155 -msgid "Parent timeframes:" +#: src/Wordpress/CustomPostType/Restriction.php:319 +msgid "Parent Restrictions:" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1156 -msgid "All timeframes" +#: src/Wordpress/CustomPostType/Restriction.php:320 +msgid "All Restrictions" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1159 -msgid "Add to timeframe" +#: src/Wordpress/CustomPostType/Restriction.php:321 +msgid "Restriction archive" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1160 -msgid "Added to timeframe" +#: src/Wordpress/CustomPostType/Restriction.php:322 +msgid "Restriction attributes" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1162 -msgid "set timeframe image" +#: src/Wordpress/CustomPostType/Restriction.php:323 +msgid "Add to Restriction" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1163 -msgid "remove timeframe image" +#: src/Wordpress/CustomPostType/Restriction.php:324 +msgid "Added to Restriction" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1164 -msgid "use as timeframe image" +#: src/Wordpress/CustomPostType/Restriction.php:325 +msgid "Restriction image" msgstr "" -#: src/Wordpress/Options/AdminOptions.php:54 -msgid "Default values for following fields automatically set or restored, because they were empty:
" +#: src/Wordpress/CustomPostType/Restriction.php:326 +msgid "set Restriction image" msgstr "" -#: src/Wordpress/Options/OptionsTab.php:56 -msgid "CommonsBooking" +#: src/Wordpress/CustomPostType/Restriction.php:327 +msgid "remove Restriction image" msgstr "" -#: src/Wordpress/Options/OptionsTab.php:148 -msgid "The export path does not exist or is not readable." +#: src/Wordpress/CustomPostType/Restriction.php:328 +msgid "use as Restriction image" msgstr "" -#: src/Wordpress/Options/OptionsTab.php:156 -msgid "The export path is not writeable." +#: src/Wordpress/CustomPostType/Restriction.php:418 +msgid "" +"Select the type of restriction.
\n" +"\t\t\t\tSelect Notice, the item can still be used and if e.g. only one part is missing or defective.
\n" +"\t\t\t\tSelect total breakdown if the defect means that the item can no longer be used. If you select total breakdown \n" +"\t\t\t\tall affected bookings will be automatically canceled after activating this restriction and after clicking send the information email.\n" +"\t\t\t\t" msgstr "" -#: src/Wordpress/Options/OptionsTab.php:167 -msgid "Cache cleared." +#: src/Wordpress/CustomPostType/Restriction.php:440 +msgid "Hint" msgstr "" -#: src/Wordpress/Options/OptionsTab.php:175 -msgid "Error while clearing the cache." +#: src/Wordpress/CustomPostType/Restriction.php:442 +msgid "Please enter here a short information about the reason and possible effects of the usage restriction.
The explanation will be displayed on the article page and in the notification e-mail." msgstr "" -#: src/Wordpress/Widget/UserWidget.php:18 -msgid "Shows links to My Bookings, Login, Logout. Please set the Bookings Page in CommonsBooking Settings (General-Tab)" +#: src/Wordpress/CustomPostType/Restriction.php:447 +msgid "Set the start date and time" msgstr "" -#. translators: $s = user first name or email -#: src/Wordpress/Widget/UserWidget.php:73 -msgid "Welcome %s" +#: src/Wordpress/CustomPostType/Restriction.php:457 +msgid "Set the estimated end date and time" msgstr "" -#. translators: $s = bookings page url -#: src/Wordpress/Widget/UserWidget.php:76 -msgid "

  • My Bookings
  • " +#: src/Wordpress/CustomPostType/Restriction.php:474 +msgid "" +"Choose status of this restriction.
    \n" +"\t\t\t\tSet to None if you want to deactivate the restriction.
    \n" +"\t\t\t\t\tSet to Active if the restriction is active.
    \n" +"Set to Problem Solved, if the restriction is no longer in effect.
    \n" +"Depending on the selected status, affected users will receive corresponding notification emails.\n" +"Select the desired status and then click the \"Send\" button to send the e-mail.
    " msgstr "" -#. translators: $s = user profile url -#: src/Wordpress/Widget/UserWidget.php:78 -msgid "
  • My Profile
  • " +#: src/Wordpress/CustomPostType/Restriction.php:485 +msgid "Send notification emails to users" msgstr "" -#. translators: $s = wp logout url -#: src/Wordpress/Widget/UserWidget.php:80 -msgid "
  • Log out
  • " +#: src/Wordpress/CustomPostType/Restriction.php:486 +msgid "Important: Please save this restriction before clicking the send-button. Dependent of the status of the restriction, the appropriate notifications are sent to all affected users and location admins. You can configure the e-mail templates via Options -> Commonsbooking -> Tab Restrictions" msgstr "" -#: src/Wordpress/Widget/UserWidget.php:85 -msgid "You are not logged in." +#: src/Wordpress/CustomPostType/Restriction.php:504 +msgid "Total breakdown" msgstr "" -#. translators: $s = wp login url -#: src/Wordpress/Widget/UserWidget.php:88 -msgid "
  • Login
  • " +#: src/Wordpress/CustomPostType/Restriction.php:505 +msgid "Notice" msgstr "" -#. translators: $s = wp registration url -#: src/Wordpress/Widget/UserWidget.php:90 -msgid "
  • Register
  • " +#: src/Wordpress/CustomPostType/Restriction.php:515 +msgid "Not active" msgstr "" -#: src/Wordpress/Widget/UserWidget.php:109 -msgid "Title:" +#: src/Wordpress/CustomPostType/Restriction.php:516 +msgid "Active" msgstr "" -#: src/Wordpress/Widget/UserWidget.php:115 -msgid "Text:" +#: src/Wordpress/CustomPostType/Restriction.php:517 +msgid "Problem solved" msgstr "" -#: templates/booking-single-form.php:8 -msgid "Cancel booking process" +#: src/Wordpress/CustomPostType/Timeframe.php:105 +msgid "Max. Booking Duration" msgstr "" -#: templates/booking-single-form.php:13 -msgid "Confirm Booking" +#: src/Wordpress/CustomPostType/Timeframe.php:124 +msgid "All timeframe types" msgstr "" -#: templates/booking-single-form.php:18 -msgid "Add to Calendar" +#: src/Wordpress/CustomPostType/Timeframe.php:130 +msgid "Bookable" msgstr "" -#: templates/booking-single-form.php:19 -msgid "Cancel Booking" +#: src/Wordpress/CustomPostType/Timeframe.php:131 +msgid "Holidays or location closed" msgstr "" -#: templates/booking-single-notallowed.php:10 -msgid "You are not allowed to access this booking." +#: src/Wordpress/CustomPostType/Timeframe.php:134 +msgid "Blocked (not overbookable)" msgstr "" -#: templates/booking-single-notallowed.php:14 -#: templates/timeframe-notallowed.php:14 -msgid "Login to your account" +#: src/Wordpress/CustomPostType/Timeframe.php:161 +msgid "Select Dates:" msgstr "" -#: templates/booking-single.php:45 -#: templates/timeframe-calendar.php:49 -msgid "Pickup" +#: src/Wordpress/CustomPostType/Timeframe.php:451 +#: src/Wordpress/CustomPostType/Timeframe.php:1145 +msgid "Timeframe" msgstr "" -#: templates/booking-single.php:49 -#: templates/timeframe-calendar.php:60 -msgid "Return" +#: src/Wordpress/CustomPostType/Timeframe.php:480 +msgid "This comment is internal for timeframes like bookable, repair, holiday. If timeframe is a booking this comment can be set by users during the booking confirmation process." msgstr "" -#: templates/booking-single.php:70 -msgid "Location: " +#: src/Wordpress/CustomPostType/Timeframe.php:487 +msgid "Select Type of this timeframe: Bookable or Location Closed. See Documentation for detailed information." msgstr "" -#: templates/booking-single.php:95 -#: templates/booking-single.php:103 -msgid "Contact" +#: src/Wordpress/CustomPostType/Timeframe.php:502 +msgid "Location Category Selection" msgstr "" -#: templates/booking-single.php:115 -msgid "Your profile" +#: src/Wordpress/CustomPostType/Timeframe.php:510 +msgid "Location Selection" msgstr "" -#: templates/booking-single.php:121 -msgid "Admin Booking by" +#: src/Wordpress/CustomPostType/Timeframe.php:513 +#: src/Wordpress/CustomPostType/Timeframe.php:551 +msgid "Please select" msgstr "" -#: templates/booking-single.php:140 -msgid "Your E-Mail" +#: src/Wordpress/CustomPostType/Timeframe.php:518 +msgid "Select one or more locations" msgstr "" -#: templates/booking-single.php:144 -msgid "Your data" +#: src/Wordpress/CustomPostType/Timeframe.php:525 +msgid "Item Selection" msgstr "" -#: templates/calendar-key.php:12 -msgid "Color legend" +#: src/Wordpress/CustomPostType/Timeframe.php:533 +msgid "Select one or more items" msgstr "" -#: templates/calendar-key.php:13 -msgid "bookable" +#: src/Wordpress/CustomPostType/Timeframe.php:540 +msgid "Item Category Selection" msgstr "" -#: templates/calendar-key.php:14 -msgid "booked/blocked" +#: src/Wordpress/CustomPostType/Timeframe.php:548 +msgid "Item selection" msgstr "" -#: templates/calendar-key.php:15 -msgid "station closed" +#: src/Wordpress/CustomPostType/Timeframe.php:556 +msgid "Configure bookings" msgstr "" -#: templates/calendar-key.php:16 -msgid "not bookable" +#: src/Wordpress/CustomPostType/Timeframe.php:561 +msgid "Maximum" msgstr "" -#: templates/dashboard-index.php:17 -msgid "Support" +#: src/Wordpress/CustomPostType/Timeframe.php:562 +msgid "days in a row" msgstr "" -#: templates/dashboard-index.php:19 -msgid "Documentation & Tutorials" +#: src/Wordpress/CustomPostType/Timeframe.php:574 +msgid "Lead time:" msgstr "" -#: templates/dashboard-index.php:20 -msgid "Support E-Mail" +#: src/Wordpress/CustomPostType/Timeframe.php:575 +msgid "Enter the number of days that should be blocked for bookings as a booking lead time (calculated from the current day)." msgstr "" -#: templates/dashboard-index.php:21 -msgid "Contact & Newsletter" +#: src/Wordpress/CustomPostType/Timeframe.php:587 +msgid "Calendar shows as bookable" msgstr "" -#: templates/dashboard-index.php:23 -msgid "CommonsBooking Version" +#: src/Wordpress/CustomPostType/Timeframe.php:588 +msgid "Select for how many days in advance the calendar should display bookable days. Calculated from the current date." msgstr "" -#: templates/dashboard-index.php:31 -msgid "Setup and manage Items, Locations and Timeframes" +#: src/Wordpress/CustomPostType/Timeframe.php:600 +msgid "Allowed for" msgstr "" -#: templates/dashboard-index.php:43 -msgid "See Bookings & manage restrictions" +#: src/Wordpress/CustomPostType/Timeframe.php:602 +msgid "
    Select one or more user roles that will be allowed to book the item exclusively.
    Leave this blank to allow all users to book the item. " msgstr "" -#: templates/dashboard-index.php:52 -msgid "Configuration" +#: src/Wordpress/CustomPostType/Timeframe.php:606 +msgid "User roles" msgstr "" -#: templates/dashboard-index.php:57 -msgid "Settings" +#: src/Wordpress/CustomPostType/Timeframe.php:611 +msgid "Configure timeframe" msgstr "" -#: templates/dashboard-index.php:69 -msgid "Today's pickups" +#: src/Wordpress/CustomPostType/Timeframe.php:616 +msgid "Full day" msgstr "" -#: templates/dashboard-index.php:76 -msgid "No pickups today" +#: src/Wordpress/CustomPostType/Timeframe.php:617 +msgid "If this option is selected, users can choose only whole days for pickup and return. No specific time slots for pickup or return are offered. Select this option if the pickup/return should be arranged personally between the location and the user. " msgstr "" -#: templates/dashboard-index.php:82 -msgid "Today's returns" +#: src/Wordpress/CustomPostType/Timeframe.php:626 +msgid "Grid" msgstr "" -#: templates/dashboard-index.php:89 -msgid "No returns today" +#: src/Wordpress/CustomPostType/Timeframe.php:627 +msgid "Choose whether users can only select the entire from/to time period when booking (full slot) or book within the time period in an hourly grid. See the documentation: Manage Booking Timeframes" msgstr "" -#. translators: %1$s: wp_login_url, 1$s: wp_registration_url -#: templates/item-single.php:42 -#: templates/location-single.php:42 -msgid "To be able to book, you must first login or register." +#: src/Wordpress/CustomPostType/Timeframe.php:634 +msgid "Start time" msgstr "" -#: templates/location-calendar-header.php:31 -msgid "Pickup instructions:" +#: src/Wordpress/CustomPostType/Timeframe.php:651 +msgid "End time" msgstr "" -#: templates/location-single-meta.php:23 -msgid "Adress" +#: src/Wordpress/CustomPostType/Timeframe.php:668 +msgid "Timeframe Repetition" msgstr "" -#: templates/location-single-meta.php:34 -msgid "Location contact" +#: src/Wordpress/CustomPostType/Timeframe.php:669 +msgid "Choose whether the time frame should repeat at specific intervals. The repetitions refer to the unit of a day. With the start and end date you define when the repetition interval starts and ends. If you choose \"weekly\", you can select specific days of the week below. Read the documentation for more information and examples." msgstr "" -#: templates/map-admin-page-template.php:9 -msgid "These settings help you to configure the usage and appearance of Commons Booking Map." +#: src/Wordpress/CustomPostType/Timeframe.php:679 +msgid "Import holidays" msgstr "" -#: templates/map-admin-page-template.php:13 -msgid "Map Presentation" +#: src/Wordpress/CustomPostType/Timeframe.php:680 +msgid "Select the year and state to import holidays for (as of now only German holidays are supported)" msgstr "" -#: templates/map-admin-page-template.php:17 -msgid "shortcode" +#: src/Wordpress/CustomPostType/Timeframe.php:687 +msgid "Configure repetition" msgstr "" -#: templates/map-admin-page-template.php:19 -msgid "with this shortcode the map can be included in posts or pages" +#: src/Wordpress/CustomPostType/Timeframe.php:688 +msgid "Below you can make settings regarding the time frame repetition. " msgstr "" -#: templates/map-admin-page-template.php:25 -msgid "base map" +#: src/Wordpress/CustomPostType/Timeframe.php:693 +msgid "Selected manual dates" msgstr "" -#: templates/map-admin-page-template.php:27 -msgid "the base map defines the rendering style of the map tiles" +#: src/Wordpress/CustomPostType/Timeframe.php:694 +msgid "Enter the dates in the YYYY-MM-DD format here, the dates are separated by a comma.
    Example: 2023-05-24,2023-06-24
    You can also use the datepicker above to pick dates for this field." msgstr "" -#: templates/map-admin-page-template.php:32 -msgid "OSM - mapnik" +#: src/Wordpress/CustomPostType/Timeframe.php:701 +msgid "Set the start date. If you have selected repetition, this is the start date of the interval. " msgstr "" -#: templates/map-admin-page-template.php:33 -msgid "OSM - german style" +#: src/Wordpress/CustomPostType/Timeframe.php:709 +msgid "Weekdays" msgstr "" -#: templates/map-admin-page-template.php:42 -msgid "show scale" +#: src/Wordpress/CustomPostType/Timeframe.php:713 +msgid "Monday" msgstr "" -#: templates/map-admin-page-template.php:44 -msgid "show the current scale in the left bottom corner of the map" +#: src/Wordpress/CustomPostType/Timeframe.php:714 +msgid "Tuesday" msgstr "" -#: templates/map-admin-page-template.php:52 -msgid "map height" +#: src/Wordpress/CustomPostType/Timeframe.php:715 +msgid "Wednesday" msgstr "" -#: templates/map-admin-page-template.php:54 -msgid "the height the map is rendered with - the width is the same as of the parent element" +#: src/Wordpress/CustomPostType/Timeframe.php:716 +msgid "Thursday" msgstr "" -#: templates/map-admin-page-template.php:63 -msgid "no locations message" +#: src/Wordpress/CustomPostType/Timeframe.php:717 +msgid "Friday" msgstr "" -#: templates/map-admin-page-template.php:65 -msgid "in case a user filters locations and gets no result, a message is shown - here the text can be customized" +#: src/Wordpress/CustomPostType/Timeframe.php:718 +msgid "Saturday" msgstr "" -#: templates/map-admin-page-template.php:73 -msgid "enable data export" +#: src/Wordpress/CustomPostType/Timeframe.php:719 +msgid "Sunday" msgstr "" -#: templates/map-admin-page-template.php:75 -msgid "activate to enable a button that allows the export of map data (geojson format)" +#: src/Wordpress/CustomPostType/Timeframe.php:725 +msgid "" +"Set the end date. If you have selected repetition, this is the end date of the interval. Leave blank if you do not want to set an end date.\n" +"
    Notice: If you want to select only one day (e.g. for holidays or blocked days) set the start and the end date to same day." msgstr "" -#: templates/map-admin-page-template.php:86 -msgid "Zoom" +#: src/Wordpress/CustomPostType/Timeframe.php:734 +#: src/Wordpress/CustomPostType/Timeframe.php:758 +#: src/Wordpress/CustomPostType/Timeframe.php:781 +msgid "Booking Codes" msgstr "" -#: templates/map-admin-page-template.php:90 -msgid "min. zoom level" +#: src/Wordpress/CustomPostType/Timeframe.php:735 +msgid "" +"You can automatically generate booking codes. Codes can be generated only with the following settings:
    \n" +"\t\t\t\t- Whole day is enabled
    \n" +"\t\t\t\t- Timeframe is bookable
    \n" +"\t\t\t\tMore Information in the documentation\n" +"\t\t\t\t" msgstr "" -#: templates/map-admin-page-template.php:92 -msgid "the minimal zoom level a user can choose" +#: src/Wordpress/CustomPostType/Timeframe.php:744 +msgid "Create Booking Codes" msgstr "" -#: templates/map-admin-page-template.php:100 -msgid "max. zoom level" +#: src/Wordpress/CustomPostType/Timeframe.php:745 +msgid "Select to generate booking codes for each day within the start/end date. The booking codes will be generated after clicking \"Save / Update\"." msgstr "" -#: templates/map-admin-page-template.php:102 -msgid "the maximal zoom level a user can choose" +#: src/Wordpress/CustomPostType/Timeframe.php:751 +msgid "Show Booking Codes" msgstr "" -#: templates/map-admin-page-template.php:110 -msgid "start zoom level" +#: src/Wordpress/CustomPostType/Timeframe.php:752 +msgid "Select whether users should be shown a booking code when booking." msgstr "" -#: templates/map-admin-page-template.php:112 -msgid "the zoom level that will be set when the map is loaded" +#: src/Wordpress/CustomPostType/Timeframe.php:764 +msgid "Send booking codes automated by email" msgstr "" -#: templates/map-admin-page-template.php:120 -msgid "enable scroll wheel zoom" +#: src/Wordpress/CustomPostType/Timeframe.php:765 +msgid "Enable automated sending of booking codes by email" msgstr "" -#: templates/map-admin-page-template.php:122 -msgid "when activated users can zoom the map using the scroll wheel" +#: src/Wordpress/CustomPostType/Timeframe.php:767 +msgid "First day to send Codes (List starts at next month)
    (Same day will be used for subsequent messages) " msgstr "" -#: templates/map-admin-page-template.php:133 -msgid "Map Positioning (center) at Intialization" +#: src/Wordpress/CustomPostType/Timeframe.php:770 +msgid "Months to send" msgstr "" -#: templates/map-admin-page-template.php:137 -msgid "start latitude" +#: src/Wordpress/CustomPostType/Timeframe.php:771 +msgid "Send booking codes for this amount of month's in one email" msgstr "" -#: templates/map-admin-page-template.php:139 -msgid "the latitude of the map center when the map is loaded" +#: src/Wordpress/CustomPostType/Timeframe.php:773 +msgid "Next email planned for: " msgstr "" -#: templates/map-admin-page-template.php:147 -msgid "start longitude" +#: src/Wordpress/CustomPostType/Timeframe.php:774 +msgid "(not planned)" msgstr "" -#: templates/map-admin-page-template.php:149 -msgid "the longitude of the map center when the map is loaded" +#: src/Wordpress/CustomPostType/Timeframe.php:820 +msgid "Manual selection" msgstr "" -#: templates/map-admin-page-template.php:160 -msgid "Adaptive Map Section" +#: src/Wordpress/CustomPostType/Timeframe.php:821 +msgid "Select by category" msgstr "" -#: templates/map-admin-page-template.php:164 -msgid "initial adjustment to marker bounds" +#: src/Wordpress/CustomPostType/Timeframe.php:822 +#: templates/shortcode-bookings.php:54 +msgid "All" msgstr "" -#: templates/map-admin-page-template.php:166 -msgid "adjust map section to bounds of shown markers automatically when map is loaded" +#: src/Wordpress/CustomPostType/Timeframe.php:832 +msgid "Full slot" msgstr "" -#: templates/map-admin-page-template.php:175 -msgid "adjustment to marker bounds on filter" +#: src/Wordpress/CustomPostType/Timeframe.php:833 +msgid "Hourly" msgstr "" -#: templates/map-admin-page-template.php:177 -msgid "adjust map section to bounds of shown markers automatically when filtered by users" +#: src/Wordpress/CustomPostType/Timeframe.php:843 +msgid "No repetition" msgstr "" -#: templates/map-admin-page-template.php:190 -msgid "Marker Tooltip" +#: src/Wordpress/CustomPostType/Timeframe.php:844 +msgid "Manual repetition" msgstr "" -#: templates/map-admin-page-template.php:195 -msgid "show permanently" +#: src/Wordpress/CustomPostType/Timeframe.php:845 +msgid "Daily" msgstr "" -#: templates/map-admin-page-template.php:197 -msgid "activate to show the marker tooltips permanently" +#: src/Wordpress/CustomPostType/Timeframe.php:846 +msgid "Weekly" msgstr "" -#: templates/map-admin-page-template.php:207 -msgid "Marker Popup" +#: src/Wordpress/CustomPostType/Timeframe.php:847 +msgid "Monthly" msgstr "" -#: templates/map-admin-page-template.php:215 -msgid "show location opening hours" +#: src/Wordpress/CustomPostType/Timeframe.php:848 +msgid "Yearly" msgstr "" -#: templates/map-admin-page-template.php:217 -msgid "activate to show the opening hours of locations in the marker popup" +#: src/Wordpress/CustomPostType/Timeframe.php:932 +msgid "Orphaned bookings found, can migrate. Click here to migrate " msgstr "" -#: templates/map-admin-page-template.php:224 -#: templates/map-admin-page-template.php:244 -msgid "label for opening hours" +#: src/Wordpress/CustomPostType/Timeframe.php:1147 +#: src/Wordpress/CustomPostType/Timeframe.php:1149 +msgid "Add new timeframe" msgstr "" -#: templates/map-admin-page-template.php:227 -msgid "alternative label for the opening hours of locations in the marker popup" +#: src/Wordpress/CustomPostType/Timeframe.php:1148 +msgid "Edit timeframe" msgstr "" -#: templates/map-admin-page-template.php:235 -msgid "show location contact" +#: src/Wordpress/CustomPostType/Timeframe.php:1150 +msgid "Show timeframe" msgstr "" -#: templates/map-admin-page-template.php:237 -msgid "activate to show the location contact details in the marker popup" +#: src/Wordpress/CustomPostType/Timeframe.php:1151 +msgid "Show timeframes" msgstr "" -#: templates/map-admin-page-template.php:246 -msgid "alternative label for the contact information of locations in the marker popup" +#: src/Wordpress/CustomPostType/Timeframe.php:1152 +msgid "Search timeframes" msgstr "" -#: templates/map-admin-page-template.php:255 -msgid "show item availability" +#: src/Wordpress/CustomPostType/Timeframe.php:1153 +msgid "Timeframes not found" msgstr "" -#: templates/map-admin-page-template.php:257 -msgid "activate to show the item availability in the marker popup" +#: src/Wordpress/CustomPostType/Timeframe.php:1154 +msgid "No timeframes found in trash" msgstr "" -#: templates/map-admin-page-template.php:266 -msgid "Max. available days in popup" +#: src/Wordpress/CustomPostType/Timeframe.php:1155 +msgid "Parent timeframes:" msgstr "" -#: templates/map-admin-page-template.php:271 -msgid "Set how many days are displayed on the popup (starting from today)" +#: src/Wordpress/CustomPostType/Timeframe.php:1156 +msgid "All timeframes" msgstr "" -#: templates/map-admin-page-template.php:284 -msgid "Maximum days to choose in map availabilty filter " +#: src/Wordpress/CustomPostType/Timeframe.php:1159 +msgid "Add to timeframe" msgstr "" -#: templates/map-admin-page-template.php:289 -msgid "Notice: Defines the maximun days a user can choose in the availabilty filter in frontend map" +#: src/Wordpress/CustomPostType/Timeframe.php:1160 +msgid "Added to timeframe" msgstr "" -#: templates/map-admin-page-template.php:303 -msgid "Custom Marker" +#: src/Wordpress/CustomPostType/Timeframe.php:1162 +msgid "set timeframe image" msgstr "" -#: templates/map-admin-page-template.php:307 -#: templates/map-admin-page-template.php:393 -#: templates/map-admin-page-template.php:468 -msgid "image file" +#: src/Wordpress/CustomPostType/Timeframe.php:1163 +msgid "remove timeframe image" msgstr "" -#: templates/map-admin-page-template.php:309 -#: templates/map-admin-page-template.php:395 -#: templates/map-admin-page-template.php:470 -msgid "the default marker icon can be replaced by a custom image" +#: src/Wordpress/CustomPostType/Timeframe.php:1164 +msgid "use as timeframe image" msgstr "" -#: templates/map-admin-page-template.php:313 -#: templates/map-admin-page-template.php:399 -#: templates/map-admin-page-template.php:474 -msgid "select" +#: src/Wordpress/Options/AdminOptions.php:54 +msgid "Default values for following fields automatically set or restored, because they were empty:
    " msgstr "" -#: templates/map-admin-page-template.php:315 -#: templates/map-admin-page-template.php:401 -#: templates/map-admin-page-template.php:476 -msgid "remove" +#: src/Wordpress/Options/OptionsTab.php:56 +msgid "CommonsBooking" msgstr "" -#: templates/map-admin-page-template.php:334 -#: templates/map-admin-page-template.php:420 -#: templates/map-admin-page-template.php:495 -msgid "icon size" +#: src/Wordpress/Options/OptionsTab.php:148 +msgid "The export path does not exist or is not readable." msgstr "" -#: templates/map-admin-page-template.php:336 -#: templates/map-admin-page-template.php:422 -#: templates/map-admin-page-template.php:497 -msgid "the size of the custom marker icon image as it is shown on the map" +#: src/Wordpress/Options/OptionsTab.php:156 +msgid "The export path is not writeable." msgstr "" -#: templates/map-admin-page-template.php:350 -#: templates/map-admin-page-template.php:510 -msgid "anchor point" +#: src/Wordpress/Options/OptionsTab.php:167 +msgid "Cache cleared." msgstr "" -#: templates/map-admin-page-template.php:352 -#: templates/map-admin-page-template.php:512 -msgid "the position of the anchor point of the icon image, seen from the left top corner of the icon, often it is half of the width and full height of the icon size - this point is used to place the marker on the geo coordinates" +#: src/Wordpress/Options/OptionsTab.php:175 +msgid "Error while clearing the cache." msgstr "" -#: templates/map-admin-page-template.php:369 -msgid "Cluster" +#: src/Wordpress/Widget/UserWidget.php:18 +msgid "Shows links to My Bookings, Login, Logout. Please set the Bookings Page in CommonsBooking Settings (General-Tab)" msgstr "" -#: templates/map-admin-page-template.php:373 -msgid "max. cluster radius" +#. translators: $s = user first name or email +#: src/Wordpress/Widget/UserWidget.php:73 +msgid "Welcome %s" msgstr "" -#: templates/map-admin-page-template.php:375 -msgid "combine markers to a cluster within given radius - 0 for deactivation" +#. translators: $s = bookings page url +#: src/Wordpress/Widget/UserWidget.php:76 +msgid "
  • My Bookings
  • " msgstr "" -#: templates/map-admin-page-template.php:388 -msgid "Custom Cluster Marker" +#. translators: $s = user profile url +#: src/Wordpress/Widget/UserWidget.php:78 +msgid "
  • My Profile
  • " msgstr "" -#: templates/map-admin-page-template.php:440 -msgid "Appearance by Item Status" +#. translators: $s = wp logout url +#: src/Wordpress/Widget/UserWidget.php:80 +msgid "
  • Log out
  • " msgstr "" -#: templates/map-admin-page-template.php:445 -msgid "appearance" +#: src/Wordpress/Widget/UserWidget.php:85 +msgid "You are not logged in." msgstr "" -#: templates/map-admin-page-template.php:447 -msgid "how locations with items that are in draft status should be handled" +#. translators: $s = wp login url +#: src/Wordpress/Widget/UserWidget.php:88 +msgid "
  • Login
  • " msgstr "" -#: templates/map-admin-page-template.php:452 -msgid "don't show drafts" +#. translators: $s = wp registration url +#: src/Wordpress/Widget/UserWidget.php:90 +msgid "
  • Register
  • " msgstr "" -#: templates/map-admin-page-template.php:453 -msgid "show only drafts" +#: src/Wordpress/Widget/UserWidget.php:109 +msgid "Title:" msgstr "" -#: templates/map-admin-page-template.php:454 -msgid "show all together" +#: src/Wordpress/Widget/UserWidget.php:115 +msgid "Text:" msgstr "" -#: templates/map-admin-page-template.php:464 -msgid "Custom Item Draft Marker" +#: templates/booking-single-form.php:8 +msgid "Cancel booking process" msgstr "" -#: templates/map-admin-page-template.php:529 -msgid "Filter for Users" +#: templates/booking-single-form.php:13 +msgid "Confirm Booking" msgstr "" -#: templates/map-admin-page-template.php:533 -msgid "show location distance filter" +#: templates/booking-single-form.php:18 +msgid "Add to Calendar" msgstr "" -#: templates/map-admin-page-template.php:535 -msgid "activate to show the location distance filter" +#: templates/booking-single-form.php:19 +msgid "Cancel Booking" msgstr "" -#: templates/map-admin-page-template.php:542 -msgid "label for location distance filter" +#: templates/booking-single-notallowed.php:10 +msgid "You are not allowed to access this booking." msgstr "" -#: templates/map-admin-page-template.php:544 -msgid "alternative label for the location distance filter" +#: templates/booking-single-notallowed.php:14 +#: templates/timeframe-notallowed.php:14 +msgid "Login to your account" msgstr "" -#: templates/map-admin-page-template.php:552 -msgid "address search bounds - left bottom" +#: templates/booking-single.php:45 +#: templates/timeframe-calendar.php:49 +msgid "Pickup" msgstr "" -#: templates/map-admin-page-template.php:554 -msgid "the bottom left corner of the address search bounds" +#: templates/booking-single.php:49 +#: templates/timeframe-calendar.php:60 +msgid "Return" msgstr "" -#: templates/map-admin-page-template.php:558 -#: templates/map-admin-page-template.php:575 -msgid "longitude" +#: templates/booking-single.php:70 +msgid "Location: " msgstr "" -#: templates/map-admin-page-template.php:562 -#: templates/map-admin-page-template.php:579 -msgid "latitude" +#: templates/booking-single.php:95 +#: templates/booking-single.php:103 +msgid "Contact" msgstr "" -#: templates/map-admin-page-template.php:569 -msgid "address search bounds - right top" +#: templates/booking-single.php:115 +msgid "Your profile" msgstr "" -#: templates/map-admin-page-template.php:571 -msgid "the top right corner of the address search bounds" +#: templates/booking-single.php:121 +msgid "Admin Booking by" msgstr "" -#: templates/map-admin-page-template.php:586 -msgid "show item availability filter" +#: templates/booking-single.php:140 +msgid "Your E-Mail" msgstr "" -#: templates/map-admin-page-template.php:588 -msgid "activate to show the item availability filter" +#: templates/booking-single.php:144 +msgid "Your data" msgstr "" -#: templates/map-admin-page-template.php:595 -msgid "label for item availability filter" +#: templates/calendar-key.php:12 +msgid "Color legend" msgstr "" -#: templates/map-admin-page-template.php:597 -msgid "alternative label for the item availability filter" +#: templates/calendar-key.php:13 +msgid "bookable" msgstr "" -#: templates/map-admin-page-template.php:605 -msgid "label for item category filter" +#: templates/calendar-key.php:14 +msgid "booked/blocked" msgstr "" -#: templates/map-admin-page-template.php:607 -msgid "alternative label for the item category filter" +#: templates/calendar-key.php:15 +msgid "station closed" msgstr "" -#: templates/map-admin-page-template.php:616 -msgid "custom text for filter button" +#: templates/calendar-key.php:16 +msgid "not bookable" msgstr "" -#: templates/map-admin-page-template.php:618 -msgid "the text for the button used for filtering" +#: templates/dashboard-index.php:17 +msgid "Support" msgstr "" -#: templates/map-admin-page-template.php:626 -msgid "available categories" +#: templates/dashboard-index.php:19 +msgid "Documentation & Tutorials" msgstr "" -#: templates/map-admin-page-template.php:628 -msgid "select the categories that are presented the users to filter items - none for no filters" +#: templates/dashboard-index.php:20 +msgid "Support E-Mail" msgstr "" -#: templates/map-admin-page-template.php:642 -msgid "grouping of and custom markup for filters" +#: templates/dashboard-index.php:21 +msgid "Contact & Newsletter" msgstr "" -#: templates/map-admin-page-template.php:645 -msgid "add filter group" +#: templates/dashboard-index.php:23 +msgid "CommonsBooking Version" msgstr "" -#: templates/map-admin-page-template.php:654 -msgid "Filter Item Presets" +#: templates/dashboard-index.php:31 +msgid "Setup and manage Items, Locations and Timeframes" msgstr "" -#: templates/map-admin-page-template.php:658 -#: templates/map-admin-page-template.php:680 -msgid "preset categories" +#: templates/dashboard-index.php:43 +msgid "See Bookings & manage restrictions" msgstr "" -#: templates/map-admin-page-template.php:660 -msgid "select the categories that are used to prefilter the items that are shown on the map - none for all items" +#: templates/dashboard-index.php:52 +msgid "Configuration" msgstr "" -#: templates/map-admin-page-template.php:676 -msgid "Filter Location Presets" +#: templates/dashboard-index.php:57 +msgid "Settings" msgstr "" -#: templates/map-admin-page-template.php:682 -msgid "select the categories that are used to prefilter the location categories that are shown on the map - none for all locations" +#: templates/dashboard-index.php:69 +msgid "Today's pickups" msgstr "" -#: templates/map-admin-page-template.php:741 -msgid "filter group" +#: templates/dashboard-index.php:76 +msgid "No pickups today" msgstr "" -#: templates/map-admin-page-template.php:741 -msgid "group name" +#: templates/dashboard-index.php:82 +msgid "Today's returns" msgstr "" -#: templates/map-admin-page-template.php:744 -msgid "remove filter group" +#: templates/dashboard-index.php:89 +msgid "No returns today" msgstr "" -#: templates/map-settings-page-template.php:9 -msgid "Settings for the Map" +#. translators: %1$s: wp_login_url, 1$s: wp_registration_url +#: templates/item-single.php:42 +#: templates/location-single.php:42 +msgid "To be able to book, you must first login or register." msgstr "" -#: templates/map-settings-page-template.php:11 -msgid "general settings regarding the behaviour of the Map" +#: templates/location-calendar-header.php:31 +msgid "Pickup instructions:" msgstr "" -#: templates/map-settings-page-template.php:22 -msgid "replace map link on booking page" +#: templates/location-single-meta.php:23 +msgid "Adress" msgstr "" -#: templates/map-settings-page-template.php:23 -msgid "set the target of the map link on booking page to openstreetmap" +#: templates/location-single-meta.php:34 +msgid "Location contact" msgstr "" #: templates/massoperations-index.php:7 diff --git a/package-lock.json b/package-lock.json index f67a61367..492bd5b09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,9 +21,9 @@ }, "devDependencies": { "@babel/preset-env": "^7.26.0", - "@wordpress/env": "^10.12.0", + "@wordpress/env": "^10.15.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", - "cypress": "^13.16.0", + "cypress": "^13.17.0", "editorconfig": "^2.0.0", "grunt": "^1.6.1", "grunt-babel": "^8.0.0", @@ -36,7 +36,7 @@ "grunt-contrib-watch": "^1.1.0", "grunt-dart-sass": "^2.0.1", "matchdep": "^2.0.0", - "sass": "^1.81.0" + "sass": "^1.83.1" } }, "node_modules/@ampproject/remapping": { @@ -1589,6 +1589,407 @@ "vue": "^3.2.0" } }, + "node_modules/@inquirer/checkbox": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.0.4.tgz", + "integrity": "sha512-fYAKCAcGNMdfjL6hZTRUwkIByQ8EIZCXKrIQZH7XjADnN/xvRUhj8UdBbpC4zoUzvChhkSC/zRKaP/tDs3dZpg==", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.1.2", + "@inquirer/figures": "^1.0.9", + "@inquirer/type": "^3.0.2", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/confirm": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.1.tgz", + "integrity": "sha512-vVLSbGci+IKQvDOtzpPTCOiEJCNidHcAq9JYVoWTW0svb5FiwSLotkM+JXNXejfjnzVYV9n0DTBythl9+XgTxg==", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.1.2", + "@inquirer/type": "^3.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/core": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.1.2.tgz", + "integrity": "sha512-bHd96F3ezHg1mf/J0Rb4CV8ndCN0v28kUlrHqP7+ECm1C/A+paB7Xh2lbMk6x+kweQC+rZOxM/YeKikzxco8bQ==", + "dev": true, + "dependencies": { + "@inquirer/figures": "^1.0.9", + "@inquirer/type": "^3.0.2", + "ansi-escapes": "^4.3.2", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@inquirer/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@inquirer/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@inquirer/core/node_modules/mute-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", + "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "dev": true, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/@inquirer/core/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@inquirer/core/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@inquirer/editor": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.1.tgz", + "integrity": "sha512-xn9aDaiP6nFa432i68JCaL302FyL6y/6EG97nAtfIPnWZ+mWPgCMLGc4XZ2QQMsZtu9q3Jd5AzBPjXh10aX9kA==", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.1.2", + "@inquirer/type": "^3.0.2", + "external-editor": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/expand": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.4.tgz", + "integrity": "sha512-GYocr+BPyxKPxQ4UZyNMqZFSGKScSUc0Vk17II3J+0bDcgGsQm0KYQNooN1Q5iBfXsy3x/VWmHGh20QnzsaHwg==", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.1.2", + "@inquirer/type": "^3.0.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/figures": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.9.tgz", + "integrity": "sha512-BXvGj0ehzrngHTPTDqUoDT3NXL8U0RxUk2zJm2A66RhCEIWdtU1v6GuUqNAgArW4PQ9CinqIWyHdQgdwOj06zQ==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@inquirer/input": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.1.1.tgz", + "integrity": "sha512-nAXAHQndZcXB+7CyjIW3XuQZZHbQQ0q8LX6miY6bqAWwDzNa9JUioDBYrFmOUNIsuF08o1WT/m2gbBXvBhYVxg==", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.1.2", + "@inquirer/type": "^3.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/number": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.4.tgz", + "integrity": "sha512-DX7a6IXRPU0j8kr2ovf+QaaDiIf+zEKaZVzCWdLOTk7XigqSXvoh4cul7x68xp54WTQrgSnW7P1WBJDbyY3GhA==", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.1.2", + "@inquirer/type": "^3.0.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/password": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.4.tgz", + "integrity": "sha512-wiliQOWdjM8FnBmdIHtQV2Ca3S1+tMBUerhyjkRCv1g+4jSvEweGu9GCcvVEgKDhTBT15nrxvk5/bVrGUqSs1w==", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.1.2", + "@inquirer/type": "^3.0.2", + "ansi-escapes": "^4.3.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/prompts": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.2.1.tgz", + "integrity": "sha512-v2JSGri6/HXSfoGIwuKEn8sNCQK6nsB2BNpy2lSX6QH9bsECrMv93QHnj5+f+1ZWpF/VNioIV2B/PDox8EvGuQ==", + "dev": true, + "dependencies": { + "@inquirer/checkbox": "^4.0.4", + "@inquirer/confirm": "^5.1.1", + "@inquirer/editor": "^4.2.1", + "@inquirer/expand": "^4.0.4", + "@inquirer/input": "^4.1.1", + "@inquirer/number": "^3.0.4", + "@inquirer/password": "^4.0.4", + "@inquirer/rawlist": "^4.0.4", + "@inquirer/search": "^3.0.4", + "@inquirer/select": "^4.0.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/rawlist": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.0.4.tgz", + "integrity": "sha512-IsVN2EZdNHsmFdKWx9HaXb8T/s3FlR/U1QPt9dwbSyPtjFbMTlW9CRFvnn0bm/QIsrMRD2oMZqrQpSWPQVbXXg==", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.1.2", + "@inquirer/type": "^3.0.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/search": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.0.4.tgz", + "integrity": "sha512-tSkJk2SDmC2MEdTIjknXWmCnmPr5owTs9/xjfa14ol1Oh95n6xW7SYn5fiPk4/vrJPys0ggSWiISdPze4LTa7A==", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.1.2", + "@inquirer/figures": "^1.0.9", + "@inquirer/type": "^3.0.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/select": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.0.4.tgz", + "integrity": "sha512-ZzYLuLoUzTIW9EJm++jBpRiTshGqS3Q1o5qOEQqgzaBlmdsjQr6pA4TUNkwu6OBYgM2mIRbCz6mUhFDfl/GF+w==", + "dev": true, + "dependencies": { + "@inquirer/core": "^10.1.2", + "@inquirer/figures": "^1.0.9", + "@inquirer/type": "^3.0.2", + "ansi-escapes": "^4.3.2", + "yoctocolors-cjs": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.2.tgz", + "integrity": "sha512-ZhQ4TvhwHZF+lGhQ2O/rsjo80XoZR5/5qhOY3t6FJuX5XBg5Be8YzYTvaUGJnc12AUGI2nr4QSUE4PhKSigx7g==", + "dev": true, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -1978,6 +2379,16 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@rokoli/vue-tiny-i18n": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/@rokoli/vue-tiny-i18n/-/vue-tiny-i18n-0.3.0.tgz", @@ -2287,20 +2698,20 @@ } }, "node_modules/@wordpress/env": { - "version": "10.12.0", - "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-10.12.0.tgz", - "integrity": "sha512-+tsdVfngQYcysxdVonXRSwuJjqoqTSv7wwrcThCYXR1OBCMQ/xT2Ywfvf9a/yItJs5uicO9Vx8B5aIuvXiGVqg==", + "version": "10.15.0", + "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-10.15.0.tgz", + "integrity": "sha512-UMd7taPznebwMnW7tHlr+PzRMrCFzPL/rtJZdufxGCCr4MNaAYecb4OjJsuy2w1Bm9erDjTa7BjUEw2V+jWB/Q==", "dev": true, "dependencies": { + "@inquirer/prompts": "^7.2.0", "chalk": "^4.0.0", "copy-dir": "^1.3.0", "docker-compose": "^0.24.3", "extract-zip": "^1.6.7", "got": "^11.8.5", - "inquirer": "^7.1.0", "js-yaml": "^3.13.1", "ora": "^4.0.2", - "rimraf": "^3.0.2", + "rimraf": "^5.0.10", "simple-git": "^3.5.0", "terminal-link": "^2.0.0", "yargs": "^17.3.0" @@ -2328,6 +2739,15 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/@wordpress/env/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, "node_modules/@wordpress/env/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -2362,6 +2782,42 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/@wordpress/env/node_modules/foreground-child": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", + "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@wordpress/env/node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@wordpress/env/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2371,6 +2827,72 @@ "node": ">=8" } }, + "node_modules/@wordpress/env/node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/@wordpress/env/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@wordpress/env/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/@wordpress/env/node_modules/rimraf": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@wordpress/env/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@wordpress/env/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3243,12 +3765,12 @@ } }, "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "dev": true, "engines": { - "node": ">= 10" + "node": ">= 12" } }, "node_modules/cliui": { @@ -3483,9 +4005,9 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/cypress": { - "version": "13.16.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.16.0.tgz", - "integrity": "sha512-g6XcwqnvzXrqiBQR/5gN+QsyRmKRhls1y5E42fyOvsmU7JuY+wM6uHJWj4ZPttjabzbnRvxcik2WemR8+xT6FA==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.17.0.tgz", + "integrity": "sha512-5xWkaPurwkIljojFidhw8lFScyxhtiFHl/i/3zov+1Z5CmY4t9tjIdvSXfu82Y3w7wt0uR9KkucbhkVvJZLQSA==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -4043,6 +4565,12 @@ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", "dev": true }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -6234,100 +6762,6 @@ "node": ">=10" } }, - "node_modules/inquirer": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", - "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.19", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.6.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/inquirer/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/inquirer/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/inquirer/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/inquirer/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/inquirer/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/intercept-stdout": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/intercept-stdout/-/intercept-stdout-0.1.2.tgz", @@ -8522,6 +8956,12 @@ "node": ">=8" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true + }, "node_modules/parse-filepath": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", @@ -8618,6 +9058,37 @@ "node": ">=0.10.0" } }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -9094,27 +9565,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -9143,9 +9593,9 @@ "dev": true }, "node_modules/sass": { - "version": "1.81.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.81.0.tgz", - "integrity": "sha512-Q4fOxRfhmv3sqCLoGfvrC9pRV8btc0UtqL9mN6Yrv6Qi9ScL55CVH1vlPP863ISLEEMNLLuu9P+enCeGHlnzhA==", + "version": "1.83.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.83.1.tgz", + "integrity": "sha512-EVJbDaEs4Rr3F0glJzFSOvtg2/oy2V/YrGFPqPY24UqcLDWcI9ZY5sN+qyO3c/QCZwzgfirvhXvINiJCE/OLcA==", "dev": true, "dependencies": { "chokidar": "^4.0.0", @@ -9717,6 +10167,21 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -9729,6 +10194,19 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -12057,12 +12535,6 @@ "node": ">= 8" } }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -12479,6 +12951,57 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -12590,6 +13113,18 @@ "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } + }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", + "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/package.json b/package.json index bbb8efd6d..cc34e30ea 100644 --- a/package.json +++ b/package.json @@ -10,9 +10,9 @@ }, "devDependencies": { "@babel/preset-env": "^7.26.0", - "@wordpress/env": "^10.12.0", + "@wordpress/env": "^10.15.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", - "cypress": "^13.16.0", + "cypress": "^13.17.0", "editorconfig": "^2.0.0", "grunt": "^1.6.1", "grunt-babel": "^8.0.0", @@ -25,7 +25,7 @@ "grunt-contrib-watch": "^1.1.0", "grunt-dart-sass": "^2.0.1", "matchdep": "^2.0.0", - "sass": "^1.81.0" + "sass": "^1.83.1" }, "scripts": { "start": "composer install --ignore-platform-reqs && npm install && npm run dist", diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 000000000..5cbf5b993 --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,6 @@ +parameters: + ignoreErrors: + - + message: "#^Action callback returns bool but should not return anything\\.$#" + count: 1 + path: src/Wordpress/CustomPostType/CustomPostType.php diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 000000000..cee3f6f33 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,21 @@ +includes: + - phpstan-baseline.neon +parameters: + phpVersion: 70400 + scanFiles: + - commonsbooking.php + - vendor/cmb2/cmb2/includes/helper-functions.php + - vendor/cmb2/cmb2/includes/CMB2_Utils.php + - vendor/cmb2/cmb2/includes/CMB2_Field.php + paths: + - commonsbooking.php + - src/ + - includes/ + level: 0 + ignoreErrors: +# - identifier: missingType.iterableValue +# - '#Constant (COMMONSBOOKING.*|WP_DEBUG_LOG) not found.#' +# - '#Instantiated class (CommonsBooking.*CB_Data) not found.#' + - '#Function cb_object_to_array not found.#' + - + identifier: requireOnce.fileNotFound # https://github.com/szepeviktor/phpstan-wordpress/issues/239 diff --git a/readme.txt b/readme.txt index 6cf3dedc8..d707dc020 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Donate link: https://www.wielebenwir.de/verein/unterstutzen Tags: booking, calendar, sharing, commoning, open-source Requires at least: 5.9 Tested up to: 6.7 -Stable Tag: 2.9.4 +Stable Tag: 2.10.2 Requires PHP: 7.4 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -80,6 +80,31 @@ CommonsBooking was developed for the ["Commons Cargobike" movement](http://commo ## Changelog +### 2.10.2 (14.01.2025) + +FIXED: Language features used that were incompatible with PHP 7.4 + +### 2.10.1 (09.01.2025) +FIXED: Fatal error when loading map with certain timeframe configurations +UPDATED: Dependencies + +### 2.10 (09.01.2025) +ADDED: When changing the location of an item you will now be given the option to move the bookings to the new location. +ENHANCED: Export of timeframes no longer time out. +ENHANCED: Total breakdowns cancelling all bookings can now be disabled. +ENHANCED: Map filter groups are now easier to configure. +ENHANCED: Loading the map should now be significantly faster. +ENHANCED: Greatly simplified booking codes; they will also not be generated for the past anymore. (thx @nelarsen) +ENHANCED: Show past bookings in [cb_bookings] overview. +FIXED: Booking codes now truly random. (thx @nelarsen) +FIXED: Map sometimes not rendering on certain aspects ratios. (thx @kmohrf) +FIXED: Saving posts should now be faster. +FIXED: Cache warmup not working in some cases. +FIXED: In certain overlapping timeframe configurations timeframes were not shown as bookable. (thx @nelarsen) +FIXED: Disabled restriction creation for all items / locations because of a missing permission check. +UPDATED: Dependencies + + ### 2.9.4 (17.07.2024) FIXED: Plugin not usable in multisite mode diff --git a/src/CB/CB1UserFields.php b/src/CB/CB1UserFields.php index a83eaa792..3b701f952 100644 --- a/src/CB/CB1UserFields.php +++ b/src/CB/CB1UserFields.php @@ -11,9 +11,9 @@ class CB1UserFields { /** - * @var false|mixed + * @var mixed */ - private mixed $termsservices_url; + private $termsservices_url; /** * @var array|string[] */ @@ -33,7 +33,7 @@ class CB1UserFields { /** * @var array|mixed */ - private mixed $user_vars; + private $user_vars; public function __construct() { @@ -227,6 +227,7 @@ public function registration_add_meta( $user_id ) { /** * Sets a flat array of user field/value pairs * + * @since 2.10 deprecated (cb_object_to_array is unspecified) * @since 0.6 * */ diff --git a/src/Map/MapAdmin.php b/src/Map/MapAdmin.php deleted file mode 100644 index a8404aeb1..000000000 --- a/src/Map/MapAdmin.php +++ /dev/null @@ -1,550 +0,0 @@ -' + location.location_name + '
    ' + location.address.street + '
    ' + location.address.zip + ' ' + location.address.city + '

    ' + location.opening_hours + '

    '"; - - public static $options; - - public static function add_meta_boxes() { - self::add_settings_meta_box( - 'cb_map_admin', - esc_html__( 'Map Configuration', 'commonsbooking' ) ); - } - - public static function add_settings_meta_box( $meta_box_id, $meta_box_title ) { - $plugin_prefix = 'cb_map_post_type_'; - - $html_id_attribute = $plugin_prefix . $meta_box_id . '_meta_box'; - $callback = array( MapAdmin::class, 'render_options_page' ); - $show_on_post_type = 'cb_map'; - $box_placement = 'normal'; - $box_priority = 'high'; - - add_meta_box( - $html_id_attribute, - $meta_box_title, - $callback, - $show_on_post_type, - $box_placement, - $box_priority - ); - } - - /** - * - **/ - public static function get_options( $cb_map_id = null, $force_reload = false ) { - self::load_options( $cb_map_id, $force_reload ); - - return self::$options; - } - - public static function load_options( $cb_map_id = null, $force_reload = false ) { - if ( ! isset( self::$options ) || $force_reload ) { - if ( $cb_map_id ) { - $options = get_post_meta( $cb_map_id, 'cb_map_options', true ); - - if ( ! is_array( $options ) ) { - $options = []; - } - } else { - $options = []; - } - - self::$options = self::populate_option_defaults( $options ); - } - } - - public static function populate_option_defaults( $options ) { - foreach ( self::OPTION_KEYS as $key ) { - if ( ! isset( $options[ $key ] ) ) { - $options[ $key ] = self::get_option_default( $key ); - } - } - - return $options; - } - - private static function get_option_default( $option_name ) { - $default_name = strtoupper( $option_name ) . '_DEFAULT'; - $const_value = constant( "self::$default_name" ); - - return $const_value ?? null; - } - - /** - * sanitize and validate the options provided by input array - **/ - public static function validate_options( $cb_map_id ) { - self::load_options( $cb_map_id ); - - $validated_input = self::populate_option_defaults( [] ); - - $input = []; - if ( isset( $_POST['cb_map_options'] ) ) { - $input = commonsbooking_sanitizeArrayorString( $_POST['cb_map_options'] ); - } - - //base_map - if ( isset( $input['base_map'] ) && $input['base_map'] >= 1 && $input['base_map'] <= 4 ) { - $validated_input['base_map'] = (int) $input['base_map']; - } - - //map_height - if ( isset( $input['map_height'] ) && (int) $input['map_height'] >= self::MAP_HEIGHT_VALUE_MIN && $input['map_height'] <= self::MAP_HEIGHT_VALUE_MAX ) { - $validated_input['map_height'] = (int) $input['map_height']; - } - - //custom_no_locations_message - if ( isset( $input['custom_no_locations_message'] ) ) { - $validated_input['custom_no_locations_message'] = sanitize_text_field( $input['custom_no_locations_message'] ); - } - - //zoom_min - if ( isset( $input['zoom_min'] ) && (int) $input['zoom_min'] >= self::ZOOM_VALUE_MIN && $input['zoom_min'] <= self::ZOOM_VALUE_MAX ) { - $validated_input['zoom_min'] = (int) $input['zoom_min']; - } - - //zoom_max - if ( isset( $input['zoom_max'] ) && (int) $input['zoom_max'] >= self::ZOOM_VALUE_MIN && $input['zoom_max'] <= self::ZOOM_VALUE_MAX ) { - if ( (int) $input['zoom_max'] >= $validated_input['zoom_min'] ) { - $validated_input['zoom_max'] = (int) $input['zoom_max']; - } else { - $validated_input['zoom_max'] = $validated_input['zoom_min']; - } - } - - //zoom_start - if ( isset( $input['zoom_start'] ) && (int) $input['zoom_start'] >= self::ZOOM_VALUE_MIN && $input['zoom_start'] <= self::ZOOM_VALUE_MAX ) { - if ( (int) $input['zoom_start'] >= $validated_input['zoom_min'] && (int) $input['zoom_start'] <= $validated_input['zoom_max'] ) { - $validated_input['zoom_start'] = (int) $input['zoom_start']; - } else { - $validated_input['zoom_start'] = $validated_input['zoom_min']; - } - } - - //lat_start - if ( self::validateStringInput( $input, 'lat_start' ) && (float) $input['lat_start'] >= self::LAT_VALUE_MIN && (float) $input['lat_start'] <= self::LAT_VALUE_MAX ) { - $validated_input['lat_start'] = (float) $input['lat_start']; - } - - //lon_start - if ( self::validateStringInput( $input, 'lon_start' ) && (float) $input['lon_start'] >= self::LON_VALUE_MIN && (float) $input['lon_start'] <= self::LON_VALUE_MAX ) { - $validated_input['lon_start'] = (float) $input['lon_start']; - } - - //max_cluster_radius - if ( isset( $input['max_cluster_radius'] ) && (int) $input['max_cluster_radius'] >= self::MAX_CLUSTER_RADIUS_VALUE_MIN && $input['max_cluster_radius'] <= self::MAX_CLUSTER_RADIUS_VALUE_MAX ) { - $validated_input['max_cluster_radius'] = (int) $input['max_cluster_radius']; - } - - $checkboxInputs = [ - 'show_scale', - 'marker_map_bounds_initial', - 'marker_map_bounds_filter', - 'marker_tooltip_permanent', - 'show_location_contact', - 'show_location_opening_hours', - 'show_item_availability', - 'show_location_distance_filter', - 'scrollWheelZoom' - ]; - - foreach ( $checkboxInputs as $checkboxInput ) { - $validated_input[ $checkboxInput ] = self::validateCheckboxInput( $input, $checkboxInput ); - } - - $integerInputs = [ - 'custom_marker_media_id', - 'custom_marker_cluster_media_id', - 'marker_item_draft_media_id', - 'availability_max_days_to_show', - 'availability_max_day_count', - ]; - - foreach ( $integerInputs as $integerInput ) { - if ( isset( $input[ $integerInput ] ) ) { - $validated_input[ $integerInput ] = abs( (int) $input[ $integerInput ] ); - } - } - - $floatInputs = [ - 'marker_icon_width', - 'marker_icon_height', - 'marker_icon_anchor_x', - 'marker_icon_anchor_y', - 'marker_cluster_icon_width', - 'marker_cluster_icon_height', - 'marker_item_draft_icon_width', - 'marker_item_draft_icon_height', - 'marker_item_draft_icon_anchor_x', - 'marker_item_draft_icon_anchor_y' - ]; - - foreach ( $floatInputs as $floatInput ) { - if ( isset( $input[ $floatInput ] ) ) { - $validated_input[ $floatInput ] = (float) $input[ $floatInput ]; - } - } - - //label_location_opening_hours - if ( self::validateStringInput( $input, 'label_location_opening_hours' ) ) { - $validated_input['label_location_opening_hours'] = sanitize_text_field( $input['label_location_opening_hours'] ); - } - - - //label_location_contact - if ( self::validateStringInput( $input, 'label_location_contact' ) ) { - $validated_input['label_location_contact'] = sanitize_text_field( $input['label_location_contact'] ); - } - - - //item_draft_appearance - if ( isset( $input['item_draft_appearance'] ) && $input['item_draft_appearance'] >= 1 && $input['item_draft_appearance'] <= 3 ) { - $validated_input['item_draft_appearance'] = $input['item_draft_appearance']; - } - - - //address_search_bounds_left_bottom_lat - if ( self::validateStringInput( $input, 'address_search_bounds_left_bottom_lat' ) && (float) $input['address_search_bounds_left_bottom_lat'] >= self::LAT_VALUE_MIN && (float) $input['address_search_bounds_left_bottom_lat'] <= self::LAT_VALUE_MAX ) { - $validated_input['address_search_bounds_left_bottom_lat'] = (float) $input['address_search_bounds_left_bottom_lat']; - } - - if ( self::validateStringInput( $input, 'address_search_bounds_left_bottom_lon' ) && (float) $input['address_search_bounds_left_bottom_lon'] >= self::LON_VALUE_MIN && (float) $input['address_search_bounds_left_bottom_lon'] <= self::LON_VALUE_MAX ) { - $validated_input['address_search_bounds_left_bottom_lon'] = (float) $input['address_search_bounds_left_bottom_lon']; - } - - //address_search_bounds_right_top_lat - if ( self::validateStringInput( $input, 'address_search_bounds_right_top_lat' ) && (float) $input['address_search_bounds_right_top_lat'] >= self::LAT_VALUE_MIN && (float) $input['address_search_bounds_right_top_lat'] <= self::LAT_VALUE_MAX ) { - $validated_input['address_search_bounds_right_top_lat'] = (float) $input['address_search_bounds_right_top_lat']; - } - - //address_search_bounds_right_top_lon - if ( self::validateStringInput( $input, 'address_search_bounds_right_top_lon' ) && (float) $input['address_search_bounds_right_top_lon'] >= self::LON_VALUE_MIN && (float) $input['address_search_bounds_right_top_lon'] <= self::LON_VALUE_MAX ) { - $validated_input['address_search_bounds_right_top_lon'] = (float) $input['address_search_bounds_right_top_lon']; - } - - //label_location_distance_filter - if ( self::validateStringInput( $input, 'label_location_distance_filter' ) ) { - $validated_input['label_location_distance_filter'] = sanitize_text_field( $input['label_location_distance_filter'] ); - } - - //show_item_availability_filter - if ( isset( $input['show_item_availability_filter'] ) ) { - $validated_input['show_item_availability_filter'] = true; - } else { - $validated_input['show_item_availability_filter'] = false; - } - - //label_item_availability_filter - if ( self::validateStringInput( $input, 'label_item_availability_filter' ) ) { - $validated_input['label_item_availability_filter'] = sanitize_text_field( $input['label_item_availability_filter'] ); - } - - //label_item_category_filter - if ( self::validateStringInput( $input, 'label_item_category_filter' ) ) { - $validated_input['label_item_category_filter'] = sanitize_text_field( $input['label_item_category_filter'] ); - } - - - //custom_filterbutton_label - if ( isset( $input['custom_filterbutton_label'] ) ) { - $validated_input['custom_filterbutton_label'] = sanitize_text_field( $input['custom_filterbutton_label'] ); - } - - //cb_items_available_categories - $category_terms = \CommonsBooking\Repository\Item::getTerms(); - $valid_term_ids = []; - foreach ( $category_terms as $category_term ) { - $valid_term_ids[] = $category_term->term_id; - } - - $loc_category_terms = \CommonsBooking\Repository\Item::getTerms(); - - $valid_loc_term_ids = []; - foreach ( $loc_category_terms as $loc_category_term ) { - $valid_loc_term_ids[] = $loc_category_term->term_id; - } - - if ( isset( $input['cb_items_available_categories'] ) ) { - //first element has to be a filter group and has to contain at least one category - $array_keys = array_keys( $input['cb_items_available_categories'] ); - if ( count( $input['cb_items_available_categories'] ) > 1 && substr( $array_keys[0], 0, - 1 ) == 'g' && substr( $array_keys[1], 0, 1 ) != 'g' ) { - foreach ( $input['cb_items_available_categories'] as $key => $value ) { - //filter group - if ( substr( $key, 0, 1 ) == 'g' ) { - $validated_input['cb_items_available_categories'][ $key ] = sanitize_text_field( $value ); - } //custom markup for category - else { - if ( in_array( (int) $key, $valid_term_ids ) ) { - $validated_input['cb_items_available_categories'][ $key ] = self::strip_script_tags( $value ); - } - } - } - } - } - - //cb_items_preset_categories - if ( isset( $input['cb_items_preset_categories'] ) ) { - foreach ( $input['cb_items_preset_categories'] as $cb_items_category_id ) { - if ( in_array( (int) $cb_items_category_id, $valid_term_ids ) ) { - $validated_input['cb_items_preset_categories'][] = $cb_items_category_id; - } - } - } - - if ( isset( $input['cb_locations_preset_categories'] ) ) { - foreach ( $input['cb_locations_preset_categories'] as $cb_locations_category_id ) { - if ( in_array( (int) $cb_locations_category_id, $valid_loc_term_ids ) ) { - $validated_input['cb_locations_preset_categories'][] = $cb_locations_category_id; - } - } - } - - - update_post_meta( $cb_map_id, 'cb_map_options', $validated_input ); - - return $validated_input; - } - - /** - * @param $input - * @param $key - * - * @return bool - */ - protected static function validateStringInput( $input, $key ): bool { - return isset( $input[ $key ] ) && strlen( $input[ $key ] ) > 0; - } - - /** - * @param $input - * @param $key - * - * @return bool - */ - protected static function validateCheckboxInput( $input, $key ): bool { - return isset( $input[ $key ] ); - } - - public static function strip_script_tags( $input ) { - return preg_replace( '/]*>(.*?)<\/script>/is', '', $input ); - } - - - public static function render_options_page( $post ) { - $cb_map_id = $post->ID; - - wp_enqueue_media(); - - // info: upload script is enqueued in includes/Admin.php - - //map translation - $translation = [ - 'SELECT_IMAGE' => esc_html__( 'Select an image', 'commonsbooking' ), - 'SAVE' => esc_html__( 'save', 'commonsbooking' ), - 'MARKER_IMAGE_MEASUREMENTS' => esc_html__( 'measurements', 'commonsbooking' ), - ]; - echo ''; - - //available categories - $available_categories_args = [ - 'taxonomy' => 'cb_items_category', - 'echo' => false, - 'checked_ontop' => false, - 'selected_cats' => array_keys( self::get_option( $cb_map_id, 'cb_items_available_categories' ) ), - ]; - $available_categories_checklist_markup = wp_terms_checklist( 0, $available_categories_args ); - $available_categories_checklist_markup = str_replace( 'name="tax_input[cb_items_category][]"', - 'class="cb_items_available_category_choice"', $available_categories_checklist_markup ); - $available_categories_checklist_markup = str_replace( 'id="in-cb_items_category-', - 'id="cb_items_available_category-', $available_categories_checklist_markup ); - - //rearrange to nummeric array, because object property order isn't stable in js - $cb_items_available_categories = self::get_option( $cb_map_id, 'cb_items_available_categories' ); - $available_categories = []; - foreach ( $cb_items_available_categories as $id => $content ) { - $available_categories[] = [ - 'id' => (string) $id, - 'content' => $content, - ]; - } - - //preset item categories - $preset_categories_args = [ - 'taxonomy' => 'cb_items_category', - 'echo' => false, - 'checked_ontop' => false, - 'selected_cats' => self::get_option( $cb_map_id, 'cb_items_preset_categories' ), - ]; - $preset_categories_checklist_markup = wp_terms_checklist( 0, $preset_categories_args ); - $preset_categories_checklist_markup = str_replace( 'name="tax_input[cb_items_category]', - 'name="cb_map_options[cb_items_preset_categories]', $preset_categories_checklist_markup ); - $preset_categories_checklist_markup = str_replace( 'id="in-cb_items_category-', 'id="cb_items_preset_category-', - $preset_categories_checklist_markup ); - - //preset location categories - $preset_location_categories_args = [ - 'taxonomy' => 'cb_locations_category', - 'echo' => false, - 'checked_ontop' => false, - 'selected_cats' => self::get_option( $cb_map_id, 'cb_locations_preset_categories' ), - ]; - $preset_location_categories_checklist_markup = wp_terms_checklist( 0, $preset_location_categories_args ); - $preset_location_categories_checklist_markup = str_replace( 'name="tax_input[cb_locations_category]', - 'name="cb_map_options[cb_locations_preset_categories]', $preset_location_categories_checklist_markup ); - $preset_location_categories_checklist_markup = str_replace( 'id="in-cb_locations_category-', 'id="cb_locations_preset_category-', - $preset_location_categories_checklist_markup ); - - wp_enqueue_style( 'cb_map_admin_css', COMMONSBOOKING_MAP_ASSETS_URL . 'css/cb-map-admin.css' ); - - include_once( COMMONSBOOKING_MAP_PATH . 'templates/map-admin-page-template.php' ); - } - - /** - * option getter - * - * @param $cb_map_id - * @param $key - * - * @return mixed - */ - public static function get_option( $cb_map_id, $key ) { - self::load_options( $cb_map_id ); - - if ( array_key_exists( $key, self::$options ) ) { - return is_array((self::$options[ $key ])) ? self::$options[ $key ] : commonsbooking_sanitizeHTML(self::$options[ $key ]); - } else { - return is_array(self::get_option_default( $key )) ? self::get_option_default( $key ) : commonsbooking_sanitizeHTML(self::get_option_default( $key )); - } - } - -} diff --git a/src/Map/MapData.php b/src/Map/MapData.php index 535269a9a..96404c1a0 100644 --- a/src/Map/MapData.php +++ b/src/Map/MapData.php @@ -3,12 +3,15 @@ namespace CommonsBooking\Map; use CommonsBooking\Helper\Wordpress; -use CommonsBooking\Wordpress\CustomPostType\Map; +use CommonsBooking\Model\Map; class MapData { public static function geo_search() { if ( isset( $_POST['query'] ) && $_POST['cb_map_id'] ) { + $map = new Map( $_POST['cb_map_id'] ); + + $check_capacity = true; $attempts = 0; @@ -41,12 +44,11 @@ public static function geo_search() { 'limit' => 1, ]; - $options = MapAdmin::get_options( sanitize_text_field( $_POST['cb_map_id'] ), true ); + if ( $map->getMeta( 'address_search_bounds_left_bottom_lat' ) && $map->getMeta( 'address_search_bounds_left_bottom_lon' ) && $map->getMeta( 'address_search_bounds_right_top_lat' ) && $map->getMeta( 'address_search_bounds_right_top_lon' ) ) { - if ( $options['address_search_bounds_left_bottom_lat'] && $options['address_search_bounds_left_bottom_lon'] && $options['address_search_bounds_right_top_lat'] && $options['address_search_bounds_right_top_lon'] ) { $params['bounded'] = 1; //viewbox - lon1, lat1, lon2, lat2: 12.856779316446545, 52.379790828551016, 13.948545673868422, 52.79694936237738 - $params['viewbox'] = $options['address_search_bounds_left_bottom_lon'] . ',' . $options['address_search_bounds_left_bottom_lat'] . ',' . $options['address_search_bounds_right_top_lon'] . ',' . $options['address_search_bounds_right_top_lat']; + $params['viewbox'] = $map->getMeta( 'address_search_bounds_left_bottom_lon' ) . ',' . $map->getMeta( 'address_search_bounds_left_bottom_lat' ) . ',' . $map->getMeta( 'address_search_bounds_right_top_lon' ) . ',' . $map->getMeta( 'address_search_bounds_right_top_lat' ); } $url = 'https://nominatim.openstreetmap.org/search?' . http_build_query( $params ); @@ -62,7 +64,9 @@ public static function geo_search() { } else { if ( $data['response']['code'] == 200 ) { - if ( Map::is_json( $data['body'] ) ) { + json_decode( $data['body'] ); + // Check if the json is valid + if ( json_last_error() == JSON_ERROR_NONE ) { wp_send_json( $data['body'] ); } else { wp_send_json_error( [ 'error' => 4 ], 403 ); @@ -90,6 +94,7 @@ public static function get_locations() { if ( $post && $post->post_type == 'cb_map' ) { $cb_map_id = $post->ID; + $map = new Map( $cb_map_id ); } else { wp_send_json_error( [ 'error' => 2 ], 400 ); @@ -103,15 +108,16 @@ public static function get_locations() { if ( $post->post_status == 'publish' ) { + $map = new Map( $cb_map_id ); $settings = self::get_settings( $cb_map_id ); $default_date_start = $settings['filter_availability']['date_min']; $default_date_end = $settings['filter_availability']['date_max']; $itemTerms = self::getItemCategoryTerms( $settings ); - $locations = Map::get_locations( $cb_map_id, $itemTerms ); + $locations = $map->get_locations( $itemTerms ); //create availabilities - $show_item_availability = MapAdmin::get_option( $cb_map_id, 'show_item_availability' ); - $show_item_availability_filter = MapAdmin::get_option( $cb_map_id, 'show_item_availability_filter' ); + $show_item_availability = $map->getMeta( 'show_item_availability' ); + $show_item_availability_filter = $map->getMeta( 'show_item_availability_filter' ); if ( $show_item_availability || $show_item_availability_filter ) { $locations = MapItemAvailable::create_items_availabilities( @@ -154,12 +160,13 @@ public static function getItemCategoryTerms( $settings ): array { * get the settings for the frontend of the map with given id **/ public static function get_settings( $cb_map_id ): array { + $map = new Map( $cb_map_id ); $date_min = Wordpress::getUTCDateTime(); $date_min = $date_min->format( 'Y-m-d' ); - $max_days_in_future = MapAdmin::get_option( $cb_map_id, 'availability_max_days_to_show' ); + $max_days_in_future = $map->getMeta( 'availability_max_days_to_show' ); $date_max = Wordpress::getUTCDateTime( $date_min . ' + ' . $max_days_in_future . ' days' ); $date_max = $date_max->format( 'Y-m-d' ); - $maxdays = MapAdmin::get_option( $cb_map_id, 'availability_max_day_count' ); + $maxdays = $map->getMeta( 'availability_max_day_count' ); $settings = [ 'data_url' => get_site_url( null, '', null ) . '/wp-admin/admin-ajax.php', @@ -178,88 +185,112 @@ public static function get_settings( $cb_map_id ): array { 'asset_path' => COMMONSBOOKING_MAP_ASSETS_URL, ]; - $options = MapAdmin::get_options( $cb_map_id, true ); - $pass_through = [ 'base_map', - 'show_scale', 'zoom_min', 'zoom_max', - 'scrollWheelZoom', 'zoom_start', 'lat_start', 'lon_start', + 'max_cluster_radius', + 'label_location_distance_filter', + 'label_item_availability_filter', + 'label_item_category_filter', + ]; + + $pass_through_conditional = [ + 'show_scale', + 'scrollWheelZoom', 'marker_map_bounds_initial', 'marker_map_bounds_filter', - 'max_cluster_radius', 'marker_tooltip_permanent', 'show_location_contact', 'show_location_opening_hours', 'show_item_availability', 'show_location_distance_filter', - 'label_location_distance_filter', 'show_item_availability_filter', - 'label_item_availability_filter', - 'label_item_category_filter', ]; - foreach ( $options as $key => $value ) { - if ( in_array( $key, $pass_through ) ) { - $settings[ $key ] = $value; - } elseif ( $key == 'custom_marker_media_id' ) { - if ( $value != null ) { - $settings['custom_marker_icon'] = [ - 'iconUrl' => wp_get_attachment_url( $options['custom_marker_media_id'] ), - 'iconSize' => [ $options['marker_icon_width'], $options['marker_icon_height'] ], - 'iconAnchor' => [ $options['marker_icon_anchor_x'], $options['marker_icon_anchor_y'] ], - ]; - } - } elseif ( $key == 'marker_item_draft_media_id' ) { - if ( $value != null ) { - $settings['item_draft_marker_icon'] = [ - 'iconUrl' => wp_get_attachment_url( $options['marker_item_draft_media_id'] ), - 'iconSize' => [ - $options['marker_item_draft_icon_width'], - $options['marker_item_draft_icon_height'], - ], //[27, 35], // size of the icon - 'iconAnchor' => [ - $options['marker_item_draft_icon_anchor_x'], - $options['marker_item_draft_icon_anchor_y'], - ], //[13.5, 0], // point of the icon which will correspond to marker's location - ]; - } - } elseif ( $key == 'custom_marker_cluster_media_id' ) { - if ( $value != null ) { - $settings['marker_cluster_icon'] = [ - 'url' => wp_get_attachment_url( $options['custom_marker_cluster_media_id'] ), - 'size' => [ - 'width' => $options['marker_cluster_icon_width'], - 'height' => $options['marker_cluster_icon_height'], - ], - ]; - } - } //categories are only meant to be shown on local maps - elseif ( $key == 'cb_items_available_categories' ) { - $settings['filter_cb_item_categories'] = []; - $current_group_id = null; - foreach ( $options['cb_items_available_categories'] as $categoryKey => $content ) { - if ( substr( $categoryKey, 0, 1 ) == 'g' ) { - $current_group_id = $categoryKey; - $settings['filter_cb_item_categories'][ $categoryKey ] = [ - 'name' => $content, - 'elements' => [], - ]; - } else { - $settings['filter_cb_item_categories'][ $current_group_id ]['elements'][] = [ - 'cat_id' => $categoryKey, - 'markup' => $content, - ]; - } - } + foreach ( $pass_through as $key ) { + $meta = $map->getMeta( $key ); + if ( is_numeric( $meta ) ) { + $meta = floatval( $meta ); + } + $settings[ $key ] = $meta; + } + + foreach ( $pass_through_conditional as $key ) { + $meta = $map->getMeta( $key ); + if ( $meta == 'off' ) { + $settings[ $key ] = false; + } else { + $settings[ $key ] = boolval( $meta ); } + } + if ( $map->getMeta( 'custom_marker_media_id' ) ) { + $settings['custom_marker_icon'] = [ + 'iconUrl' => wp_get_attachment_url( $map->getMeta( 'custom_marker_media_id' ) ), + 'iconSize' => [ + intval( $map->getMeta( 'marker_icon_width' ) ), + intval( $map->getMeta( 'marker_icon_height' ) ) + ], + 'iconAnchor' => [ + intval( $map->getMeta( 'marker_icon_anchor_x' ) ), + intval( $map->getMeta( 'marker_icon_anchor_y' ) ) + ], + ]; } + if ( $map->getMeta( 'marker_item_draft_media_id' ) ) { + $settings['item_draft_marker_icon'] = [ + 'iconUrl' => wp_get_attachment_url( $map->getMeta( 'marker_item_draft_media_id' ) ), + 'iconSize' => [ + intval( $map->getMeta( 'marker_item_draft_icon_width' ) ), + intval( $map->getMeta( 'marker_item_draft_icon_height' ) ) + ], + 'iconAnchor' => [ + intval( $map->getMeta( 'marker_item_draft_icon_anchor_x' ) ), + intval( $map->getMeta( 'marker_item_draft_icon_anchor_y' ) ) + ], + ]; + } + + if ( $map->getMeta( 'custom_marker_cluster_media_id' ) ) { + $settings['marker_cluster_icon'] = [ + 'url' => wp_get_attachment_url( $map->getMeta( 'custom_marker_cluster_media_id' ) ), + 'size' => [ + 'width' => intval( $map->getMeta( 'marker_cluster_icon_width' ) ), + 'height' => intval( $map->getMeta( 'marker_cluster_icon_height' ) ), + ], + ]; + } + + //categories are only meant to be shown on local maps + //TODO: Evaluate if it makes sense to only show them when categories are imported + if ( $map->getMeta( 'cb_items_available_categories' ) ) { + $settings['filter_cb_item_categories'] = []; + + foreach ( $map->getMeta( 'filtergroups' ) as $groupID => $group ) { + $elements = []; + foreach ( $group['categories'] as $termID ) { + $term = get_term( $termID ); + $customMarkup = get_term_meta( $termID, COMMONSBOOKING_METABOX_PREFIX . 'markup', true ); + $termName = empty( $customMarkup ) ? $term->name : $customMarkup; + + $elements[] = [ + 'cat_id' => intval( $termID ), + 'markup' => $termName, + ]; + } + $isExclusive = $group['isExclusive'] ?? 'off'; + $settings['filter_cb_item_categories'][ $groupID ] = [ + 'name' => $group['name'] ?? "", + 'elements' => $elements, + 'isExclusive' => $isExclusive == 'on', + ]; + } + } return $settings; } } \ No newline at end of file diff --git a/src/Map/MapSettings.php b/src/Map/MapSettings.php deleted file mode 100644 index c37690d45..000000000 --- a/src/Map/MapSettings.php +++ /dev/null @@ -1,114 +0,0 @@ -' . __( 'Settings' ) . ''; - array_unshift( $links, $settings_link ); - - return $links; - } - - /** - * render the settings page - **/ - public function render_settings_page() { - wp_enqueue_style( 'cb_map_admin_css', COMMONSBOOKING_MAP_ASSETS_URL . 'css/cb-map-admin.css' ); - - include_once( COMMONSBOOKING_MAP_PATH . 'templates/map-settings-page-template.php' ); - } -} \ No newline at end of file diff --git a/src/Map/MapShortcode.php b/src/Map/MapShortcode.php index aff758b6b..451978dfa 100644 --- a/src/Map/MapShortcode.php +++ b/src/Map/MapShortcode.php @@ -2,19 +2,24 @@ namespace CommonsBooking\Map; +use CommonsBooking\Model\Map; + /** * Shortcode for the legacy map with the old non-responsive standard leaflet style. */ class MapShortcode extends BaseShortcode { - protected function create_container($cb_map_id, $attrs, $options, $content) { - $map_height = MapAdmin::get_option( $cb_map_id, 'map_height' ); + protected function create_container( $cb_map_id, $attrs, $options, $content ) { + $map = new Map( $cb_map_id ); + $map_height = $map->getMeta( 'map_height' ); + return '
    '; } + protected function parse_attributes( $atts ) { - return shortcode_atts(array('id' => 0), $atts); + return shortcode_atts( array( 'id' => 0 ), $atts ); } - protected function inject_script($cb_map_id) { + protected function inject_script( $cb_map_id ) { wp_add_inline_script( 'cb-map-shortcode', "jQuery(document).ready(function ($) { var cb_map = new CB_Map(); @@ -31,13 +36,14 @@ protected function inject_script($cb_map_id) { * get the translations for the frontend **/ private function get_translation( $cb_map_id ): array { - $label_location_opening_hours = MapAdmin::get_option( $cb_map_id, 'label_location_opening_hours' ); - $label_location_contact = MapAdmin::get_option( $cb_map_id, 'label_location_contact' ); - $custom_no_locations_message = MapAdmin::get_option( $cb_map_id, 'custom_no_locations_message' ); - $custom_filterbutton_label = MapAdmin::get_option( $cb_map_id, 'custom_filterbutton_label' ); - $label_item_availability_filter = MapAdmin::get_option( $cb_map_id, 'label_item_availability_filter' ); - $label_item_category_filter = MapAdmin::get_option( $cb_map_id, 'label_item_category_filter' ); - $label_location_distance_filter = MapAdmin::get_option( $cb_map_id, 'label_location_distance_filter' ); + $map = new Map( $cb_map_id ); + $label_location_opening_hours = $map->getMeta( 'label_location_opening_hours' ); + $label_location_contact = $map->getMeta( 'label_location_contact' ); + $custom_no_locations_message = $map->getMeta( 'custom_no_locations_message' ); + $custom_filterbutton_label = $map->getMeta( 'custom_filterbutton_label' ); + $label_item_availability_filter = $map->getMeta( 'label_item_availability_filter' ); + $label_item_category_filter = $map->getMeta( 'label_item_category_filter' ); + $label_location_distance_filter = $map->getMeta( 'label_location_distance_filter' ); return [ 'OPENING_HOURS' => strlen( $label_location_opening_hours ) > 0 ? $label_location_opening_hours : esc_html__( 'opening hours', 'commonsbooking' ), diff --git a/src/Model/Booking.php b/src/Model/Booking.php index 64240d3b1..9e7462fda 100755 --- a/src/Model/Booking.php +++ b/src/Model/Booking.php @@ -850,6 +850,36 @@ public function getEmailSignature(): string { ); } + /** + * Will return if a booking is affected by a total breakdown ( the booked item is not usable ). + * Because since #866 not all total breakdowns are cancelled, we need a way to make sure that the user + * will not be notified about their upcoming bookings or asked to give feedback because they might not have used the item. + * @return bool true if booking is affected by a total breakdown + */ + public function hasTotalBreakdown(): bool { + $itemID = $this->getItem()->ID; + $locationID = $this->getLocation()->ID; + $restrictions = \CommonsBooking\Repository\Restriction::get( + [$locationID], + [$itemID], + null, + true, + $this->getStartDate() + ); + foreach ( $restrictions as $restriction ) { + if ( + $restriction->getType() == Restriction::TYPE_REPAIR ) { + $bookings = \CommonsBooking\Repository\Booking::getByRestriction( $restriction ); + foreach ( $bookings as $booking ) { + if ( $booking->ID == $this->ID ) { + return true; + } + } + } + } + return false; + } + /** * Returns formatted user info based on the template field in settings -> templates * diff --git a/src/Model/CustomPost.php b/src/Model/CustomPost.php index 9cf48f263..e105d7e7e 100644 --- a/src/Model/CustomPost.php +++ b/src/Model/CustomPost.php @@ -17,7 +17,7 @@ * @package CommonsBooking\Model * * @property int $post_author identifier of the WordPress user. - * @property int $post_status describes whether the post is published. + * @property string $post_status describes whether the post is published. * @property int $ID of the WordPress post. * @property string $post_title */ diff --git a/src/Model/Map.php b/src/Model/Map.php index 9dbd68c27..224620c42 100644 --- a/src/Model/Map.php +++ b/src/Model/Map.php @@ -2,15 +2,212 @@ namespace CommonsBooking\Model; +use CommonsBooking\Repository\Item; +use CommonsBooking\Repository\Timeframe; +use CommonsBooking\Wordpress\CustomPostType\Location; +use Exception; + /** - * This class currently does not have any functionality. - * It's just a placeholder for the Map post type. - * Because the map feature was taken from another plugin, it is not yet adapted to the structure of this plugin. - * This class will be used to adapt the map feature to the structure of this plugin. + * This class does the heavy lifting for the map shortcode + * Code style differs because it has been taken from the fLotte Map shortcode plugin * - * Currently, it's only referenced by the @see \CommonsBooking\Wordpress\CustomPostType\CustomPostType::getModel() method to use the methods from the CustomPost class. */ -class Map extends CustomPost -{ +class Map extends CustomPost { + + /** + * fetches locations and if available the connected items. + * Will only include items and locations when either no categories are set or the item / location has a category that is in the map config + * attaches start / enddate of the bookable timeframe to the item + * Fetches location & item metadata to be displayed on the map + * + * @param $mapItemTerms array of term ids + * + * @return array with postIDs as keys for an array with location data relevant for this map + * @throws Exception + */ + public function get_locations( array $mapItemTerms ): array { + $locations = []; + + $show_location_contact = $this->getMeta( 'show_location_contact' ); + + $preset_categories = $this->getMeta( 'cb_items_preset_categories' ); + $preset_location_categories = $this->getMeta( 'cb_locations_preset_categories' ); + + + $args = [ + 'post_type' => Location::$postType, + 'posts_per_page' => - 1, + 'post_status' => 'publish', + 'meta_query' => [ + [ + 'key' => 'geo_longitude', + 'meta_compare' => 'EXISTS', + ], + ], + ]; + + $locationObjects = \CommonsBooking\Repository\Location::get( + $args, + true + ); + + /** @var \CommonsBooking\Model\Location $post */ + foreach ( $locationObjects as $post ) { + $location_meta = get_post_meta( $post->ID, null, true ); + + //set serialized empty array if not set + //THIS FUNCTIONALITY IS DEPRECATED, closing days were a feature of 0.9.X + $closed_days = isset( $location_meta['commons-booking_location_closeddays'] ) ? $location_meta['commons-booking_location_closeddays'][0] : 'a:0:{}'; + + $items = []; + + /** + * filters out not preset location categories, if location categories are set + */ + + if ( $preset_location_categories ) { + if ( ! has_term( $preset_location_categories, 'cb_locations_category', $post->ID ) ) { + continue; //skip to next location in loop + } + } + + foreach ( Item::getByLocation( $post->ID, true ) as $item ) { + + $item_terms = wp_get_post_terms( + $item->ID, + \CommonsBooking\Wordpress\CustomPostType\Item::$postType . 's_category' + ); + if ( is_array( $item_terms ) && count( $item_terms ) ) { + $item_terms = array_map( + function ( $item ) { + return $item->term_id; + }, + $item_terms + ); + } + + /** + * If current item has a category, that isn't in map config, we'll skip it. + */ + if ( count( $mapItemTerms ) && count( $item_terms ) && ! count( array_intersect( $item_terms, $mapItemTerms ) ) ) { + continue; + } + + /** + * Filter items by preset item categories + */ + + if ( $preset_categories ) { + //check if preset category is in items + if ( ! has_term( $preset_categories, 'cb_items_category', $item->ID ) ) { + continue; //skip to next item in loop + } + } + + + $timeframesData = []; + $timeframes = Timeframe::getBookableForCurrentUser( + [ $post->ID ], + [ $item->ID ], + null, + true + ); + + /** @var \CommonsBooking\Model\Timeframe $timeframe */ + foreach ( $timeframes as $timeframe ) { + $startDate = date( 'Y-m-d', $timeframe->getStartDate() ); + $endDate = $timeframe->getEndDate() ?: date( 'Y-m-d', strtotime( '2999-01-01' ) ); + $timeframesData[] = [ + 'date_start' => $startDate, + 'date_end' => $endDate + ]; + } + + $thumbnailID = get_post_thumbnail_id( $item->ID ); + //this thumbnail is kept for backwards compatibility + $thumbnail = wp_get_attachment_image_url( $thumbnailID, 'thumbnail' ); + $images = [ + 'thumbnail' => wp_get_attachment_image_src( $thumbnailID, 'thumbnail' ), + 'medium' => wp_get_attachment_image_src( $thumbnailID, 'medium' ), + 'large' => wp_get_attachment_image_src( $thumbnailID, 'large' ), + 'full' => wp_get_attachment_image_src( $thumbnailID, 'full' ), + ]; + $items[] = [ + 'id' => $item->ID, + 'name' => $item->post_title, + 'short_desc' => has_excerpt( $item->ID ) ? wp_strip_all_tags( get_the_excerpt( $item->ID ) ) : "", + 'status' => $item->post_status, + 'terms' => $item_terms, + 'link' => add_query_arg( 'cb-location', $post->ID, get_permalink( $item->ID ) ), + 'thumbnail' => $thumbnail ?: null, + 'images' => $images, + 'timeframes' => $timeframesData + ]; + } + + if ( count( $items ) ) { + $locations[ $post->ID ] = [ + 'lat' => (float) $location_meta['geo_latitude'][0], + 'lon' => (float) $location_meta['geo_longitude'][0], + 'location_name' => $post->post_title, + 'location_link' => get_permalink( $post->ID ), + 'closed_days' => unserialize( $closed_days ), + 'address' => [ + 'street' => $location_meta[ COMMONSBOOKING_METABOX_PREFIX . 'location_street' ][0], + 'city' => $location_meta[ COMMONSBOOKING_METABOX_PREFIX . 'location_city' ][0], + 'zip' => $location_meta[ COMMONSBOOKING_METABOX_PREFIX . 'location_postcode' ][0], + ], + 'items' => $items, + ]; + + if ( $show_location_contact ) { + $locations[ $post->ID ]['contact'] = $location_meta[ COMMONSBOOKING_METABOX_PREFIX . 'location_contact' ][0]; + } + } + } + + return $locations; + } + + /** + * recursive clean up of location data entries + * + * @param $value + * @param $linebreak_replacement + * + * @return mixed|string|string[]|null + */ + public static function cleanup_location_data_entry( $value, $linebreak_replacement ) { + + if ( is_string( $value ) ) { + $value = wp_strip_all_tags( $value ); //strip all tags + $value = preg_replace( '/(\r\n)|\n|\r/', $linebreak_replacement, $value ); //replace linebreaks + } + + if ( is_array( $value ) ) { + foreach ( $value as &$child_value ) { + //recursive call + $child_value = self::cleanup_location_data_entry( $child_value, $linebreak_replacement ); + } + } + + return $value; + } + + /** + * clean up the location data + * + * @param $locations + * @param $linebreak_replacement + * + * @return mixed + */ + public static function cleanup_location_data( $locations, $linebreak_replacement ) { + foreach ( $locations as &$location ) { + $location = self::cleanup_location_data_entry( $location, $linebreak_replacement ); + } + + return $locations; + } } \ No newline at end of file diff --git a/src/Model/Restriction.php b/src/Model/Restriction.php index 02ddf3b00..ad1fa630e 100644 --- a/src/Model/Restriction.php +++ b/src/Model/Restriction.php @@ -293,8 +293,9 @@ public function apply() { // send restriction mails to all affected bookings $this->sendRestrictionMails( $bookings ); + $userDisabledBookingCancellationOnTotalBreakdown = \CommonsBooking\Settings\Settings::getOption( 'commonsbooking_options_restrictions', 'restrictions-no-cancel-on-total-breakdown' ) == 'on'; // cancel all affected booking - if ( $this->isActive() && $this->getType() == self::TYPE_REPAIR ) { + if ( ! $userDisabledBookingCancellationOnTotalBreakdown && $this->isActive() && $this->getType() == self::TYPE_REPAIR ) { $this->cancelBookings( $bookings ); } diff --git a/src/Plugin.php b/src/Plugin.php index b61119d53..50dc971c1 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -449,6 +449,36 @@ public static function registerItemTaxonomy() { //hook the term updates to the item post type function. This only runs when a term is updated but that is enough. When a term is added, the post is saved and therefore the other hook is triggered which also runs the same function. add_action( 'saved_' . $taxonomy, array( 'CommonsBooking\Wordpress\CustomPostType\Item', 'termChange' ), 10, 3 ); add_action( 'delete_' . $taxonomy, array( 'CommonsBooking\Wordpress\CustomPostType\Item', 'termChange' ), 10, 3 ); + + //hook this for later, if we run it now, it would fail + add_action( 'cmb2_admin_init', array( self::class, 'registerItemTaxonomyMetaboxes' ) ); + } + + /** + * Add custom label for item categories that will be displayed in the map filter groups. + * @return void + */ + public static function registerItemTaxonomyMetaboxes() { + $taxonomy = Item::getPostType() . 's_category'; + + $cmb_taxonomy = new_cmb2_box( + array( + 'id' => COMMONSBOOKING_METABOX_PREFIX . 'edit', + 'title' => esc_html__( 'Item Category', 'commonsbooking' ), + 'object_types' => array( 'term' ), + 'taxonomies' => array( 'category', $taxonomy ), + 'context' => 'side', + ) + ); + + $cmb_taxonomy->add_field( + array( + 'name' => __( 'Add custom title for filter', 'commonsbooking' ), + 'id' => COMMONSBOOKING_METABOX_PREFIX . 'markup', + 'type' => 'textarea_small', + 'desc' => __( 'Define name that should be used for the category if it is displayed in the map as a filter group. You can also use this to add custom HTML to the category name. When left empty, the defined name of the category will be used.', 'commonsbooking' ), + ) + ); } /** diff --git a/src/Repository/Booking.php b/src/Repository/Booking.php index f5587a9e7..4b3842fd9 100644 --- a/src/Repository/Booking.php +++ b/src/Repository/Booking.php @@ -511,6 +511,9 @@ function ( $post ) use ( $args ) { /** * Returns bookings for location and / or item that don't have a corresponding timeframe * Will only consider bookings in the future + * This function is used to find orphaned bookings due to moving a location. + * It however will also show bookings whose corresponding timeframe has been shortened, + * and therefore do not have a valid timeframe anymore. * * @param int|null $startdate * @param int[] $items diff --git a/src/Repository/BookingCodes.php b/src/Repository/BookingCodes.php index ba21470b6..a1ce9cf18 100644 --- a/src/Repository/BookingCodes.php +++ b/src/Repository/BookingCodes.php @@ -275,8 +275,10 @@ public static function initBookingCodesTable() :void { PRIMARY KEY (date, timeframe, location, item, code) ) $charset_collate;"; + // Include dbDelta since it's not part of autoloaded modules require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); dbDelta( $sql ); + add_option( COMMONSBOOKING_PLUGIN_SLUG . '_bookingcodes_db_version', $cb_db_version ); } diff --git a/src/Service/Booking.php b/src/Service/Booking.php index a4552db85..bcdff1f7a 100644 --- a/src/Service/Booking.php +++ b/src/Service/Booking.php @@ -47,6 +47,9 @@ private static function sendMessagesForDay ( int $tsDate, bool $onStartDate, Mes } if ( count( $bookings ) ) { foreach ( $bookings as $booking ) { + if ( $booking->hasTotalBreakdown() ) { + continue; + } $message = new $message( $booking->getPost()->ID, $message->getAction() ); $message->triggerMail(); } diff --git a/src/Service/Cache.php b/src/Service/Cache.php index 0c492fa74..bc6c151b6 100644 --- a/src/Service/Cache.php +++ b/src/Service/Cache.php @@ -208,14 +208,15 @@ public static function clearCache( array $tags = [] ) { * Calls clearCache using WP Cron. * Why? ClearCache can be resource intensive on larger instances and should be offloaded. * - * @param array $tags + * @param array $tags to clear cache for * * @return void */ public static function scheduleClearCache( array $tags = [] ) { - $event = wp_schedule_single_event( time(), self::$clearCacheHook, [ $tags ] ); + $event = wp_schedule_single_event( time(), self::$clearCacheHook, [ $tags ], true ); + // TODO document why only on wp-error, why this can fail, why we don't re-try or do other things, instead of forcing the execution of this resource intensive task? if ( is_wp_error( $event ) ) { - //run the event right away when scheduling fails + // runs the event right away, when scheduling fails self::clearCache( $tags ); } } diff --git a/src/Service/Holiday.php b/src/Service/Holiday.php index 3358979e0..58e1220fb 100644 --- a/src/Service/Holiday.php +++ b/src/Service/Holiday.php @@ -13,7 +13,7 @@ class Holiday { * @param $object_type * @param $field_type * - * @return void + * @return string */ public static function renderFields( $field, $value, $object_id, $object_type, $field_type ) { @@ -61,6 +61,8 @@ public static function renderFields( $field, $value, $object_id, $object_type, $
    _desc( true ); + + return ''; } diff --git a/src/Service/MassOperations.php b/src/Service/MassOperations.php index 0a94e4660..a4938ba26 100644 --- a/src/Service/MassOperations.php +++ b/src/Service/MassOperations.php @@ -2,12 +2,10 @@ namespace CommonsBooking\Service; -class MassOperations -{ +class MassOperations { - public static function ajaxMigrateOrphaned() - { - check_ajax_referer('cb_orphaned_booking_migration', 'nonce'); + public static function ajaxMigrateOrphaned() { + check_ajax_referer( 'cb_orphaned_booking_migration', 'nonce' ); if ( $_POST['data'] == 'false' ) { $post_data = 'false'; @@ -17,9 +15,26 @@ public static function ajaxMigrateOrphaned() $post_data = array_map( 'intval', $post_data ); } - $result = self::migrateOrphaned($post_data); + $success = false; + try { + $success = self::migrateOrphaned( $post_data ); + } catch ( \Exception $e ) { + $errorMessage = $e->getMessage(); + } + + if ( $success ) { + $result = array( + 'success' => true, + 'message' => __( 'All selected orphaned bookings have been migrated.', 'commonsbooking' ) + ); + } else { + $result = array( + 'success' => false, + 'message' => $errorMessage ?? __( 'An error occurred while moving bookings.', 'commonsbooking' ) + ); + } - wp_send_json($result); + wp_send_json( $result ); } /** @@ -29,45 +44,36 @@ public static function ajaxMigrateOrphaned() * * @param int[] $bookingIds * - * @return array + * @return true * @throws \Exception */ - public static function migrateOrphaned(array $bookingIds): array { - $result = array( - 'success' => true, - 'message' => '' - ); - - if (empty($bookingIds)) { - $result['success'] = false; - $result['message'] = __('No bookings to move selected.','commonsbooking'); - return $result; + public static function migrateOrphaned( array $bookingIds ): bool { + if ( empty( $bookingIds ) ) { + throw new \Exception( __( 'No bookings to move selected.', 'commonsbooking' ) ); } $orphanedBookings = \CommonsBooking\Repository\Booking::getOrphaned(); //iterate over them and assign them new locations - foreach ($orphanedBookings as $booking) { - if ( !in_array($booking->ID(), $bookingIds) ) { + foreach ( $orphanedBookings as $booking ) { + if ( ! in_array( $booking->ID, $bookingIds ) ) { continue; } try { $moveLocation = $booking->getMoveableLocation(); + if ( $moveLocation === null ) { + throw new \Exception( sprintf( __( 'New location not found for booking with ID %s', 'commonsbooking' ), $booking->ID ) ); + } } catch ( \Exception $e ) { - $moveLocation = null; + throw new \Exception( sprintf( __( 'New location not found for booking with ID %s', 'commonsbooking' ), $booking->ID ) ); } - if ($moveLocation !== null) { - update_post_meta($booking->ID, 'location-id', $moveLocation->ID()); + if ( \CommonsBooking\Repository\Booking::getExistingBookings( $booking->getItemID(), $moveLocation->ID, $booking->getStartDate(), $booking->getEndDate() ) ) { + throw new \Exception( sprintf( __( 'There is already a booking on the new location during the timeframe of booking with ID %s.', 'commonsbooking' ), $booking->ID ) ); } - else { - $result['message'] .= sprintf( __('New location not found for booking with ID %s','commonsbooking'), $booking->ID() ) ; - $result['success'] = false; + if ( $moveLocation !== null ) { + update_post_meta( $booking->ID, 'location-id', $moveLocation->ID ); } } - if ($result['success']) { - $result['message'] = __('All selected orphaned bookings have been migrated.','commonsbooking'); - } - - return $result; + return true; } } \ No newline at end of file diff --git a/src/Service/Scheduler.php b/src/Service/Scheduler.php index 36db02452..762bdf4aa 100644 --- a/src/Service/Scheduler.php +++ b/src/Service/Scheduler.php @@ -213,6 +213,13 @@ public function getJobhook(): string { return $this->jobhook; } + /** + * @return int timestamp of scheduled event + */ + public function getTimestamp(): int { + return $this->timestamp; + } + /** * Unschedules the current job. * This can have multiple reasons: diff --git a/src/Service/Upgrade.php b/src/Service/Upgrade.php index 1692022b8..a47d8ca56 100644 --- a/src/Service/Upgrade.php +++ b/src/Service/Upgrade.php @@ -6,6 +6,7 @@ use CommonsBooking\Model\Timeframe; use CommonsBooking\Plugin; use CommonsBooking\Settings\Settings; +use CommonsBooking\Wordpress\CustomPostType\Map; use CommonsBooking\Wordpress\Options\AdminOptions; use Psr\Cache\InvalidArgumentException; @@ -49,7 +50,10 @@ class Upgrade { [ self::class, 'fixBrokenICalTitle' ] ], '2.9.2' => [ - [self::class, 'enableLocationBookingNotification'] + [ self::class, 'enableLocationBookingNotification' ] + ], + '2.10' => [ + [ self::class, 'migrateMapSettings' ] ] ]; @@ -94,6 +98,7 @@ private function runEveryUpgrade(): void { // update version number in options update_option( self::VERSION_OPTION, $this->currentVersion ); + // Clear cache try { Plugin::clearCache(); @@ -461,14 +466,96 @@ public static function setMultiSelectTimeFrameDefault( int $page = 1 ) { * Previously, if a location email was set that meant that they also receive a copy of each booking / cancellation email. * Now we have a separate checkbox to enable that which should be enabled for existing locations so that they will still receive emails after upgrade. * - * @since 2.9.2 * @return void + * @since 2.9.2 */ public static function enableLocationBookingNotification() { $locations = \CommonsBooking\Repository\Location::get(); - foreach ($locations as $location) { - update_post_meta($location->ID, COMMONSBOOKING_METABOX_PREFIX . 'location_email_bcc', 'on'); + foreach ( $locations as $location ) { + update_post_meta( $location->ID, COMMONSBOOKING_METABOX_PREFIX . 'location_email_bcc', 'on' ); + } + } + + + /** + * Migrate Map Settings from old options to new CMB2 options + * + * @return void + * @since 2.10 + */ + public static function migrateMapSettings(): void { + $maps = get_posts( [ + 'post_type' => \CommonsBooking\Wordpress\CustomPostType\Map::$postType, + 'numberposts' => - 1 + ] ); + foreach ( $maps as $map ) { + $options = get_post_meta( $map->ID, 'cb_map_options', true ); + if ( empty( $options ) ) { //When default map options are empty + continue; + } + if ( get_post_meta( $map->ID, array_key_first( $options ), true ) ) { + //if the first key in the options array is already set, we assume that the migration has already been done + continue; + } + //will map to an associative array with key being the option name and the value the default value + $defaultValues = array_reduce( + Map::getCustomFields(), + function ( $result, $option ) { + if ( isset( $option['default'] ) ) { + $result[ $option['id'] ] = $option['default']; + } + + return $result; + }, + array() + ); + foreach ( $options as $key => $value ) { + if ( empty( $value ) && ! empty( $defaultValues[ $key ] ) ) { + //fetch from default values when key happens to be empty + $value = $defaultValues[ $key ]; + } + if ( ! empty( $value ) ) { + update_post_meta( $map->ID, $key, $value ); + } + } + if ( ! empty( $options['custom_marker_media_id'] ) ) { + // write the image url to the metabox, this way CMB2 can properly display it + $image = wp_get_attachment_image_src( intval( $options['custom_marker_media_id'] ) ); + update_post_meta( $map->ID, 'custom_marker_media', reset( $image ) ); + } + if ( ! empty( $options['custom_marker_cluster_id'] ) ) { + // write the image url to the metabox, this way CMB2 can properly display it + $image = wp_get_attachment_image_src( intval( $options['custom_marker_cluster_id'] ) ); + update_post_meta( $map->ID, 'custom_marker_cluster', reset( $image ) ); + } + if ( ! empty( $options['marker_item_draft_media'] ) ) { + // write the image url to the metabox, this way CMB2 can properly display it + $image = wp_get_attachment_image_src( intval( $options['marker_item_draft_media'] ) ); + update_post_meta( $map->ID, 'marker_item_draft', reset( $image ) ); + } + if ( ! empty( $options['cb_items_available_categories'] ) ) { + $newCategoryArray = []; + $currentCategoryIndex = -1; //start with -1 so we can increment to 0 + foreach ( $options['cb_items_available_categories'] as $key => $value ) { + if ( substr( $key, 0, 1 ) == 'g' ) { + $currentCategoryIndex ++; + $newCategoryArray[ $currentCategoryIndex ] = [ + 'name' => $value, + 'type' => '', + 'isExclusive' => false, + 'categories' => [] + ]; + } else { + $newCategoryArray[ $currentCategoryIndex ]['categories'][] = (string) $key; + //see if specified name is different from taxonomy name, save differing name in taxonomy meta + if ( get_term( $key )->name != $value ) { + update_term_meta( $key, COMMONSBOOKING_METABOX_PREFIX . 'markup', $value ); + } + } + } + update_post_meta( $map->ID, 'filtergroups', $newCategoryArray ); + } } } } diff --git a/src/View/Calendar.php b/src/View/Calendar.php index 72ac3fcd7..391af8a92 100644 --- a/src/View/Calendar.php +++ b/src/View/Calendar.php @@ -437,7 +437,6 @@ public static function getClosestBookableTimeFrameForToday( $bookableTimeframes default: //More than one timeframe for current day // consider starttime and endtime $now = new DateTime(); - /** @var \CommonsBooking\Model\Timeframe $todayTimeframes */ $bookableTimeframes = array_filter( $todayTimeframes, function ( $timeframe ) use ( $now ) { $startTime = $timeframe->getStartTime(); $startTimeDT = new DateTime( $startTime ); @@ -446,6 +445,19 @@ public static function getClosestBookableTimeFrameForToday( $bookableTimeframes return $startTimeDT <= $now && $now <= $endTimeDT; } ); + + //condition, that we are not currently in a timeframe + // for example, we have two timeframes, one from 02:00pm to 04:00pm and one from 04:00pm to 06:00pm. + // it is currently 11:00am, so we should take the first timeframe + if ( empty( $bookableTimeframes ) ) { + usort( $todayTimeframes, function ( $a, $b ) { + $aStartTimeDT = $a->getStartTimeDateTime(); + $bStartTimeDT = $b->getStartTimeDateTime(); + + return $bStartTimeDT <=> $aStartTimeDT; + } ); + $bookableTimeframes = $todayTimeframes; + } break; } diff --git a/src/View/Map.php b/src/View/Map.php index 132e2809d..aecb669ce 100644 --- a/src/View/Map.php +++ b/src/View/Map.php @@ -22,10 +22,9 @@ public static function render_cb_map( $field, $escaped_value, $object_id, $objec wp_enqueue_script( 'cb-map-positioning_js', COMMONSBOOKING_MAP_ASSETS_URL . 'js/cb-map-positioning.js' ); //map defaults - $options = MapAdmin::get_options(); $defaults = [ - 'latitude' => $options['lat_start'], - 'longitude' => $options['lon_start'], + 'latitude' => \CommonsBooking\Wordpress\CustomPostType\Map::LATITUDE_DEFAULT, + 'longitude' => \CommonsBooking\Wordpress\CustomPostType\Map::LONGITUDE_DEFAULT, ]; wp_add_inline_script('cb-map-positioning_js','cb_map_positioning.defaults =' . wp_json_encode($defaults) ); } diff --git a/src/View/MassOperations.php b/src/View/MassOperations.php index 1b1ef63a6..f9d25b115 100644 --- a/src/View/MassOperations.php +++ b/src/View/MassOperations.php @@ -2,11 +2,10 @@ namespace CommonsBooking\View; -class MassOperations -{ +class MassOperations { public static function index() { global $templateData; - $templateData = []; + $templateData = []; $templateData["orphanedBookings"] = \CommonsBooking\Repository\Booking::getOrphaned(); ob_start(); @@ -19,15 +18,15 @@ public static function index() { * * @return void */ - public static function renderBookingViewTable (array $bookings){ + public static function renderBookingViewTable( array $bookings ) { + + if ( empty( $bookings ) ) { + echo '

    ' . esc_html__( 'No bookings found.' ) . '

    '; - if (empty($bookings)) { - echo '

    No bookings found.

    '; return; } - $tableString = ''; - $tableString .= ' + $tableString = ' @@ -35,52 +34,52 @@ public static function renderBookingViewTable (array $bookings){ - - - - - - - + + + + + + + '; - foreach ($bookings as $booking): - try { - $itemTitle = $booking->getItem()->post_title; - } catch ( \Exception $e ) { - $itemTitle = 'Item not found'; - } + foreach ( $bookings as $booking ): + try { + $itemTitle = $booking->getItem()->post_title; + } catch ( \Exception $e ) { + $itemTitle = esc_html__( 'Item not found' ); + } - try { - $locationTitle = $booking->getLocation()->post_title; - } catch ( \Exception $e ) { - $locationTitle = 'Location not found'; - } + try { + $locationTitle = $booking->getLocation()->post_title; + } catch ( \Exception $e ) { + $locationTitle = esc_html__( 'Location not found' ); + } - try { - $newLocationTitle = $booking->getMoveableLocation()->post_title; - } catch ( \Exception $e ) { - $newLocationTitle = 'New Location not found'; - } + try { + $newLocationTitle = $booking->getMoveableLocation()->post_title; + } catch ( \Exception $e ) { + $newLocationTitle = esc_html__( 'New Location not found' ); + } - $tableString .= ' - + $tableString .= ' + - + - - - - - - + + + + + + '; - endforeach; - $tableString .= ' + endforeach; + $tableString .= '
    ' . esc_html__("ID",'commonsbooking') . '' . esc_html__("User",'commonsbooking') . '' . esc_html__("Item name",'commonsbooking') . ' - ' . esc_html__("Start-date",'commonsbooking') . '' . esc_html__("End-date",'commonsbooking') . '' . esc_html__("Status",'commonsbooking') . '' . esc_html__("Location name",'commonsbooking') . '' . esc_html__("New location name",'commonsbooking') . '' . esc_html__( "ID", 'commonsbooking' ) . '' . esc_html__( "User", 'commonsbooking' ) . '' . esc_html__( "Item name", 'commonsbooking' ) . ' + ' . esc_html__( "Start-date", 'commonsbooking' ) . '' . esc_html__( "End-date", 'commonsbooking' ) . '' . esc_html__( "Status", 'commonsbooking' ) . '' . esc_html__( "Location name", 'commonsbooking' ) . '' . esc_html__( "New location name", 'commonsbooking' ) . '
    - + ' . $booking->ID .'' . $booking->ID . ' ' . $booking->getUserData()->user_nicename . '' . $itemTitle . '' . $booking->getFormattedStartDate() . '' . $booking->getFormattedEndDate() . '' . $booking->post_status . '' . $locationTitle . '' . $newLocationTitle . '' . $itemTitle . '' . $booking->getFormattedStartDate() . '' . $booking->getFormattedEndDate() . '' . $booking->post_status . '' . $locationTitle . '' . $newLocationTitle . '
    '; diff --git a/src/Wordpress/CustomPostType/CustomPostType.php b/src/Wordpress/CustomPostType/CustomPostType.php index c2aa5955f..c68aceddc 100644 --- a/src/Wordpress/CustomPostType/CustomPostType.php +++ b/src/Wordpress/CustomPostType/CustomPostType.php @@ -138,7 +138,7 @@ public static function getCMB2FieldsArrayFromCustomMetadata( $type ): ?array { * * @param mixed $actions * - * @return void + * @return mixed */ public static function modifyRowActions( $actions, $post ) { diff --git a/src/Wordpress/CustomPostType/Map.php b/src/Wordpress/CustomPostType/Map.php index 3233c886a..e08886057 100644 --- a/src/Wordpress/CustomPostType/Map.php +++ b/src/Wordpress/CustomPostType/Map.php @@ -4,14 +4,12 @@ namespace CommonsBooking\Wordpress\CustomPostType; -use CommonsBooking\Helper\Helper; -use CommonsBooking\Map\MapAdmin; -use CommonsBooking\Map\MapSettings; use CommonsBooking\Map\MapShortcode; use CommonsBooking\Repository\CB1; use CommonsBooking\Repository\Item; -use CommonsBooking\Repository\Timeframe; -use Exception; +use CMB2_Field; +use CommonsBooking\Repository\Location; + use function __; class Map extends CustomPostType { @@ -21,362 +19,613 @@ class Map extends CustomPostType { */ public static $postType = 'cb_map'; + /** + * The default coordinates of the map center. + * Is used when no other coordinates are set. + * These are currently the coordinates of Cologne, Germany. + */ + const LATITUDE_DEFAULT = 50.937531; + const LONGITUDE_DEFAULT = 6.960279; + /** * Initiates needed hooks. */ public function initHooks() { - $cb_map_settings = new MapSettings(); - - // TODO check the following comment - // deactivated individual map settings because we don't need them righ now - // map setting should be integrated in CB settings in the future - //$cb_map_settings->prepare_settings(); - - if ( $cb_map_settings->get_option( 'booking_page_link_replacement' ) ) { - add_action( 'wp_enqueue_scripts', array( Map::class, 'replace_map_link_target' ), 11 ); - } - // Add shortcodes add_shortcode( 'cb_map', array( MapShortcode::class, 'execute' ) ); // Add actions - add_action( 'save_post_' . self::$postType, array( MapAdmin::class, 'validate_options' ), 10, 3 ); - add_action( 'add_meta_boxes_cb_map', array( MapAdmin::class, 'add_meta_boxes' ) ); - } - - public static function getView() { - return new \CommonsBooking\View\Map(); - } - - /** - * enforce the replacement of the original (google maps) link target on cb_item booking pages - * - * @since 2.10 it is deprecated - * - * @deprecated to remove old legacy code. - **/ - public static function replace_map_link_target() { - global $post; - if ( is_object( $post ) && $post->post_type == CB1::$ITEM_TYPE_ID ) { - //get timeframes of item - $cb_data = new CB_Data(); - $date_start = date( 'Y-m-d' ); // current date - $timeframes = $cb_data->get_timeframes( $post->ID, $date_start ); - - $geo_coordinates = []; - if ( $timeframes ) { - foreach ( $timeframes as $timeframe ) { - $geo_coordinates[ $timeframe['id'] ] = [ - 'lat' => get_post_meta( $timeframe['location_id'], 'cb-map_latitude', true ), - 'lon' => get_post_meta( $timeframe['location_id'], 'cb-map_longitude', true ), - ]; - } - } - - wp_register_script( 'cb_map_replace_map_link_js', COMMONSBOOKING_MAP_ASSETS_URL . 'js/cb-map-replace-link.js' ); - - wp_add_inline_script( 'cb_map_replace_map_link_js', - "cb_map_timeframes_geo = " . wp_json_encode( $geo_coordinates ) . ";" ); - - wp_enqueue_script( 'cb_map_replace_map_link_js' ); - } + add_action( 'cmb2_admin_init', array( $this, 'registerMetabox' ) ); } - /** - * load all timeframes from db (that end in the future and it's item's status is 'publish') - **/ - public static function get_timeframes() { - - $result = []; - - $timeframes = Timeframe::getBookableForCurrentUser( - [], - [], - false, - true, - Helper::getLastFullHourTimestamp() + public function registerMetabox() { + $cmb = new_cmb2_box( + [ + 'id' => static::getPostType() . "-custom-fields", + 'title' => esc_html__( 'Map settings', 'commonsbooking' ), + 'object_types' => array( static::getPostType() ), + ] ); - /** @var \CommonsBooking\Model\Timeframe $timeframe */ - foreach ( $timeframes as $timeframe ) { - //TODO #507 - $item = $timeframe->getItem(); - $location = $timeframe->getLocation(); - if ( $item && $location ) { - $item_desc = $item->getMeta( COMMONSBOOKING_METABOX_PREFIX . 'location_info' ); - $thumbnail = get_the_post_thumbnail_url( $item, 'thumbnail' ); - - $result[] = [ - 'location_id' => $timeframe->getLocationID(), - 'item' => [ - 'id' => $item->ID, - 'name' => $item->post_title, - 'short_desc' => $item_desc, - 'link' => get_permalink( $item ), - 'thumbnail' => $thumbnail ?: null, - 'status' => $item->post_status, - ], - 'date_start' => $timeframe->getStartDate(), - 'date_end' => $timeframe->getEndDate(), - ]; - } - } - - return $result; - } - - public static function has_item_valid_status( $item, $item_draft_appearance ): bool { - - if ( $item_draft_appearance == 1 ) { - return $item->post_status == 'publish'; + foreach ( self::getCustomFields() as $customField ) { + $cmb->add_field( $customField ); } - if ( $item_draft_appearance == 2 ) { - return $item->post_status != 'publish'; - } - if ( $item_draft_appearance == 3 ) { - return true; - } - return false; } - /** - * get geo data from location metadata - * - * @param $cb_map_id - * @param $mapItemTerms - * - * @return array - * @throws Exception - */ - public static function get_locations( $cb_map_id, $mapItemTerms ): array { - $locations = []; - - $show_location_contact = MapAdmin::get_option( $cb_map_id, 'show_location_contact' ); - $show_location_opening_hours = MapAdmin::get_option( $cb_map_id, 'show_location_opening_hours' ); - - $preset_categories = MapAdmin::get_option( $cb_map_id, 'cb_items_preset_categories' ); - $preset_location_categories = MapAdmin::get_option( $cb_map_id, 'cb_locations_preset_categories' ); - - - $args = [ - 'post_type' => Location::$postType, - 'posts_per_page' => - 1, - 'post_status' => 'publish', - 'meta_query' => [ - [ - 'key' => 'geo_longitude', - 'meta_compare' => 'EXISTS', - ], - ], - ]; - - $locationObjects = \CommonsBooking\Repository\Location::get( - $args, - true + public static function getCustomFields(): array { + return array( + array( + 'name' => esc_html__( 'These settings help you to configure the usage and appearance of Commons Booking Map', 'commonsbooking' ), + 'id' => 'map_settings_info', + 'type' => 'title', + ), + array( + 'render_row_cb' => array( self::class, 'getShortcode' ), + 'type' => 'text', + 'id' => 'shortcode', + ), + //Begin group presentation + array( + 'name' => esc_html__( 'Presentation', 'commonsbooking' ), + 'type' => 'title', + 'id' => 'presentation_info', + 'classes' => 'map-organizer' + ), + array( + 'name' => esc_html__( 'base map', 'commonsbooking' ), + 'desc' => esc_html__( 'the base map defines the rendering style of the map tiles', 'commonsbooking' ), + 'id' => 'base_map', + 'type' => 'select', + 'options' => array( + '1' => esc_html__( 'OSM - mapnik', 'commonsbooking' ), + '2' => esc_html__( 'OSM - german style', 'commonsbooking' ) + /* + * Reenable the map styles if neede + '3' => esc_html__( 'OSM - hike and bike', 'commonsbooking' ), + '4' => esc_html__( 'OSM - lokaler (min. zoom: 9)', 'commonsbooking' ) + */ + ), + 'classes' => 'presentation_option', + ), + array( + 'name' => esc_html__( 'show scale', 'commonsbooking' ), + 'desc' => esc_html__( 'show the current scale in the bottom left corner of the map', 'commonsbooking' ), + 'id' => 'show_scale', + 'type' => 'checkbox', + ), + array( + 'name' => esc_html__( 'map height', 'commonsbooking' ), + 'desc' => 'px
    ' . esc_html__( 'the height the map is rendered with - the width is the same as of the parent element', 'commonsbooking' ), + 'id' => 'map_height', + 'type' => 'text_small', + 'default' => '400', + 'attributes' => array( + 'type' => 'number', + 'pattern' => '\d*', + ), + ), + array( + 'name' => esc_html__( 'no locations message', 'commonsbooking' ), + 'desc' => esc_html__( 'in case a user filters locations and gets no result, a message is shown - here the text can be customized', 'commonsbooking' ), + 'id' => 'custom_no_locations_message', + 'type' => 'text', + 'default' => esc_html__( 'No locations found', 'commonsbooking' ), + ), + array( + 'name' => esc_html__( 'enable data export', 'commonsbooking' ), + 'desc' => esc_html__( 'activate to enable a button that allows the export of map data (geojson format)', 'commonsbooking' ), + 'id' => 'enable_map_data_export', + 'type' => 'checkbox', + ), + //Begin group Zoom + array( + 'name' => esc_html__( 'Zoom', 'commonsbooking' ), + 'type' => 'title', + 'id' => 'zoom_info', + 'classes' => 'map-organizer' + ), + array( + 'name' => esc_html__( 'min. zoom level', 'commonsbooking' ), + 'desc' => esc_html__( 'the minimal zoom level a user can choose', 'commonsbooking' ), + 'id' => 'zoom_min', + 'type' => 'text_small', + 'default' => '9', + 'attributes' => array( + 'type' => 'number', + 'pattern' => '\d*', + 'min' => '1', + 'max' => '19', + ) + ), + array( + 'name' => esc_html__( 'max. zoom level', 'commonsbooking' ), + 'desc' => esc_html__( 'the maximal zoom level a user can choose', 'commonsbooking' ), + 'id' => 'zoom_max', + 'type' => 'text_small', + 'default' => '19', + 'attributes' => array( + 'type' => 'number', + 'pattern' => '\d*', + 'min' => '1', + 'max' => '19', + ) + ), + array( + 'name' => esc_html__( 'start zoom level', 'commonsbooking' ), + 'desc' => esc_html__( 'the zoom level that will be set when the map is loaded', 'commonsbooking' ), + 'id' => 'zoom_start', + 'type' => 'text_small', + 'default' => '9', + 'attributes' => array( + 'type' => 'number', + 'pattern' => '\d*', + 'min' => '1', + 'max' => '19', + ) + ), + array( + 'name' => esc_html__( 'enable scroll wheel zoom', 'commonsbooking' ), + 'desc' => esc_html__( 'when activated users can zoom the map using the scroll wheel', 'commonsbooking' ), + 'id' => 'scrollWheelZoom', + 'type' => 'checkbox', + 'default_cb' => 'commonsbooking_cmb2_set_checkbox_default_for_new_post', + ), + //End group Zoom + //Begin group Positioning + array( + 'name' => esc_html__( 'Positioning', 'commonsbooking' ), + 'type' => 'title', + 'id' => 'positioning_info', + 'classes' => 'map-organizer' + ), + array( + 'name' => esc_html__( 'start latitude', 'commonsbooking' ), + 'desc' => esc_html__( 'the latitude of the map center when the map is loaded', 'commonsbooking' ), + 'id' => 'lat_start', + 'type' => 'text_small', + 'default' => self::LATITUDE_DEFAULT, + ), + array( + 'name' => esc_html__( 'start longitude', 'commonsbooking' ), + 'desc' => esc_html__( 'the longitude of the map center when the map is loaded', 'commonsbooking' ), + 'id' => 'lon_start', + 'type' => 'text_small', + 'default' => self::LONGITUDE_DEFAULT, + ), + array( + 'name' => esc_html__( 'initial adjustment to marker bounds', 'commonsbooking' ), + 'desc' => esc_html__( 'adjust map section to bounds of shown markers automatically when map is loaded', 'commonsbooking' ), + 'id' => 'marker_map_bounds_initial', + 'type' => 'checkbox', + 'default_cb' => 'commonsbooking_cmb2_set_checkbox_default_for_new_post', + ), + array( + 'name' => esc_html__( 'adjustment to marker bounds on filter', 'commonsbooking' ), + 'desc' => esc_html__( 'adjust map section to bounds of shown markers automatically when filtered by users', 'commonsbooking' ), + 'id' => 'marker_map_bounds_filter', + 'type' => 'checkbox', + 'default_cb' => 'commonsbooking_cmb2_set_checkbox_default_for_new_post', + ), + //End group Positioning + //Begin group Tooltip + array( + 'name' => esc_html__( 'Marker Tooltip', 'commonsbooking' ), + 'type' => 'title', + 'id' => 'marker_tooltip_info', + 'classes' => 'map-organizer' + ), + array( + 'name' => esc_html__( 'Show marker tooltip permanently', 'commonsbooking' ), + 'desc' => esc_html__( 'activate to show the marker tooltips permanently', 'commonsbooking' ), + 'id' => 'marker_tooltip_permanent', + 'type' => 'checkbox', + ), + //End group Tooltip + //Begin group popup + array( + 'name' => esc_html__( 'Marker Popup', 'commonsbooking' ), + 'type' => 'title', + 'id' => 'marker_popup_info', + 'classes' => 'map-organizer' + ), + array( + 'name' => esc_html__( 'show item availability', 'commonsbooking' ), + 'desc' => esc_html__( 'activate to show the item availability in the marker popup', 'commonsbooking' ), + 'id' => 'show_item_availability', + 'type' => 'checkbox' + ), + array( + 'name' => esc_html__( 'Max. available days in popup', 'commonsbooking' ), + 'desc' => esc_html__( 'Set how many days are displayed on the popup (starting from today)', 'commonsbooking' ), + 'id' => 'availability_max_days_to_show', + 'type' => 'text_small', + 'default' => '11', + 'attributes' => array( + 'type' => 'number', + 'pattern' => '\d*', + 'min' => '1', + ) + ), + array( + 'name' => esc_html__( 'Maximum days to choose in map availabilty filter ', 'commonsbooking' ), + 'desc' => esc_html__( 'Notice: Defines the maximun days a user can choose in the availabilty filter in frontend map', 'commonsbooking' ), + 'id' => 'availability_max_day_count', + 'default' => '14', + 'type' => 'text_small', + 'attributes' => array( + 'type' => 'number', + 'pattern' => '\d*', + ) + ), + //End group popup + //Begin group custom marker + array( + 'name' => esc_html__( 'Custom Marker', 'commonsbooking' ), + 'type' => 'title', + 'id' => 'custom_marker_info', + 'classes' => 'map-organizer' + ), + array( + 'name' => esc_html__( 'image file', 'commonsbooking' ), + 'desc' => esc_html__( 'the default marker icon can be replaced by a custom image', 'commonsbooking' ), + 'id' => 'custom_marker_media', + 'type' => 'file', + 'options' => array( + 'url' => false, + ), + 'query_args' => array( + 'type' => array( + 'image/png', + ), + ), + ), + array( + 'name' => esc_html__( 'icon width', 'commonsbooking' ), + 'desc' => 'px ' . esc_html__( 'the size of the custom marker icon image as it is shown on the map', 'commonsbooking' ), + 'id' => 'marker_icon_width', + 'type' => 'text_small', + 'attributes' => array( + 'type' => 'number', + 'pattern' => '\d*', + 'min' => '1', + ), + ), + array( + 'name' => esc_html__( 'icon height', 'commonsbooking' ), + 'desc' => 'px ' . esc_html__( 'the size of the custom marker icon image as it is shown on the map', 'commonsbooking' ), + 'id' => 'marker_icon_height', + 'type' => 'text_small', + 'attributes' => array( + 'type' => 'number', + 'pattern' => '\d*', + 'min' => '1', + ), + ), + array( + 'name' => esc_html__( 'anchor point', 'commonsbooking' ) . ' x', + 'desc' => 'px ' . esc_html__( 'the position of the anchor point of the icon image, seen from the left top corner of the icon, often it is half of the width and full height of the icon size - this point is used to place the marker on the geo coordinates', 'commonsbooking' ), + 'id' => 'marker_icon_anchor_x', + 'type' => 'text_small', + 'attributes' => array( + 'type' => 'number', + 'pattern' => '\d*', + ), + ), + array( + 'name' => esc_html__( 'anchor point', 'commonsbooking' ) . ' y', + 'desc' => 'px ' . esc_html__( 'the position of the anchor point of the icon image, seen from the left top corner of the icon, often it is half of the width and full height of the icon size - this point is used to place the marker on the geo coordinates', 'commonsbooking' ), + 'id' => 'marker_icon_anchor_y', + 'type' => 'text_small', + 'attributes' => array( + 'type' => 'number', + 'pattern' => '\d*', + ), + ), + //End group custom marker + //Begin group cluster + array( + 'name' => esc_html__( 'Cluster', 'commonsbooking' ), + 'type' => 'title', + 'id' => 'cluster_info', + 'classes' => 'map-organizer' + ), + array( + 'name' => esc_html__( 'max. cluster radius', 'commonsbooking' ), + 'desc' => 'px ' . esc_html__( 'combine markers to a cluster within given radius - 0 for deactivation', 'commonsbooking' ), + 'id' => 'max_cluster_radius', + 'type' => 'text_small', + 'default' => '80', + 'attributes' => array( + 'type' => 'number', + 'pattern' => '\d*', + 'min' => 0, + 'max' => 1000 + ), + ), + array( + 'name' => esc_html__( 'Custom Cluster Marker', 'commonsbooking' ), + 'desc' => esc_html__( 'the default marker icon can be replaced by a custom image', 'commonsbooking' ), + 'id' => 'custom_marker_cluster_media', + 'type' => 'file', + 'options' => array( + 'url' => false, + ), + 'query_args' => array( + 'type' => array( + 'image/png', + ), + ), + ), + array( + 'name' => esc_html__( 'icon width', 'commonsbooking' ), + 'desc' => 'px ' . esc_html__( 'the size of the custom marker icon image as it is shown on the map', 'commonsbooking' ), + 'id' => 'marker_cluster_icon_width', + 'type' => 'text_small', + 'attributes' => array( + 'type' => 'number', + 'pattern' => '\d*', + 'min' => '1', + ), + ), + array( + 'name' => esc_html__( 'icon height', 'commonsbooking' ), + 'desc' => 'px ' . esc_html__( 'the size of the custom marker icon image as it is shown on the map', 'commonsbooking' ), + 'id' => 'marker_cluster_icon_height', + 'type' => 'text_small', + 'attributes' => array( + 'type' => 'number', + 'pattern' => '\d*', + 'min' => '1', + ), + ), + //End group cluster + //Begin group Appearance + array( + 'name' => esc_html__( 'Appearance by Item Status', 'commonsbooking' ), + 'type' => 'title', + 'id' => 'item_status_appearance_info', + 'classes' => 'map-organizer' + ), + array( + 'name' => esc_html__( 'appearance', 'commonsbooking' ), + 'desc' => esc_html__( 'how locations with items that are in draft status should be handled', 'commonsbooking' ), + 'id' => 'item_draft_appearance', + 'type' => 'radio', + 'options' => array( + '1' => esc_html__( "don't show drafts", 'commonsbooking' ), + '2' => esc_html__( 'show only drafts', 'commonsbooking' ), + '3' => esc_html__( 'show all together', 'commonsbooking' ), + ), + 'default' => '1', + ), + array( + 'name' => esc_html__( 'Custom Item Draft Marker', 'commonsbooking' ), + 'desc' => esc_html__( 'the default marker icon can be replaced by a custom image', 'commonsbooking' ), + 'id' => 'marker_item_draft_media', + 'type' => 'file', + 'options' => array( + 'url' => false, + ), + 'query_args' => array( + 'type' => array( + 'image/png', + ), + ), + ), + array( + 'name' => esc_html__( 'icon width', 'commonsbooking' ), + 'desc' => 'px ' . esc_html__( 'the size of the custom marker icon image as it is shown on the map', 'commonsbooking' ), + 'id' => 'marker_item_draft_icon_width', + 'type' => 'text_small', + 'attributes' => array( + 'type' => 'number', + 'pattern' => '\d*', + 'min' => '1', + ), + ), + array( + 'name' => esc_html__( 'icon height', 'commonsbooking' ), + 'desc' => 'px ' . esc_html__( 'the size of the custom marker icon image as it is shown on the map', 'commonsbooking' ), + 'id' => 'marker_item_draft_icon_height', + 'type' => 'text_small', + 'attributes' => array( + 'type' => 'number', + 'pattern' => '\d*', + 'min' => '1', + ), + ), + array( + 'name' => esc_html__( 'anchor point', 'commonsbooking' ) . ' x', + 'desc' => 'px ' . esc_html__( 'the position of the anchor point of the icon image, seen from the left top corner of the icon, often it is half of the width and full height of the icon size - this point is used to place the marker on the geo coordinates', 'commonsbooking' ), + 'id' => 'marker_item_draft_icon_anchor_x', + 'type' => 'text_small', + 'attributes' => array( + 'type' => 'number', + 'pattern' => '\d*', + ), + ), + array( + 'name' => esc_html__( 'anchor point', 'commonsbooking' ) . ' y', + 'desc' => 'px ' . esc_html__( 'the position of the anchor point of the icon image, seen from the left top corner of the icon, often it is half of the width and full height of the icon size - this point is used to place the marker on the geo coordinates', 'commonsbooking' ), + 'id' => 'marker_item_draft_icon_anchor_y', + 'type' => 'text_small', + 'attributes' => array( + 'type' => 'number', + 'pattern' => '\d*', + ), + ), + //End group Appearance + //Begin group Filters + array( + 'name' => esc_html__( 'Filter for Users', 'commonsbooking' ), + 'type' => 'title', + 'id' => 'filter_info', + 'classes' => 'map-organizer' + ), + array( + 'name' => esc_html__( 'show location distance filter', 'commonsbooking' ), + 'desc' => esc_html__( 'activate to show the location distance filter', 'commonsbooking' ), + 'id' => 'show_location_distance_filter', + 'type' => 'checkbox', + ), + array( + 'name' => esc_html__( 'label for location distance filter', 'commonsbooking' ), + 'desc' => esc_html__( 'alternative label for the location distance filter', 'commonsbooking' ), + 'id' => 'label_location_distance_filter', + 'type' => 'text', + 'attributes' => array( + 'placeholder' => esc_html__( 'distance', 'commonsbooking' ), + ) + ), + array( + 'name' => esc_html__( 'address search bounds - left bottom', 'commonsbooking' ) . ' ' . esc_html__( 'longitude', 'commonsbooking' ), + 'desc' => esc_html__( 'defines the bounds of the address search - set the longitude of the left bottom corner of the bounding box', 'commonsbooking' ), + 'id' => 'address_search_bounds_left_bottom_lon', + 'type' => 'text_small', + ), + array( + 'name' => esc_html__( 'address search bounds - left bottom', 'commonsbooking' ) . ' ' . esc_html__( 'latitude', 'commonsbooking' ), + 'desc' => esc_html__( 'defines the bounds of the address search - set the bottom left corner of the bounding box', 'commonsbooking' ), + 'id' => 'address_search_bounds_left_bottom_lat', + 'type' => 'text_small', + ), + array( + 'name' => esc_html__( 'address search bounds - right top', 'commonsbooking' ) . ' ' . esc_html__( 'longitude', 'commonsbooking' ), + 'desc' => esc_html__( 'defines the bounds of the address search - set the longitude of the right top corner of the bounding box', 'commonsbooking' ), + 'id' => 'address_search_bounds_right_top_lon', + 'type' => 'text_small', + ), + array( + 'name' => esc_html__( 'address search bounds - right top', 'commonsbooking' ) . ' ' . esc_html__( 'latitude', 'commonsbooking' ), + 'desc' => esc_html__( 'defines the bounds of the address search - set the latitude of the right top corner of the bounding box', 'commonsbooking' ), + 'id' => 'address_search_bounds_right_top_lat', + 'type' => 'text_small', + ), + array( + 'name' => esc_html__( 'show item availability filter', 'commonsbooking' ), + 'desc' => esc_html__( 'activate to show the item availability filter', 'commonsbooking' ), + 'id' => 'show_item_availability_filter', + 'type' => 'checkbox', + ), + array( + 'name' => esc_html__( 'label for item availability filter', 'commonsbooking' ), + 'desc' => esc_html__( 'alternative label for the item availability filter', 'commonsbooking' ), + 'id' => 'label_item_availability_filter', + 'type' => 'text', + 'attributes' => array( + 'placeholder' => esc_html__( 'availability', 'commonsbooking' ), + ) + ), + array( + 'name' => esc_html__( 'label for item category filter', 'commonsbooking' ), + 'desc' => esc_html__( 'alternative label for the item category filter', 'commonsbooking' ), + 'id' => 'label_item_category_filter', + 'type' => 'text', + 'attributes' => array( + 'placeholder' => esc_html__( 'categories', 'commonsbooking' ), + ) + ), + array( + 'name' => esc_html__( 'custom text for filter button', 'commonsbooking' ), + 'desc' => esc_html__( 'the text for the button used for filtering', 'commonsbooking' ), + 'id' => 'custom_filterbutton_label', + 'type' => 'text', + 'attributes' => array( + 'placeholder' => esc_html__( 'filter', 'commonsbooking' ), + ) + ), + array( + 'name' => commonsbooking_sanitizeHTML( __( 'Filter groups', 'commonsbooking' ) ), + 'desc' => commonsbooking_sanitizeHTML( __( 'Filter groups can group item or location categories together to allow for filtering in the map.', 'commonsbooking' ) ), + 'id' => 'filtergroups', + 'type' => 'group', + 'repeatable' => true, + 'options' => array( + 'group_title' => commonsbooking_sanitizeHTML( __( 'Filter group {#}', 'commonsbooking' ) ), + 'add_button' => commonsbooking_sanitizeHTML( __( 'Add another filter group', 'commonsbooking' ) ), + 'remove_button' => commonsbooking_sanitizeHTML( __( 'Remove filter group', 'commonsbooking' ) ), + 'sortable' => true, + ), + 'fields' => array( + array( + 'name' => commonsbooking_sanitizeHTML( __( 'Name', 'commonsbooking' ) ), + 'id' => 'name', + 'type' => 'text', + 'desc' => commonsbooking_sanitizeHTML( __( 'The name of the filter group', 'commonsbooking' ) ), + 'default' => '', + ), + array( + 'name' => commonsbooking_sanitizeHTML( __( 'Type', 'commonsbooking' ) ), + 'id' => 'type', + 'type' => 'select', + 'desc' => commonsbooking_sanitizeHTML( __( 'This is not available yet. Which data source should be used for the filter group. Taxonomy stands for the assigned categories, post-meta can be individually configured custom fields for item posts. When this item field contains data, it will be included. If it does not contain data or does not exist, the item will be excluded.', 'commonsbooking' ) ), + 'options' => array( + 'taxonomy' => commonsbooking_sanitizeHTML( __( 'Taxonomy', 'commonsbooking' ) ), + 'postmeta' => commonsbooking_sanitizeHTML( __( 'Post-meta', 'commonsbooking' ) ), + ), + 'default' => 'taxonomy', + //TODO: disabled until postmeta is implemented + 'attributes' => array( + 'disabled' => true + ), + ), + array( + 'name' => commonsbooking_sanitizeHTML( __( 'Exclusive selection', 'commonsbooking' ) ), + 'id' => 'isExclusive', + 'type' => 'checkbox', + 'desc' => commonsbooking_sanitizeHTML( __( 'WARNING: This feature is only available for the cb_search shortcode, not for cb_map. If checked, only one category can be selected in this filter group. If unchecked, multiple categories can be selected.', 'commonsbooking' ) ), + ), + array( + 'name' => commonsbooking_sanitizeHTML( __( 'Categories', 'commonsbooking' ) ), + 'id' => 'categories', + 'type' => 'multicheck', + 'desc' => commonsbooking_sanitizeHTML( __( 'The categories to be included in the filter group', 'commonsbooking' ) ), + 'options' => \CommonsBooking\Wordpress\CustomPostType\CustomPostType::sanitizeOptions( Item::getTerms() ), + 'select_all_button' => false, + ), + ), + ), + //TODO: Add available categories & filtergroups + //End group Filters + //Begin group Presets + array( + 'name' => esc_html__( 'Filter Item Presets', 'commonsbooking' ), + 'desc' => esc_html__( 'select the categories that are used to prefilter the items that are shown on the map - none for all items', 'commonsbooking' ), + 'id' => 'cb_items_preset_categories', + 'type' => 'multicheck', + 'options' => CustomPostType::sanitizeOptions( Item::getTerms() ), + 'select_all_button' => false, + ), + array( + 'name' => esc_html__( 'Filter Location Presets', 'commonsbooking' ), + 'desc' => esc_html__( 'select the categories that are used to prefilter the locations that are shown on the map - none for all locations', 'commonsbooking' ), + 'id' => 'cb_locations_preset_categories', + 'type' => 'multicheck', + 'options' => CustomPostType::sanitizeOptions( Location::getTerms() ), + 'select_all_button' => false, + ), + //End group Presets ); - - /** @var \CommonsBooking\Model\Location $post */ - foreach ( $locationObjects as $post ) { - $location_meta = get_post_meta( $post->ID, null, true ); - - //set serialized empty array if not set - $closed_days = isset( $location_meta['commons-booking_location_closeddays'] ) ? $location_meta['commons-booking_location_closeddays'][0] : 'a:0:{}'; - - $items = []; - - /** - * filters out not preset location categories, if location categories are set - */ - - if ($preset_location_categories) { - if ( !has_term( $preset_location_categories , 'cb_locations_category' , $post->ID) ) { - continue; //skip to next location in loop - } - } - - foreach ( Item::getByLocation( $post->ID, true ) as $item ) { - - $item_terms = wp_get_post_terms( - $item->ID, - \CommonsBooking\Wordpress\CustomPostType\Item::$postType . 's_category' - ); - if ( is_array( $item_terms ) && count( $item_terms ) ) { - $item_terms = array_map( - function ( $item ) { - return $item->term_id; - }, - $item_terms - ); - } - - /** - * If current item has a category, that isn't in map config, we'll skip it. - */ - if ( count( $mapItemTerms ) && count( $item_terms ) && ! count( array_intersect( $item_terms, $mapItemTerms ) ) ) { - continue; - } - - /** - * Filter items by preset item categories - */ - - if ($preset_categories) { - //check if preset category is in items - if ( !has_term( $preset_categories , 'cb_items_category' , $item->ID) ) { - continue; //skip to next item in loop - } - } - - - $timeframesData = []; - $timeframes = Timeframe::getBookableForCurrentUser( - [ $post->ID ], - [ $item->ID ], - null, - true - ); - - /** @var \CommonsBooking\Model\Timeframe $timeframe */ - foreach ( $timeframes as $timeframe ) { - $startDate = date( 'Y-m-d', $timeframe->getStartDate() ); - $endDate = $timeframe->getEndDate() ?: date( 'Y-m-d', strtotime( '2999-01-01' ) ); - $timeframesData[] = [ - 'date_start' => $startDate, - 'date_end' => $endDate - ]; - } - - $thumbnailID = get_post_thumbnail_id( $item->ID ); - //this thumbnail is kept for backwards compatibility - $thumbnail = wp_get_attachment_image_url( $thumbnailID, 'thumbnail' ); - $images = [ - 'thumbnail' => wp_get_attachment_image_src( $thumbnailID, 'thumbnail' ), - 'medium' => wp_get_attachment_image_src( $thumbnailID, 'medium' ), - 'large' => wp_get_attachment_image_src( $thumbnailID, 'large' ), - 'full' => wp_get_attachment_image_src( $thumbnailID, 'full' ), - ]; - $items[] = [ - 'id' => $item->ID, - 'name' => $item->post_title, - 'short_desc' => has_excerpt( $item->ID ) ? wp_strip_all_tags( get_the_excerpt( $item->ID ) ) : "", - 'status' => $item->post_status, - 'terms' => $item_terms, - 'link' => add_query_arg( 'cb-location', $post->ID, get_permalink( $item->ID ) ), - 'thumbnail' => $thumbnail ?: null, - 'images' => $images, - 'timeframes' => $timeframesData - ]; - } - - if ( count( $items ) ) { - $locations[ $post->ID ] = [ - 'lat' => (float) $location_meta['geo_latitude'][0], - 'lon' => (float) $location_meta['geo_longitude'][0], - 'location_name' => $post->post_title, - 'location_link' => get_permalink($post->ID), - 'closed_days' => unserialize( $closed_days ), - 'address' => [ - 'street' => $location_meta[ COMMONSBOOKING_METABOX_PREFIX . 'location_street' ][0], - 'city' => $location_meta[ COMMONSBOOKING_METABOX_PREFIX . 'location_city' ][0], - 'zip' => $location_meta[ COMMONSBOOKING_METABOX_PREFIX . 'location_postcode' ][0], - ], - 'items' => $items, - ]; - - if ( $show_location_contact ) { - $locations[ $post->ID ]['contact'] = $location_meta[ COMMONSBOOKING_METABOX_PREFIX . 'location_contact' ][0]; - } - } - - //@TODO: Check field -> we don't have such a field at the moment. -// if ($show_location_opening_hours) { -// $locations[$post->ID]['opening_hours'] = $location_meta['commons-booking_location_openinghours'][0]; -// } - } - - return $locations; - } - - public static function get_cb_items_category_groups( $preset_categories ) { - $groups = []; - $category_terms = Item::getTerms(); - - foreach ( $category_terms as $term ) { - if ( in_array( $term->term_id, $preset_categories ) ) { - if ( ! isset( $groups[ $term->parent ] ) ) { - $groups[ $term->parent ] = []; - } - $groups[ $term->parent ][] = $term->term_id; - - } - } - - return $groups; - } - - /** - * basic check if the given string is valid JSON - **/ - public static function is_json( $string ) { - json_decode( $string ); - - return ( json_last_error() == JSON_ERROR_NONE ); } - /** - * clean up the location data - * - * @param $locations - * @param $linebreak_replacement - * - * @return mixed - */ - public static function cleanup_location_data( $locations, $linebreak_replacement ) { - foreach ( $locations as &$location ) { - $location = self::cleanup_location_data_entry( $location, $linebreak_replacement ); - } - - return $locations; - } - - /** - * recursive clean up of location data entries - * - * @param $value - * @param $linebreak_replacement - * - * @return mixed|string|string[]|null - */ - public static function cleanup_location_data_entry( $value, $linebreak_replacement ) { - - if ( is_string( $value ) ) { - $value = preg_replace( '/(\r\n)|\n|\r/', $linebreak_replacement, $value ); //replace linebreaks - $value = preg_replace( '/<.*(.*?)/', '', $value ); //strip off everything that smell's like HTML - } - - if ( is_array( $value ) ) { - foreach ( $value as &$child_value ) { - $child_value = self::cleanup_location_data_entry( $child_value, $linebreak_replacement ); - } - } - - return $value; + public static function getView() { + return new \CommonsBooking\View\Map(); } public function getArgs() { $labels = array( - 'name' => self::__( 'Maps', 'commonsbooking' ), - 'singular_name' => self::__( 'Map', 'commonsbooking' ), - 'add_new' => self::__( 'create CB map', 'commonsbooking' ), - 'add_new_item' => self::__( 'create Commons Booking map', 'commonsbooking' ), - 'edit_item' => self::__( 'edit Commons Booking map', 'commonsbooking' ), - 'new_item' => self::__( 'create CB map', 'commonsbooking' ), - 'view_item' => self::__( 'view CB map', 'commonsbooking' ), - 'search_items' => self::__( 'search CB maps', 'commonsbooking' ), - 'not_found' => self::__( 'no Commons Booking map found', 'commonsbooking' ), - 'not_found_in_trash' => self::__( 'no Commons Booking map found in the trash', 'commonsbooking' ), - 'parent_item_colon' => self::__( 'parent CB maps', 'commonsbooking' ), + 'name' => esc_html__( 'Maps', 'commonsbooking' ), + 'singular_name' => esc_html__( 'Map', 'commonsbooking' ), + 'add_new' => esc_html__( 'create CB map', 'commonsbooking' ), + 'add_new_item' => esc_html__( 'create Commons Booking map', 'commonsbooking' ), + 'edit_item' => esc_html__( 'edit Commons Booking map', 'commonsbooking' ), + 'new_item' => esc_html__( 'create CB map', 'commonsbooking' ), + 'view_item' => esc_html__( 'view CB map', 'commonsbooking' ), + 'search_items' => esc_html__( 'search CB maps', 'commonsbooking' ), + 'not_found' => esc_html__( 'no Commons Booking map found', 'commonsbooking' ), + 'not_found_in_trash' => esc_html__( 'no Commons Booking map found in the trash', 'commonsbooking' ), + 'parent_item_colon' => esc_html__( 'parent CB maps', 'commonsbooking' ), ); $supports = array( @@ -390,7 +639,7 @@ public function getArgs() { // Sichtbarkeit des Post Types 'public' => true, - // Standart Ansicht im Backend aktivieren (Wie Artikel / Seiten) + // Standard Ansicht im Backend aktivieren (Wie Artikel / Seiten) 'show_ui' => true, // Soll es im Backend Menu sichtbar sein? @@ -405,7 +654,7 @@ public function getArgs() { // in den Navigations Menüs sichtbar machen? 'show_in_nav_menus' => true, 'hierarchical' => false, - 'description' => self::__( 'Maps to show Commons Booking Locations and their Items', 'commonsbooking' ), + 'description' => esc_html__( 'Maps to show Commons Booking Locations and their Items', 'commonsbooking' ), 'supports' => $supports, 'menu_icon' => 'dashicons-location', 'publicly_queryable' => false, @@ -419,20 +668,18 @@ public function getArgs() { } /** - * @param $text - * @param string $domain - * @param null $default + * Renders the shortcode for the map * - * @return mixed */ - public static function __( $text, string $domain = 'default', $default = null ) { - - $translation = __( $text, $domain ); - - if ( $translation == $text && isset( $default ) ) { - $translation = $default; - } - - return $translation; + public static function getShortcode( array $field_args, CMB2_Field $field ) { + $id = get_the_ID(); + ?> + Shortcode: +
    + [cb_map id=] + +
    + -
    - -

    - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - : - - [cb_map id=]
    - : - - - - -
    - : - - - value="on"> -
    - : - - px -
    - : - -
    - : - - value="on">
    -
    -
    - -
    -
    - - - - - - - - - - - - - - - - - - -
    - : - -
    - : - -
    - : - -
    - : - - value="on">
    -
    -
    - -
    -
    - - - - - - - - - - - -
    - : - -
    - : - -
    -
    -
    - -
    -
    - - - - - - - - - - -
    - : - - - value="on"> -
    - : - - - value="on"> -
    -
    -
    - -
    -
    - - - - - - - -
    - : - - value="on">
    -
    -
    -
    -
    - - - - - - - - - - - - - - - -
    - : - - - value="on"> -
    - : - - - -
    - : - - - -
    -
    -
    - -
    -
    - - - - - - - - - - - - - - - - - - - -
    - : - - - - -
    -
    -
    - -
    -
    - - - - - - -
    - : - - - px -
    -
    - -
    - - - - - - - - - - - - - - - - -
    - : - - - - -
    -
    -
    - -
    -
    - - - - - - - -
    - : - - - - -
    -
    -
    - -
    -
    - - - - - - - - - - - - - - - - - - -
    - : - - - - -
    -
    -
    - -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - : - - value="on">
    - : - -
    - : - - - / - -
    - : - - - / - -
    - : - - value="on">
    - : - -
    - : - -
    - : - -
    - : - - -
      -
      - -
      -
    -
    - - - - - - -
    - -
    -
    -
    - -
    -
    - - - - - - -
    - : - - -
      -
      - -
      -
    -
    -
    -
    - -
    -
    - - - - - - -
    - : - - -
      -
      - -
      -
    -
    -
    -
    - -
    - - diff --git a/templates/map-settings-page-template.php b/templates/map-settings-page-template.php deleted file mode 100644 index e26f929d6..000000000 --- a/templates/map-settings-page-template.php +++ /dev/null @@ -1,35 +0,0 @@ - -
    - -

    - -

    - -
    - - - - - - - -
    - : - - - value="on"> -
    - - -
    -
    diff --git a/tests/cypress/wordpress-files/content-example.xml b/tests/cypress/wordpress-files/content-example.xml index ddbd89965..3df37f5e3 100644 --- a/tests/cypress/wordpress-files/content-example.xml +++ b/tests/cypress/wordpress-files/content-example.xml @@ -16,7 +16,7 @@ - + commonsbooking http://localhost:1001 - Thu, 21 Mar 2024 10:24:21 +0000 + Wed, 04 Dec 2024 17:40:51 +0000 en-US 1.2 http://localhost:1001 @@ -44,7 +44,7 @@ - https://wordpress.org/?v=6.4.1 + https://wordpress.org/?v=6.7 <![CDATA[BasicTest - NoAdmin]]> @@ -838,6 +838,14 @@ 0 + + + + + + + + @@ -918,6 +926,14 @@ 0 + + + + + + + + @@ -1002,6 +1018,14 @@ 0 + + + + + + + + @@ -1086,6 +1110,14 @@ 0 + + + + + + + + @@ -1170,6 +1202,14 @@ 0 + + + + + + + + @@ -1256,6 +1296,14 @@ + + + + + + + + @@ -1322,6 +1370,14 @@ 0 + + + + + + + + @@ -1408,6 +1464,14 @@ + + + + + + + + @@ -1474,6 +1538,14 @@ 0 + + + + + + + + @@ -1560,6 +1632,14 @@ + + + + + + + + @@ -1626,6 +1706,14 @@ 0 + + + + + + + + @@ -1740,6 +1828,14 @@ 0 + + + + + + + + @@ -1828,6 +1924,14 @@ 0 + + + + + + + + @@ -1918,6 +2022,14 @@ + + + + + + + + @@ -1976,8 +2088,8 @@ 123 - - + + @@ -1988,20 +2100,84 @@ 0 - - + + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <![CDATA[Navigation]]> + http://localhost:1001/?p=4 + Fri, 27 Sep 2024 11:01:23 +0000 + + http://localhost:1001/?p=4 + + ]]> + + 4 + + + + + + + + + 0 + 0 + + + 0 + + + <![CDATA[Navigation]]> http://localhost:1001/?p=7 Mon, 11 Sep 2023 15:23:00 +0000 @@ -2016,7 +2192,7 @@ - + 0 0 diff --git a/tests/php/Model/BookingTest.php b/tests/php/Model/BookingTest.php index 1f69c5a20..164494929 100644 --- a/tests/php/Model/BookingTest.php +++ b/tests/php/Model/BookingTest.php @@ -6,6 +6,7 @@ use CommonsBooking\Model\Booking; use CommonsBooking\Model\Item; use CommonsBooking\Model\Location; +use CommonsBooking\Model\Restriction; use CommonsBooking\Model\Timeframe; use CommonsBooking\Plugin; use CommonsBooking\Tests\Wordpress\CustomPostTypeTest; @@ -18,7 +19,7 @@ class BookingTest extends CustomPostTypeTest { private Booking $testBookingSpanningOverTwoSlots; private Booking $testBookingFixedDate; private int $testBookingId; - private Item $testItem; + private Item $testItem; private Location $testLocation; private Timeframe $testTimeFrame; private Booking $subscriberBookingInFuture; @@ -28,115 +29,115 @@ class BookingTest extends CustomPostTypeTest { private int $testBookingPastId; public function testGetBookableTimeFrame() { - ClockMock::freeze(new \DateTime(self::CURRENT_DATE)); - $this->assertEquals($this->testTimeFrame,$this->testBookingTomorrow->getBookableTimeFrame()); + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + $this->assertEquals( $this->testTimeFrame, $this->testBookingTomorrow->getBookableTimeFrame() ); } public function testGetLocation() { - $this->assertEquals($this->testLocation,$this->testBookingTomorrow->getLocation()); + $this->assertEquals( $this->testLocation, $this->testBookingTomorrow->getLocation() ); } public function testCancel() { - ClockMock::freeze(new \DateTime(self::CURRENT_DATE)); + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); $this->testBookingTomorrow->cancel(); - $this->cancelBooking($this->testBookingPast); - $this->testBookingTomorrow = new Booking(get_post($this->testBookingId)); - $this->testBookingPast = new Booking(get_post($this->testBookingPastId)); - $this->assertTrue($this->testBookingTomorrow->isCancelled()); - $this->assertFalse($this->testBookingPast->isCancelled()); + $this->cancelBooking( $this->testBookingPast ); + $this->testBookingTomorrow = new Booking( get_post( $this->testBookingId ) ); + $this->testBookingPast = new Booking( get_post( $this->testBookingPastId ) ); + $this->assertTrue( $this->testBookingTomorrow->isCancelled() ); + $this->assertFalse( $this->testBookingPast->isCancelled() ); parent::tearDownAllBookings(); wp_cache_flush(); $this->setUpTestBooking(); } public function testGetItem() { - $this->assertEquals($this->testItem,$this->testBookingTomorrow->getItem()); + $this->assertEquals( $this->testItem, $this->testBookingTomorrow->getItem() ); } - public function testIsPast(){ - ClockMock::freeze(new \DateTime(self::CURRENT_DATE)); - $this->assertFalse($this->testBookingTomorrow->isPast()); - $this->assertTrue($this->testBookingPast->isPast()); + public function testIsPast() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + $this->assertFalse( $this->testBookingTomorrow->isPast() ); + $this->assertTrue( $this->testBookingPast->isPast() ); } - public function testTermsApply(){ + public function testTermsApply() { \CommonsBooking\Plugin::registerItemTaxonomy(); //now let's assign our item to a category, that timeframe also to the same category and check if we can still get the timeframe $taxonomy = \CommonsBooking\Wordpress\CustomPostType\Item::getPostType() . 's_category'; $term = wp_create_term( 'Test Category', $taxonomy ); $otherTerm = wp_create_term( 'Other Category', $taxonomy ); - wp_set_post_terms( $this->itemId, [$term['term_id']], $taxonomy ); - $this->assertTrue($this->testBookingTomorrow->termsApply($term['term_id'])); - $this->assertFalse($this->testBookingTomorrow->termsApply($otherTerm['term_id'])); + wp_set_post_terms( $this->itemId, [ $term['term_id'] ], $taxonomy ); + $this->assertTrue( $this->testBookingTomorrow->termsApply( $term['term_id'] ) ); + $this->assertFalse( $this->testBookingTomorrow->termsApply( $otherTerm['term_id'] ) ); } public function testFilterTermsApply() { \CommonsBooking\Plugin::registerItemTaxonomy(); //now let's assign our item to a category, that timeframe also to the same category and check if we can still get the timeframe - $taxonomy = \CommonsBooking\Wordpress\CustomPostType\Item::getPostType() . 's_category'; - $term = wp_create_term( 'Test Category', $taxonomy ); - $otherItem = $this->createItem( "Other Item",'publish' ); - $otherLocation = $this->createLocation( "Other Location",'publish' ); - $otherTimeframe = $this->createBookableTimeFrameIncludingCurrentDay($otherLocation,$otherItem); - $otherBooking = $this->createBooking( + $taxonomy = \CommonsBooking\Wordpress\CustomPostType\Item::getPostType() . 's_category'; + $term = wp_create_term( 'Test Category', $taxonomy ); + $otherItem = $this->createItem( "Other Item", 'publish' ); + $otherLocation = $this->createLocation( "Other Location", 'publish' ); + $otherTimeframe = $this->createBookableTimeFrameIncludingCurrentDay( $otherLocation, $otherItem ); + $otherBooking = $this->createBooking( $otherLocation, $otherItem, strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), strtotime( '+2 days', strtotime( self::CURRENT_DATE ) ), ); wp_set_post_terms( $this->itemId, [ $term['term_id'] ], $taxonomy ); - $bookingArr = array( + $bookingArr = array( $this->testBookingTomorrow, - new Booking ($otherBooking) + new Booking ( $otherBooking ) ); - $filteredBookings = Booking::filterTermsApply($bookingArr,$term['term_id']); - $this->assertEquals(1,count($filteredBookings)); - $this->assertEquals($this->testBookingTomorrow,$filteredBookings[0]); + $filteredBookings = Booking::filterTermsApply( $bookingArr, $term['term_id'] ); + $this->assertEquals( 1, count( $filteredBookings ) ); + $this->assertEquals( $this->testBookingTomorrow, $filteredBookings[0] ); } - public function testGetDuration(){ - $this->assertEquals(1,$this->testBookingTomorrow->getDuration()); - $this->assertEquals(1,$this->testBookingPast->getDuration()); + public function testGetDuration() { + $this->assertEquals( 1, $this->testBookingTomorrow->getDuration() ); + $this->assertEquals( 1, $this->testBookingPast->getDuration() ); //we now create a booking and cancel it shortly after it ends //this way we can test if all days are counted when it is cancelled shortly before end of the tf - $endTime = strtotime( '+4 days', strtotime( self::CURRENT_DATE ) ); - $cancelBookingId = $this->createBooking( + $endTime = strtotime( '+4 days', strtotime( self::CURRENT_DATE ) ); + $cancelBookingId = $this->createBooking( $this->locationId, $this->itemId, strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), $endTime, ); - $cancelBooking = new Booking( + $cancelBooking = new Booking( $cancelBookingId ); - $this->assertEquals(3,$cancelBooking->getDuration()); + $this->assertEquals( 3, $cancelBooking->getDuration() ); $shortlyBeforeEnd = new \DateTime(); - $shortlyBeforeEnd->setTimestamp($endTime)->modify('-10 minutes'); - ClockMock::freeze($shortlyBeforeEnd); - $this->cancelBooking($cancelBooking); + $shortlyBeforeEnd->setTimestamp( $endTime )->modify( '-10 minutes' ); + ClockMock::freeze( $shortlyBeforeEnd ); + $this->cancelBooking( $cancelBooking ); $cancelBooking = new Booking( $cancelBookingId ); - $this->assertEquals(3,$cancelBooking->getDuration()); + $this->assertEquals( 3, $cancelBooking->getDuration() ); //now we test what happens when a booking is cancelled in the middle of the tf $endTime = strtotime( '+5 days', strtotime( self::CURRENT_DATE ) ); - $cancelBookingId = $this->createBooking( + $cancelBookingId = $this->createBooking( $this->locationId, $this->itemId, strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), $endTime, ); - $cancelBooking = new Booking( + $cancelBooking = new Booking( $cancelBookingId ); - $this->assertEquals(4,$cancelBooking->getDuration()); + $this->assertEquals( 4, $cancelBooking->getDuration() ); $halfBeforeEnd = new \DateTime(); - $halfBeforeEnd->setTimestamp($endTime)->modify('-2 days'); - ClockMock::freeze($halfBeforeEnd); - $this->cancelBooking($cancelBooking); + $halfBeforeEnd->setTimestamp( $endTime )->modify( '-2 days' ); + ClockMock::freeze( $halfBeforeEnd ); + $this->cancelBooking( $cancelBooking ); $cancelBooking = new Booking( $cancelBookingId ); - $this->assertEquals(2,$cancelBooking->getDuration()); + $this->assertEquals( 2, $cancelBooking->getDuration() ); //now we test what happens when a booking is cancelled before it starts. It should have a length of 0 $cancelBookingId = $this->createBooking( @@ -145,28 +146,28 @@ public function testGetDuration(){ strtotime( '+15 day', strtotime( self::CURRENT_DATE ) ), strtotime( '+17 days', strtotime( self::CURRENT_DATE ) ), ); - $cancelBooking = new Booking( + $cancelBooking = new Booking( $cancelBookingId ); - $this->assertEquals(2,$cancelBooking->getDuration()); + $this->assertEquals( 2, $cancelBooking->getDuration() ); $shortlyBeforeStart = new \DateTime(); - $shortlyBeforeStart->setTimestamp(strtotime( '+10 day', strtotime( self::CURRENT_DATE ) )); - ClockMock::freeze($shortlyBeforeStart); - $this->cancelBooking($cancelBooking); + $shortlyBeforeStart->setTimestamp( strtotime( '+10 day', strtotime( self::CURRENT_DATE ) ) ); + ClockMock::freeze( $shortlyBeforeStart ); + $this->cancelBooking( $cancelBooking ); $cancelBooking = new Booking( $cancelBookingId ); - $this->assertEquals(0,$cancelBooking->getDuration()); + $this->assertEquals( 0, $cancelBooking->getDuration() ); // now test with overbooked days - update_post_meta( $this->locationId, COMMONSBOOKING_METABOX_PREFIX. 'count_lockdays_in_range', 'on' ); - update_post_meta( $this->locationId, COMMONSBOOKING_METABOX_PREFIX. 'count_lockdays_maximum', '1' ); + update_post_meta( $this->locationId, COMMONSBOOKING_METABOX_PREFIX . 'count_lockdays_in_range', 'on' ); + update_post_meta( $this->locationId, COMMONSBOOKING_METABOX_PREFIX . 'count_lockdays_maximum', '1' ); $overbookedBooking = new Booking( $this->createBooking( $this->locationId, $this->itemId, strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), strtotime( '+4 days', strtotime( self::CURRENT_DATE ) ), - )); - $overbookedBooking->setOverbookedDays(2); - $this->assertEquals(2,$overbookedBooking->getDuration()); + ) ); + $overbookedBooking->setOverbookedDays( 2 ); + $this->assertEquals( 2, $overbookedBooking->getDuration() ); } @@ -176,11 +177,11 @@ public function testConfirm() { public function testUnconfirm() { // Create booking - $bookingId = $this->createBooking( + $bookingId = $this->createBooking( $this->locationId, $this->itemId, - strtotime( '+1 day', strtotime(self::CURRENT_DATE)), - strtotime( '+2 days', strtotime(self::CURRENT_DATE)), + strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+2 days', strtotime( self::CURRENT_DATE ) ), '8:00 AM', '12:00 PM', 'unconfirmed', @@ -190,12 +191,17 @@ public function testUnconfirm() { } public function testGetOrphaned() { - ClockMock::freeze( new \DateTime( self::CURRENT_DATE)); + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); //create a new booking on a new timeframe and orphan it - $newLocation = $this->createLocation( 'newlocation', 'publish' ); - $newItem = $this->createItem( 'newitem', 'publish' ); - $newTimeframe = $this->createBookableTimeFrameIncludingCurrentDay($newLocation, $newItem); - $newBooking = $this->createBooking( + $newLocation = $this->createLocation( 'newlocation', 'publish' ); + $newItem = $this->createItem( 'newitem', 'publish' ); + $newTimeframe = $this->createTimeframe( + $newLocation, + $newItem, + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+14 days', strtotime( self::CURRENT_DATE ) ) + ); + $newBooking = $this->createBooking( $newLocation, $newItem, strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), @@ -204,10 +210,17 @@ public function testGetOrphaned() { $evenNewerLocation = $this->createLocation( 'evennewerlocation', 'publish' ); update_post_meta( $newTimeframe, 'location-id', $evenNewerLocation ); + //create a booking on the new location that does not collide (and is not an orphan) + $noOrphan = new Booking( $this->createBooking( + $evenNewerLocation, + $newItem, + strtotime( '+7 days', strtotime( self::CURRENT_DATE ) ), + strtotime( '+8 days' ), strtotime( self::CURRENT_DATE ) ) + ); //now retrieve all orphaned bookings and make sure we find the new one $orphanedBookings = \CommonsBooking\Repository\Booking::getOrphaned(); - $this->assertCount(1, $orphanedBookings); - $this->assertEquals($newBooking, reset($orphanedBookings)->ID); + $this->assertCount( 1, $orphanedBookings ); + $this->assertEquals( $newBooking, reset( $orphanedBookings )->ID ); } public function testReturnComment() { @@ -253,46 +266,47 @@ public function testAssignBookableTimeframeFields() { $this->assertNotNull( $timeframe ); $neededMetaFields = [ - 'full-day', - 'grid', - 'start-time', - 'end-time', - Timeframe::META_SHOW_BOOKING_CODES, - 'timeframe-max-days', - ]; + 'full-day', + 'grid', + 'start-time', + 'end-time', + Timeframe::META_SHOW_BOOKING_CODES, + 'timeframe-max-days', + ]; // assert meta value timeframe not null and booking null foreach ( $neededMetaFields as $fieldName ) { - $this->assertNotNull( get_post_meta( - $timeframe->ID, - $fieldName, - true - )); - - //$this->assertEquals( '', get_post_meta( - // $this->testBookingId, - // $fieldName, - // true - //)); + $this->assertNotNull( get_post_meta( + $timeframe->ID, + $fieldName, + true + ) ); + + //$this->assertEquals( '', get_post_meta( + // $this->testBookingId, + // $fieldName, + // true + //)); } $this->testBookingTomorrow->assignBookableTimeframeFields(); // assert meta values of booking are set foreach ( $neededMetaFields as $fieldName ) { - $this->assertNotNull( get_post_meta( - $this->testBookingId, - $fieldName, - true - )); + $this->assertNotNull( get_post_meta( + $this->testBookingId, + $fieldName, + true + ) ); } } public function testFormattedBookingCode() { - $this->assertEquals( '', $this->testBookingTomorrow->formattedBookingCode()); + $this->assertEquals( '', $this->testBookingTomorrow->formattedBookingCode() ); } -public function testCanCancelBaseCase() { - ClockMock::freeze(new \DateTime(self::CURRENT_DATE)); + + public function testCanCancelBaseCase() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); // Case: Booking in the past, no one can cancel $this->assertFalse( $this->testBookingPast->canCancel() ); @@ -306,9 +320,9 @@ public function testCanCancelBaseCase() { // Case: role can edit and != post_author => can cancel | This is the case for WordPress administrators wp_set_current_user( $this->adminUserID ); - $this->assertTrue( current_user_can('administrator' ) ); - $this->assertTrue( current_user_can('edit_posts' ) ); - $this->assertTrue( current_user_can('edit_others_posts' ) ); + $this->assertTrue( current_user_can( 'administrator' ) ); + $this->assertTrue( current_user_can( 'edit_posts' ) ); + $this->assertTrue( current_user_can( 'edit_others_posts' ) ); $userObj = get_user_by( 'ID', $this->adminUserID ); $this->assertTrue( commonsbooking_isUserAdmin( $userObj ) ); @@ -323,14 +337,45 @@ public function testCanCancelBaseCase() { $this->assertTrue( commonsbooking_isUserAllowedToSee( $this->subscriberBookingInFuture, $userObj ) ); $this->assertTrue( commonsbooking_isUserAllowedToEdit( $this->subscriberBookingInFuture, $userObj ) ); - $this->assertTrue( $this->testBookingTomorrow->canCancel() ); + $this->assertTrue( $this->testBookingTomorrow->canCancel() ); - $this->assertTrue( current_user_can('edit_post', $this->testBookingId ) ); + $this->assertTrue( current_user_can( 'edit_post', $this->testBookingId ) ); $this->assertTrue( commonsbooking_isUserAllowedToEdit( $this->testBookingTomorrow->getPost(), $userObj ) ); $this->assertTrue( commonsbooking_isCurrentUserAllowedToEdit( $this->testBookingId ) ); $this->assertTrue( commonsbooking_isCurrentUserAdmin() ); } + public function testHasTotalBreakdown() { + $testBooking = new Booking( $this->createConfirmedBookingStartingToday() ); + $this->assertFalse( $this->testBookingTomorrow->hasTotalBreakdown() ); + + //create a total breakdown that has been active in the past + $oldTotalBreakdown = $this->createRestriction( + Restriction::TYPE_REPAIR, + $this->locationId, + $this->itemId, + strtotime('- 10 days', strtotime( self::CURRENT_DATE )), + strtotime('- 9 days', strtotime( self::CURRENT_DATE )) + ); + $this->assertFalse( $testBooking->hasTotalBreakdown() ); + + //create a total breakdown that is currently inactive + $totalBreakdown = $this->createRestriction( + Restriction::TYPE_REPAIR, + $this->locationId, + $this->itemId, + strtotime( self::CURRENT_DATE ), + strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), + Restriction::STATE_SOLVED + ); + $this->assertFalse( $testBooking->hasTotalBreakdown() ); + + //activate the total breakdown + update_post_meta( $totalBreakdown, Restriction::META_STATE, Restriction::STATE_ACTIVE ); + + $this->assertTrue( $testBooking->hasTotalBreakdown() ); + } + /** * This tests the distinctions of CB Managers when they have been assigned an item or not. * Generally speaking, CB Managers should be able to only cancel bookings of items / locations they manage. @@ -352,7 +397,7 @@ public function testCanCancelCBManagerNoAssignment() { * @throws \Exception */ public function testCanCancelCBManagerItemAssignment() { - ClockMock::freeze(new \DateTime(self::CURRENT_DATE)); + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); $managerUserObj = get_user_by( 'ID', $this->cbManagerUserID ); //let's now create a new item, location and timeframe where the CB Manager is the ITEM manager $managedItem = new Item( @@ -370,14 +415,14 @@ public function testCanCancelCBManagerItemAssignment() { ); $manageTestTimeframe = new Timeframe( $this->createBookableTimeFrameIncludingCurrentDay( - $managedItem->ID(), - $unmanagedLocation->ID() + $managedItem->ID, + $unmanagedLocation->ID ) ); $testBookingTomorrow = new Booking( $this->createBooking( - $unmanagedLocation->ID(), - $managedItem->ID(), + $unmanagedLocation->ID, + $managedItem->ID, strtotime( self::CURRENT_DATE ), strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), '08:00 AM', @@ -404,7 +449,7 @@ public function testCanCancelCBManagerItemAssignment() { */ public function testOnlyViewerRole() { $subscriberUserObj = get_user_by( 'ID', $this->subscriberId ); - ClockMock::freeze(new \DateTime(self::CURRENT_DATE)); + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); //let's now create a new item, location and timeframe and assign the SUBSCRIBER to it $managedItem = new Item( $this->createItem( @@ -421,14 +466,14 @@ public function testOnlyViewerRole() { ); $manageTestTimeframe = new Timeframe( $this->createBookableTimeFrameIncludingCurrentDay( - $managedItem->ID(), - $unmanagedLocation->ID() + $managedItem->ID, + $unmanagedLocation->ID ) ); $testBookingTomorrow = new Booking( $this->createBooking( - $unmanagedLocation->ID(), - $managedItem->ID(), + $unmanagedLocation->ID, + $managedItem->ID, strtotime( self::CURRENT_DATE ), strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), ) @@ -447,21 +492,21 @@ public function testOnlyViewerRole() { public function testIsValid() { //create seperate items and locations for this test - $itemID = $this->createItem("Test Item", 'publish'); - $locationID = $this->createLocation("Test Location", 'publish'); + $itemID = $this->createItem( "Test Item", 'publish' ); + $locationID = $this->createLocation( "Test Location", 'publish' ); $timeframeID = $this->createTimeframe( $locationID, $itemID, - strtotime( '-1 day', strtotime(self::CURRENT_DATE) ), - strtotime( '+20 days', strtotime(self::CURRENT_DATE) ) + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+20 days', strtotime( self::CURRENT_DATE ) ) ); $validBooking = new Booking( $this->createBooking( $locationID, $itemID, - strtotime( '+1 days', strtotime(self::CURRENT_DATE) ), - strtotime( '+2 days', strtotime(self::CURRENT_DATE) ), + strtotime( '+1 days', strtotime( self::CURRENT_DATE ) ), + strtotime( '+2 days', strtotime( self::CURRENT_DATE ) ), ) ); $this->assertTrue( $validBooking->isValid() ); @@ -470,8 +515,8 @@ public function testIsValid() { $this->createBooking( $locationID, $itemID, - strtotime(self::CURRENT_DATE ), - strtotime( '+2 days', strtotime(self::CURRENT_DATE) ), + strtotime( self::CURRENT_DATE ), + strtotime( '+2 days', strtotime( self::CURRENT_DATE ) ), ) ); try { @@ -481,7 +526,7 @@ public function testIsValid() { $this->assertInstanceOf( TimeframeInvalidException::class, $e ); $this->assertStringContainsString( 'There are one ore more overlapping bookings within the chosen timerange', $e->getMessage() ); //also test, that correct notice for Bookings is shown - $this->assertStringContainsString('Booking is saved as draft.', $e->getMessage()); + $this->assertStringContainsString( 'Booking is saved as draft.', $e->getMessage() ); $this->assertStringContainsString( $validBooking->getFormattedEditLink(), $e->getMessage() ); } @@ -489,8 +534,8 @@ public function testIsValid() { $this->createBooking( $locationID, $itemID, - strtotime( '+15 days', strtotime(self::CURRENT_DATE) ), - strtotime( '-1 day', strtotime(self::CURRENT_DATE) ) + strtotime( '+15 days', strtotime( self::CURRENT_DATE ) ), + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ) ) ); try { @@ -505,8 +550,8 @@ public function testIsValid() { $this->createBooking( $locationID, '999', - strtotime( '+10 days', strtotime(self::CURRENT_DATE) ), - strtotime( '+12 days', strtotime(self::CURRENT_DATE) ), + strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ), + strtotime( '+12 days', strtotime( self::CURRENT_DATE ) ), ) ); try { @@ -521,8 +566,8 @@ public function testIsValid() { $this->createBooking( '999', $itemID, - strtotime( '+10 days', strtotime(self::CURRENT_DATE) ), - strtotime( '+12 days', strtotime(self::CURRENT_DATE) ), + strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ), + strtotime( '+12 days', strtotime( self::CURRENT_DATE ) ), ) ); try { @@ -537,8 +582,8 @@ public function testIsValid() { $this->createBooking( $locationID, $itemID, - strtotime( '+25 days', strtotime(self::CURRENT_DATE) ), - strtotime( '+30 days', strtotime(self::CURRENT_DATE) ), + strtotime( '+25 days', strtotime( self::CURRENT_DATE ) ), + strtotime( '+30 days', strtotime( self::CURRENT_DATE ) ), ) ); try { @@ -556,34 +601,34 @@ public function testIsValid() { * @throws \Exception */ public function testCanCancelCBManagerLocationAssignment() { - ClockMock::freeze(new \DateTime(self::CURRENT_DATE)); + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); $managerUserObj = get_user_by( 'ID', $this->cbManagerUserID ); //let's now create a new item, location and timeframe where the CB Manager is the LOCATION manager - $unmanagedItem = new Item( + $unmanagedItem = new Item( $this->createItem( "Unmanaged Item", 'publish' ) ); - $managedLocation = new Location( + $managedLocation = new Location( $this->createLocation( "Managed Location", 'publish', - [$this->cbManagerUserID] + [ $this->cbManagerUserID ] ) ); - $manageTestTimeframe = new Timeframe( + $manageTestTimeframe = new Timeframe( $this->createBookableTimeFrameIncludingCurrentDay( - $unmanagedItem->ID(), - $managedLocation->ID() + $unmanagedItem->ID, + $managedLocation->ID ) ); $testBookingTomorrow2 = new Booking( $this->createBooking( - $managedLocation->ID(), - $unmanagedItem->ID(), - strtotime(self::CURRENT_DATE), - strtotime( '+1 day', strtotime(self::CURRENT_DATE)), + $managedLocation->ID, + $unmanagedItem->ID, + strtotime( self::CURRENT_DATE ), + strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), '08:00 AM', '12:00 PM', 'confirmed', @@ -593,7 +638,7 @@ public function testCanCancelCBManagerLocationAssignment() { //and check if the CB Manager can see & cancel it (because it is their location) $this->assertTrue( commonsbooking_isUserAllowedToSee( $testBookingTomorrow2, $managerUserObj ) ); $this->assertTrue( commonsbooking_isUserAllowedToEdit( $testBookingTomorrow2, $managerUserObj ) ); - wp_set_current_user($this->cbManagerUserID); + wp_set_current_user( $this->cbManagerUserID ); $this->assertTrue( commonsbooking_isCurrentUserAllowedToSee( $testBookingTomorrow2 ) ); $this->assertTrue( commonsbooking_isCurrentUserAllowedToEdit( $testBookingTomorrow2 ) ); $this->assertTrue( $testBookingTomorrow2->canCancel() ); @@ -603,27 +648,27 @@ public function testCanCancelCBManagerLocationAssignment() { public function testSetOverbookedDays() { //case 1: no overbooked days are counted towards the booking limit update_post_meta( $this->locationId, COMMONSBOOKING_METABOX_PREFIX . 'count_lockdays_in_range', 'off' ); - $this->assertEquals(2,$this->testBookingTomorrow->setOverbookedDays(2)); - $this->assertEquals(2, $this->testBookingTomorrow->getOverbookedDays()); + $this->assertEquals( 2, $this->testBookingTomorrow->setOverbookedDays( 2 ) ); + $this->assertEquals( 2, $this->testBookingTomorrow->getOverbookedDays() ); //case 2: one overbooked day is counted towards the booking limit, the rest was overbooked update_post_meta( $this->locationId, COMMONSBOOKING_METABOX_PREFIX . 'count_lockdays_in_range', 'on' ); update_post_meta( $this->locationId, COMMONSBOOKING_METABOX_PREFIX . 'count_lockdays_maximum', '1' ); - $this->assertEquals(6,$this->testBookingTomorrow->setOverbookedDays(7)); - $this->assertEquals(6, $this->testBookingTomorrow->getOverbookedDays()); + $this->assertEquals( 6, $this->testBookingTomorrow->setOverbookedDays( 7 ) ); + $this->assertEquals( 6, $this->testBookingTomorrow->getOverbookedDays() ); //case 3: two days are counted but only one is overbooked update_post_meta( $this->locationId, COMMONSBOOKING_METABOX_PREFIX . 'count_lockdays_maximum', '2' ); - $this->assertEquals(0,$this->testBookingTomorrow->setOverbookedDays(1)); - $this->assertEquals(0, $this->testBookingTomorrow->getOverbookedDays()); + $this->assertEquals( 0, $this->testBookingTomorrow->setOverbookedDays( 1 ) ); + $this->assertEquals( 0, $this->testBookingTomorrow->getOverbookedDays() ); //case 4: all overbooked days are counted towards the booking limit update_post_meta( $this->locationId, COMMONSBOOKING_METABOX_PREFIX . 'count_lockdays_maximum', '0' ); - $this->assertEquals(0,$this->testBookingTomorrow->setOverbookedDays(2)); - $this->assertEquals(0, $this->testBookingTomorrow->getOverbookedDays()); + $this->assertEquals( 0, $this->testBookingTomorrow->setOverbookedDays( 2 ) ); + $this->assertEquals( 0, $this->testBookingTomorrow->getOverbookedDays() ); } - protected function setUpTestBooking():void { + protected function setUpTestBooking(): void { $this->testBookingId = $this->createBooking( $this->locationId, $this->itemId, @@ -639,14 +684,14 @@ protected function setUpTestBooking():void { strtotime( '-2 days', strtotime( self::CURRENT_DATE ) ), strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ) ); - $this->testBookingPast = new Booking(get_post($this->testBookingPastId)); + $this->testBookingPast = new Booking( get_post( $this->testBookingPastId ) ); // Create fixed date booking - $this->testBookingFixedDate = new Booking ( + $this->testBookingFixedDate = new Booking ( $this->createBooking( $this->locationId, $this->itemId, - strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), strtotime( '+2 days', strtotime( self::CURRENT_DATE ) ), '08:00 AM', '12:00 PM' @@ -656,8 +701,8 @@ protected function setUpTestBooking():void { $this->createBooking( $this->locationId, $this->itemId, - strtotime( '+1 day', strtotime(self::CURRENT_DATE)), - strtotime( '+2 days', strtotime(self::CURRENT_DATE)), + strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+2 days', strtotime( self::CURRENT_DATE ) ), '08:00 AM', '12:00 PM', 'confirmed', @@ -673,17 +718,17 @@ protected function setUpTestBooking():void { * @throws \Exception */ protected function setUpTestBookingOverSlotsTimeframes(): void { - $separateItem = $this->createItem("SlotItem", 'publish'); - $separateLocation = $this->createLocation("SlotLocation",'publish'); - $this->createTwoBookableTimeframeSlotsIncludingCurrentDay($separateLocation,$separateItem); + $separateItem = $this->createItem( "SlotItem", 'publish' ); + $separateLocation = $this->createLocation( "SlotLocation", 'publish' ); + $this->createTwoBookableTimeframeSlotsIncludingCurrentDay( $separateLocation, $separateItem ); //create booking spanning over two slots - $beginningTime = new \DateTime(self::CURRENT_DATE); - $beginningTime->setTime(10,00); - $endingTime = new \DateTime(self::CURRENT_DATE); - $endingTime->setTime(17,59,59); + $beginningTime = new \DateTime( self::CURRENT_DATE ); + $beginningTime->setTime( 10, 00 ); + $endingTime = new \DateTime( self::CURRENT_DATE ); + $endingTime->setTime( 17, 59, 59 ); //we need to create this booking in the "frontend" way in order to save the correct grid sizes for the generation //pickup and returntimes - $testBookingSpanningOverTwoSlotsID = \CommonsBooking\Wordpress\CustomPostType\Booking::handleBookingRequest( + $testBookingSpanningOverTwoSlotsID = \CommonsBooking\Wordpress\CustomPostType\Booking::handleBookingRequest( $separateItem, $separateLocation, 'confirmed', @@ -701,18 +746,18 @@ protected function setUpTestBookingOverSlotsTimeframes(): void { $this->bookingIds[] = $testBookingSpanningOverTwoSlotsID; } - protected function setUp() : void { + protected function setUp(): void { parent::setUp(); - $this->firstTimeframeId = $this->createTimeframe( - $this->locationId, - $this->itemId, - strtotime('-5 days', strtotime(self::CURRENT_DATE)), - strtotime('+90 days', strtotime(self::CURRENT_DATE)) + $this->firstTimeframeId = $this->createTimeframe( + $this->locationId, + $this->itemId, + strtotime( '-5 days', strtotime( self::CURRENT_DATE ) ), + strtotime( '+90 days', strtotime( self::CURRENT_DATE ) ) ); - $this->testItem = new Item($this->itemId); - $this->testLocation = new Location($this->locationId); - $this->testTimeFrame = new Timeframe($this->firstTimeframeId); + $this->testItem = new Item( $this->itemId ); + $this->testLocation = new Location( $this->locationId ); + $this->testTimeFrame = new Timeframe( $this->firstTimeframeId ); $this->createSubscriber(); $this->createAdministrator(); $this->createCBManager(); @@ -720,7 +765,7 @@ protected function setUp() : void { $this->setUpTestBookingOverSlotsTimeframes(); } - protected function tearDown() : void { + protected function tearDown(): void { parent::tearDown(); } } diff --git a/tests/php/Model/MapTest.php b/tests/php/Model/MapTest.php new file mode 100644 index 000000000..dad91cba2 --- /dev/null +++ b/tests/php/Model/MapTest.php @@ -0,0 +1,55 @@ +map->get_locations( [] ); + $this->assertIsArray( $locations ); + $this->assertNotEmpty( $locations ); + $this->assertArrayHasKey( $this->geoLocation->ID, $locations ); + $this->assertEquals( 50.9413035, $locations[ $this->geoLocation->ID ]['lat'] ); + $this->assertEquals( 6.9581379978318, $locations[ $this->geoLocation->ID ]['lon'] ); + $this->assertEquals( "Location with Geo", $locations[ $this->geoLocation->ID ]['location_name'] ); + $this->assertEquals( "Domkloster 4", $locations[ $this->geoLocation->ID ]['address']['street'] ); + $this->assertEquals( "Köln", $locations[ $this->geoLocation->ID ]['address']['city'] ); + $this->assertEquals( "50667", $locations[ $this->geoLocation->ID ]['address']['zip'] ); + + $this->assertEquals( $this->itemId, $locations[ $this->geoLocation->ID ]['items'][0]['id'] ); + } + + public function testCleanup_location_data() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + update_post_meta( $this->geoLocation->ID, COMMONSBOOKING_METABOX_PREFIX . 'location_contact', "Contact with HTML and \n linebreaks" ); + update_post_meta( $this->map->ID, 'show_location_contact', 'on' ); + $locations = $this->map->get_locations( [] ); + $this->assertNotEmpty( $locations ); + $locations = Map::cleanup_location_data( $locations, '
    ' ); + $this->assertEquals( "Contact with HTML and
    linebreaks", $locations[ $this->geoLocation->ID ]['contact'] ); + } + + protected function setUp(): void { + parent::setUp(); + $this->map = new Map ( $this->createMap() ); + $this->geoLocation = new Location ( $this->createLocation( "Location with Geo" ) ); + update_post_meta( $this->geoLocation->ID, 'geo_latitude', 50.9413035 ); + update_post_meta( $this->geoLocation->ID, 'geo_longitude', 6.9581379978318 ); + update_post_meta( $this->geoLocation->ID, COMMONSBOOKING_METABOX_PREFIX . 'location_city', 'Köln' ); + update_post_meta( $this->geoLocation->ID, COMMONSBOOKING_METABOX_PREFIX . 'location_country', 'Deutschland' ); + update_post_meta( $this->geoLocation->ID, COMMONSBOOKING_METABOX_PREFIX . 'location_street', 'Domkloster 4' ); + update_post_meta( $this->geoLocation->ID, COMMONSBOOKING_METABOX_PREFIX . 'location_postcode', '50667' ); + $this->createBookableTimeFrameIncludingCurrentDay( $this->geoLocation->ID ); + } + + +} diff --git a/tests/php/Service/MassOperationsTest.php b/tests/php/Service/MassOperationsTest.php index 86f1c8b14..e99904079 100644 --- a/tests/php/Service/MassOperationsTest.php +++ b/tests/php/Service/MassOperationsTest.php @@ -12,28 +12,73 @@ class MassOperationsTest extends CustomPostTypeTest { private Timeframe $testTimeframe; public function testMigrateOrphaned() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + //create an orphaned booking + $orphanMove = new Booking( $this->createConfirmedBookingStartingToday() ); //this booking should be moved + $orphanStay = new Booking( $this->createConfirmedBookingEndingToday() ); //this booking should stay + $newLocation = $this->createLocation( "New Location", 'publish' ); + update_post_meta( $this->testTimeframe->ID, 'location-id', $newLocation ); + + //create new booking on new location that does not collide and is not an orphan + $noOrphan = new Booking( $this->createBooking( $newLocation, + $this->itemId, + strtotime( '+7 days', strtotime( self::CURRENT_DATE ) ), + strtotime( '+8 days' ), strtotime( self::CURRENT_DATE ) ) + ); + + $this->assertTrue( $orphanMove->isOrphaned() ); + $this->assertTrue( $orphanStay->isOrphaned() ); + $orphans = \CommonsBooking\Repository\Booking::getOrphaned(); + $this->assertCount( 2, $orphans ); + $this->assertTrue( MassOperations::migrateOrphaned( [ $orphanMove->ID ] ) ); + + $this->assertFalse( $orphanMove->isOrphaned() ); + $this->assertTrue( $orphanStay->isOrphaned() ); + $this->assertEquals( $newLocation, get_post_meta( $orphanMove->ID, 'location-id', true ) ); + $this->expectExceptionMessage( 'No bookings to move selected.' ); + //empty array given + MassOperations::migrateOrphaned( [] ); + } + + public function testMigrateOrphanedWithExistingBooking() { + //test case #1695: there is already an existing booking on the new location ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); //create an orphaned booking $toOrphan = new Booking( $this->createConfirmedBookingStartingToday() ); $newLocation = $this->createLocation( "New Location", 'publish' ); update_post_meta( $this->testTimeframe->ID, 'location-id', $newLocation ); - $this->assertTrue( $toOrphan->isOrphaned() ); + //create a booking on the new location (in the place where we try to move the orphan later) + new Booking( $this->createConfirmedBookingStartingToday( $newLocation ) ); + $orphans = \CommonsBooking\Repository\Booking::getOrphaned(); $this->assertCount( 1, $orphans ); + $this->expectExceptionMessage( "There is already a booking on the new location during the timeframe of booking with ID " . $toOrphan->ID ); MassOperations::migrateOrphaned( [ $toOrphan->ID ] ); - $this->assertFalse( $toOrphan->isOrphaned() ); - $this->assertEquals( $newLocation, get_post_meta( $toOrphan->ID, 'location-id', true ) ); + } - //empty array given - $result = MassOperations::migrateOrphaned( [] ); - $this->assertFalse( $result['success'] ); + public function testMigrateOrphanedNoValidLocation() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + //create an orphaned booking + $toOrphan = new Booking( $this->createConfirmedBookingStartingToday() ); + $nonExistingLocation = '123456'; + update_post_meta( $this->testTimeframe->ID, 'location-id', $nonExistingLocation ); + + $orphans = \CommonsBooking\Repository\Booking::getOrphaned(); + $this->assertCount( 1, $orphans ); + $this->expectExceptionMessage( "New location not found for booking with ID" ); + MassOperations::migrateOrphaned( [ $toOrphan->ID ] ); } protected function setUp(): void { parent::setUp(); $this->testTimeframe = new Timeframe( - $this->createBookableTimeFrameIncludingCurrentDay() + $this->createTimeframe( + $this->locationId, + $this->itemId, + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+14 days', strtotime( self::CURRENT_DATE ) ) + ) ); } diff --git a/tests/php/Service/SchedulerTest.php b/tests/php/Service/SchedulerTest.php index dad90fff3..def551a6d 100644 --- a/tests/php/Service/SchedulerTest.php +++ b/tests/php/Service/SchedulerTest.php @@ -72,29 +72,35 @@ public function testReSchedule() { ); } + /** + * Tests custom recurrences via wp cron interfaces + */ public function testCustomRecurrence() { + + $thirty_minutes = 'thirty_minutes'; + $customSchedule = new Scheduler( 'test2', 'CommonsBooking\Tests\Service\dummyFunction', - 'thirty_minutes', + $thirty_minutes, '', array($this->dummyOptionsKey,$this->dummyFieldId), $this->dummyUpdateHook ); $this->jobhooks[] = $customSchedule->getJobhook(); - - // Should contain custom cron intervals, because Scheduler(...) adds filter - $this->assertContains( 'thirty_minutes', array_keys( wp_get_schedules() ) ); - $now = new DateTime('now', new \DateTimeZone('UTC')); - $nowTS = $now->getTimestamp(); + // Should contain custom cron intervals, because Scheduler(...) adds filter + $this->assertContains( $thirty_minutes, array_keys( wp_get_schedules() ) ); + $this->assertEquals( - $nowTS, - wp_next_scheduled($customSchedule->getJobhook()) + // returns timestamp which is used to set internal event object (via wp_schedule_event in Scheduler class) + $customSchedule->getTimestamp(), + // returns timestamp from internal event object identified by job hook + wp_next_scheduled( $customSchedule->getJobhook() ) ); $event = wp_get_scheduled_event($customSchedule->getJobhook()); - $this->assertEquals('thirty_minutes',$event->schedule); + $this->assertEquals( $thirty_minutes , $event->schedule ); } diff --git a/tests/php/Service/UpgradeTest.php b/tests/php/Service/UpgradeTest.php index f4c764cf2..4ae1e75fe 100644 --- a/tests/php/Service/UpgradeTest.php +++ b/tests/php/Service/UpgradeTest.php @@ -5,22 +5,21 @@ use CommonsBooking\Model\Timeframe; use CommonsBooking\Service\Upgrade; use CommonsBooking\Tests\Wordpress\CustomPostTypeTest; +use CommonsBooking\Wordpress\CustomPostType\Map; use SlopeIt\ClockMock\ClockMock; -class UpgradeTest extends CustomPostTypeTest -{ +class UpgradeTest extends CustomPostTypeTest { - private static bool $functionAHasRun = false; + private static bool $functionAHasRun = false; private static bool $functionBHasRun = false; private $testTasks; private $ajaxTasks; - public function testFixBrokenICalTitle() - { + public function testFixBrokenICalTitle() { \CommonsBooking\Settings\Settings::updateOption( 'commonsbooking_options_templates', 'emailtemplates_mail-booking_ics_event-title', - 'Booking for {{item:post_name}}' + 'Booking for {{item:post_name}}' ); \CommonsBooking\Settings\Settings::updateOption( COMMONSBOOKING_PLUGIN_SLUG . '_options_advanced-options', @@ -28,21 +27,20 @@ public function testFixBrokenICalTitle() 'Booking for {{item:post_name}}' ); Upgrade::fixBrokenICalTitle(); - $this->assertEquals('Booking for {{item:post_title}}', \CommonsBooking\Settings\Settings::getOption('commonsbooking_options_templates', 'emailtemplates_mail-booking_ics_event-title')); - $this->assertEquals('Booking for {{item:post_title}}', \CommonsBooking\Settings\Settings::getOption(COMMONSBOOKING_PLUGIN_SLUG . '_options_advanced-options', 'event_title')); - } - - public function testIsMajorUpdate() - { - $majorUpdate = new Upgrade('2.5.0', '2.6.0'); - $this->assertTrue($majorUpdate->isMajorUpdate()); - $minorUpdate = new Upgrade('2.5.0', '2.5.1'); - $this->assertFalse($minorUpdate->isMajorUpdate()); - $majorestUpdate = new Upgrade('2.5.0', '3.0.0'); - $this->assertTrue($majorestUpdate->isMajorUpdate()); - $downgrade = new Upgrade('2.6.0', '2.5.0'); - $this->assertFalse($downgrade->isMajorUpdate()); - } + $this->assertEquals( 'Booking for {{item:post_title}}', \CommonsBooking\Settings\Settings::getOption( 'commonsbooking_options_templates', 'emailtemplates_mail-booking_ics_event-title' ) ); + $this->assertEquals( 'Booking for {{item:post_title}}', \CommonsBooking\Settings\Settings::getOption( COMMONSBOOKING_PLUGIN_SLUG . '_options_advanced-options', 'event_title' ) ); + } + + public function testIsMajorUpdate() { + $majorUpdate = new Upgrade( '2.5.0', '2.6.0' ); + $this->assertTrue( $majorUpdate->isMajorUpdate() ); + $minorUpdate = new Upgrade( '2.5.0', '2.5.1' ); + $this->assertFalse( $minorUpdate->isMajorUpdate() ); + $majorestUpdate = new Upgrade( '2.5.0', '3.0.0' ); + $this->assertTrue( $majorestUpdate->isMajorUpdate() ); + $downgrade = new Upgrade( '2.6.0', '2.5.0' ); + $this->assertFalse( $downgrade->isMajorUpdate() ); + } /** * This will test if the upgrade tasks are run correctly. @@ -51,11 +49,11 @@ public function testIsMajorUpdate() * * @dataProvider provideUpgradeConditions */ - public function testRunUpgradeTasks($previousVersion, $currentVersion, $shouldRunFunction) { - $upgrade = new Upgrade($previousVersion, $currentVersion); + public function testRunUpgradeTasks( $previousVersion, $currentVersion, $shouldRunFunction ) { + $upgrade = new Upgrade( $previousVersion, $currentVersion ); $upgrade->runUpgradeTasks(); - $this->assertEquals($shouldRunFunction, self::$functionAHasRun); - $this->assertEquals($shouldRunFunction, self::$functionBHasRun); + $this->assertEquals( $shouldRunFunction, self::$functionAHasRun ); + $this->assertEquals( $shouldRunFunction, self::$functionBHasRun ); } /** @@ -67,117 +65,116 @@ public function testRunUpgradeTasks($previousVersion, $currentVersion, $shouldRu */ public function provideUpgradeConditions() { return array( - "Upgrade directly on version with new function (major)" => ["2.4.0", "2.5.2", true], - "Upgrade past version with new function (major)" => ["2.4.0", "2.6.0", true], - "Direct minor upgrade on same version" => ["2.5.1", "2.5.2", true], - "Direct minor upgrade on version without new function" => ["2.5.0", "2.5.1", false], //This is a weird case that should not happen, usually the function would not be added before it is needed - "Direct minor upgrade past version with new function" => ["2.5.2", "2.5.3", false], - "Direct minor upgrade past version with new function (major)" => ["2.5.2", "2.6.0", false], - "Downgrade from previous versions" => ["2.5.3", "2.5.2", false], + "Upgrade directly on version with new function (major)" => [ "2.4.0", "2.5.2", true ], + "Upgrade past version with new function (major)" => [ "2.4.0", "2.6.0", true ], + "Direct minor upgrade on same version" => [ "2.5.1", "2.5.2", true ], + "Direct minor upgrade on version without new function" => [ "2.5.0", "2.5.1", false ], + //This is a weird case that should not happen, usually the function would not be added before it is needed + "Direct minor upgrade past version with new function" => [ "2.5.2", "2.5.3", false ], + "Direct minor upgrade past version with new function (major)" => [ "2.5.2", "2.6.0", false ], + "Downgrade from previous versions" => [ "2.5.3", "2.5.2", false ], ); } - public static function fakeUpdateFunctionA() - { + public static function fakeUpdateFunctionA() { self::$functionAHasRun = true; } - public static function fakeUpdateFunctionB() - { + public static function fakeUpdateFunctionB() { self::$functionBHasRun = true; } public function testRunTasksAfterUpdate() { $olderVersion = '2.5.0'; - update_option(Upgrade::VERSION_OPTION, $olderVersion); + update_option( Upgrade::VERSION_OPTION, $olderVersion ); Upgrade::runTasksAfterUpdate(); - $this->assertEquals(COMMONSBOOKING_VERSION, get_option(Upgrade::VERSION_OPTION)); + $this->assertEquals( COMMONSBOOKING_VERSION, get_option( Upgrade::VERSION_OPTION ) ); } public function testRun() { - $upgrade = new Upgrade('2.5.0', '2.6.0'); - $this->assertTrue($upgrade->run()); - $this->assertEquals('2.6.0', get_option(Upgrade::VERSION_OPTION)); + $upgrade = new Upgrade( '2.5.0', '2.6.0' ); + $this->assertTrue( $upgrade->run() ); + $this->assertEquals( '2.6.0', get_option( Upgrade::VERSION_OPTION ) ); - $upgrade = new Upgrade('2.5.0', '2.5.1'); - $this->assertTrue($upgrade->run()); - $this->assertEquals('2.5.1', get_option(Upgrade::VERSION_OPTION)); + $upgrade = new Upgrade( '2.5.0', '2.5.1' ); + $this->assertTrue( $upgrade->run() ); + $this->assertEquals( '2.5.1', get_option( Upgrade::VERSION_OPTION ) ); //new installation - $upgrade = new Upgrade('', '2.5.0'); - $this->assertTrue($upgrade->run()); - $this->assertEquals('2.5.0', get_option(Upgrade::VERSION_OPTION)); + $upgrade = new Upgrade( '', '2.5.0' ); + $this->assertTrue( $upgrade->run() ); + $this->assertEquals( '2.5.0', get_option( Upgrade::VERSION_OPTION ) ); //no version change - $upgrade = new Upgrade('2.5.0', '2.5.0'); - $this->assertFalse($upgrade->run()); + $upgrade = new Upgrade( '2.5.0', '2.5.0' ); + $this->assertFalse( $upgrade->run() ); //AJAX tasks present -> should not be run $this->setUpAJAX(); - $upgrade = new Upgrade('2.5.1', '2.5.2'); - $this->assertFalse($upgrade->run()); + $upgrade = new Upgrade( '2.5.1', '2.5.2' ); + $this->assertFalse( $upgrade->run() ); //AJAX tasks should be ignored on new installation - $upgrade = new Upgrade('', '2.5.2'); - $this->assertTrue($upgrade->run()); + $upgrade = new Upgrade( '', '2.5.2' ); + $this->assertTrue( $upgrade->run() ); } public function testSetAdvanceBookingDaysDefault() { //create timeframe without advance booking days $timeframeId = $this->createBookableTimeFrameIncludingCurrentDay(); - update_post_meta($timeframeId, \CommonsBooking\Model\Timeframe::META_TIMEFRAME_ADVANCE_BOOKING_DAYS, ''); + update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_TIMEFRAME_ADVANCE_BOOKING_DAYS, '' ); Upgrade::setAdvanceBookingDaysDefault(); - $this->assertEquals(\CommonsBooking\Wordpress\CustomPostType\Timeframe::ADVANCE_BOOKING_DAYS, get_post_meta($timeframeId, \CommonsBooking\Model\Timeframe::META_TIMEFRAME_ADVANCE_BOOKING_DAYS, true)); + $this->assertEquals( \CommonsBooking\Wordpress\CustomPostType\Timeframe::ADVANCE_BOOKING_DAYS, get_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_TIMEFRAME_ADVANCE_BOOKING_DAYS, true ) ); } public function testRemoveBreakingPostmeta() { - ClockMock::freeze(new \DateTime(self::CURRENT_DATE)); + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); //Create timeframe that should still be valid after the cleanup - $validTF = new Timeframe($this->createBookableTimeFrameStartingInAWeek()); - $this->assertTrue($validTF->isValid()); + $validTF = new Timeframe( $this->createBookableTimeFrameStartingInAWeek() ); + $this->assertTrue( $validTF->isValid() ); //create holiday with ADVANCE_BOOKING_DAYS setting (the function does this by default) $holiday = $this->createTimeframe( $this->locationId, $this->itemId, - strtotime('+1 week', strtotime(self::CURRENT_DATE)), - strtotime('+2 weeks', strtotime(self::CURRENT_DATE)), + strtotime( '+1 week', strtotime( self::CURRENT_DATE ) ), + strtotime( '+2 weeks', strtotime( self::CURRENT_DATE ) ), ); $this->assertTrue( Upgrade::removeBreakingPostmeta() ); - $this->assertEmpty(get_post_meta($holiday, 'advance_booking_days', true)); + $this->assertEmpty( get_post_meta( $holiday, 'advance_booking_days', true ) ); } public function testSetMultiSelectTimeFrameDefault() { $tf = $this->createBookableTimeFrameIncludingCurrentDay(); - update_post_meta($tf, Timeframe::META_ITEM_SELECTION_TYPE, ''); - update_post_meta($tf, Timeframe::META_LOCATION_SELECTION_TYPE, ''); - $this->assertTrue ( Upgrade::setMultiSelectTimeFrameDefault() ); - $this->assertEquals(Timeframe::SELECTION_MANUAL_ID, get_post_meta($tf, Timeframe::META_ITEM_SELECTION_TYPE, true)); - $this->assertEquals(Timeframe::SELECTION_MANUAL_ID, get_post_meta($tf, Timeframe::META_LOCATION_SELECTION_TYPE, true)); + update_post_meta( $tf, Timeframe::META_ITEM_SELECTION_TYPE, '' ); + update_post_meta( $tf, Timeframe::META_LOCATION_SELECTION_TYPE, '' ); + $this->assertTrue( Upgrade::setMultiSelectTimeFrameDefault() ); + $this->assertEquals( Timeframe::SELECTION_MANUAL_ID, get_post_meta( $tf, Timeframe::META_ITEM_SELECTION_TYPE, true ) ); + $this->assertEquals( Timeframe::SELECTION_MANUAL_ID, get_post_meta( $tf, Timeframe::META_LOCATION_SELECTION_TYPE, true ) ); } public function testEnableLocationBookingNotification() { Upgrade::enableLocationBookingNotification(); - $this->assertEquals('on', get_post_meta($this->locationId, COMMONSBOOKING_METABOX_PREFIX . 'location_email_bcc', true) ); + $this->assertEquals( 'on', get_post_meta( $this->locationId, COMMONSBOOKING_METABOX_PREFIX . 'location_email_bcc', true ) ); } public function testIsAJAXUpgrade() { //2.5.0 -> COMMONSBOOKING_VERSION - update_option(Upgrade::VERSION_OPTION, '2.5.0'); - $this->assertFalse(Upgrade::isAJAXUpgrade()); + update_option( Upgrade::VERSION_OPTION, '2.5.0' ); + $this->assertFalse( Upgrade::isAJAXUpgrade() ); $this->setUpAJAX(); //2.5.0 -> COMMONSBOOKING_VERSION - $this->assertTrue(Upgrade::isAJAXUpgrade()); + $this->assertTrue( Upgrade::isAJAXUpgrade() ); //2.6.0 -> COMMONSBOOKING_VERSION - update_option(Upgrade::VERSION_OPTION, '2.6.0'); - $this->assertFalse(Upgrade::isAJAXUpgrade()); + update_option( Upgrade::VERSION_OPTION, '2.6.0' ); + $this->assertFalse( Upgrade::isAJAXUpgrade() ); //fresh install - update_option(Upgrade::VERSION_OPTION, ''); - $this->assertFalse(Upgrade::isAJAXUpgrade()); + update_option( Upgrade::VERSION_OPTION, '' ); + $this->assertFalse( Upgrade::isAJAXUpgrade() ); } /** @@ -188,7 +185,7 @@ protected function setUpAJAX(): void { $this->testTasks->setValue( [ '2.5.2' => [ - [self::class, 'fakeUpdateFunctionA' ], + [ self::class, 'fakeUpdateFunctionA' ], ] ] ); @@ -196,30 +193,180 @@ protected function setUpAJAX(): void { $this->ajaxTasks->setValue( [ '2.5.2' => [ - [self::class, 'fakeUpdateFunctionB' ] + [ self::class, 'fakeUpdateFunctionB' ] ] ] ); } + public function testMigrateMapSettings() { + + + //create taxonomies for test + $twowheelsCat = wp_insert_term( '2 Räder', 'cb_items_category' )['term_id']; + $threewheelsCat = wp_insert_term( '3 Räder', 'cb_items_category' )['term_id']; + $comboCat = wp_insert_term( 'Gespann', 'cb_items_category' )['term_id']; + $childTransportCat = wp_insert_term( 'Kindertransport', 'cb_items_category' )['term_id']; + $chestCat = wp_insert_term( 'Kiste mit Schloss', 'cb_items_category' )['term_id']; + $rainCoverCat = wp_insert_term( 'Regenverdeck', 'cb_items_category' )['term_id']; + $withMotorCat = wp_insert_term( 'mit Elektro', 'cb_items_category' )['term_id']; + $manualPowerCat = wp_insert_term( 'Reine Muskelkraft', 'cb_items_category' )['term_id']; + $mapOptions = array( + 'base_map' => 1, + 'show_scale' => true, + 'map_height' => 400, + 'custom_no_locations_message' => 'No locations found', + 'custom_filterbutton_label' => '', + 'zoom_min' => 9, + 'zoom_max' => 19, + 'scrollWheelZoom' => true, + 'zoom_start' => 9, + 'lat_start' => 50.937531, + 'lon_start' => 6.960279, + 'marker_map_bounds_initial' => true, + 'marker_map_bounds_filter' => true, + 'max_cluster_radius' => 80, + 'marker_tooltip_permanent' => false, + 'custom_marker_media_id' => 0, + 'marker_icon_width' => 0.0, + 'marker_icon_height' => 0.0, + 'marker_icon_anchor_x' => 0.0, + 'marker_icon_anchor_y' => 0.0, + 'show_location_contact' => false, + 'label_location_contact' => '', + 'show_location_opening_hours' => false, + 'label_location_opening_hours' => '', + 'show_item_availability' => false, + 'custom_marker_cluster_media_id' => 0, + 'marker_cluster_icon_width' => 0.0, + 'marker_cluster_icon_height' => 0.0, + 'address_search_bounds_left_bottom_lon' => null, + 'address_search_bounds_left_bottom_lat' => null, + 'address_search_bounds_right_top_lon' => null, + 'address_search_bounds_right_top_lat' => null, + 'show_location_distance_filter' => false, + 'label_location_distance_filter' => '', + 'show_item_availability_filter' => false, + 'label_item_availability_filter' => '', + 'label_item_category_filter' => '', + 'item_draft_appearance' => '1', + 'marker_item_draft_media_id' => 0, + 'marker_item_draft_icon_width' => 0.0, + 'marker_item_draft_icon_height' => 0.0, + 'marker_item_draft_icon_anchor_x' => 0.0, + 'marker_item_draft_icon_anchor_y' => 0.0, + 'cb_items_available_categories' => + array( + 'g1723473456166-602276' => 'Radzahl', + $twowheelsCat => '2 Räder', + $threewheelsCat => '3 Räder', + $comboCat => 'Gespann', + 'g1723473486911-550535' => '', + $childTransportCat => 'Kindertransport', + $chestCat => 'Kiste mit Schloss', + $rainCoverCat => 'Regenverdeck', + 'g1723473495758-257563' => '', + $withMotorCat => 'mit Elektro', + $manualPowerCat => 'Zum Strampeln', + //this is changed markup for that category, should be moved to term meta (_cb_markup) + ), + 'cb_items_preset_categories' => + array(), + 'cb_locations_preset_categories' => + array(), + 'availability_max_days_to_show' => 11, + 'availability_max_day_count' => 14, + ); + $oldMapId = wp_insert_post( [ + 'post_title' => 'Map', + 'post_type' => Map::$postType, + 'post_status' => 'publish' + ] ); + + update_post_meta( $oldMapId, 'cb_map_options', $mapOptions ); + + Upgrade::migrateMapSettings(); + //each option should now have it's own meta entry + foreach ( $mapOptions as $key => $value ) { + if ( $key === 'cb_items_available_categories' || empty($value)) { + continue; + } + $this->assertEquals( $value, get_post_meta( $oldMapId, $key, true ) ); + } + + $expectedFilterCategories = + array( + 0 => + array( + 'name' => 'Radzahl', + 'type' => '', + 'isExclusive' => false, + 'categories' => + array( + 0 => (string) $twowheelsCat, + 1 => (string) $threewheelsCat, + 2 => (string) $comboCat + ), + ), + 1 => + array( + 'name' => '', + 'type' => '', + 'isExclusive' => false, + 'categories' => + array( + 0 => (string) $childTransportCat, + 1 => (string) $chestCat, + 2 => (string) $rainCoverCat + ), + ), + 2 => + array( + 'name' => '', + 'type' => '', + 'isExclusive' => false, + 'categories' => + array( + 0 => (string) $withMotorCat, + 1 => (string) $manualPowerCat + ), + ), + ); + + $this->assertEquals( $expectedFilterCategories, get_post_meta( $oldMapId, 'filtergroups', true ) ); + //assert, that custom markup has been moved + $expectedMarkup = 'Zum Strampeln'; + $this->assertEquals( $expectedMarkup, get_term_meta( $manualPowerCat, COMMONSBOOKING_METABOX_PREFIX . 'markup', true ) ); + + wp_delete_post( $oldMapId, true ); + wp_delete_term( $twowheelsCat, 'cb_items_category' ); + wp_delete_term( $threewheelsCat, 'cb_items_category' ); + wp_delete_term( $comboCat, 'cb_items_category' ); + wp_delete_term( $childTransportCat, 'cb_items_category' ); + wp_delete_term( $chestCat, 'cb_items_category' ); + wp_delete_term( $rainCoverCat, 'cb_items_category' ); + wp_delete_term( $withMotorCat, 'cb_items_category' ); + wp_delete_term( $manualPowerCat, 'cb_items_category' ); + } + protected function setUp(): void { parent::setUp(); //This replaces the original update tasks with a internal test function that just sets a variable to true $this->testTasks = new \ReflectionProperty( '\CommonsBooking\Service\Upgrade', 'upgradeTasks' ); - $this->testTasks->setAccessible(true); + $this->testTasks->setAccessible( true ); $this->testTasks->setValue( [ '2.5.2' => [ - [self::class, 'fakeUpdateFunctionA' ], - [self::class, 'fakeUpdateFunctionB' ] + [ self::class, 'fakeUpdateFunctionA' ], + [ self::class, 'fakeUpdateFunctionB' ] ] ] ); //empty AJAX tasks $this->ajaxTasks = new \ReflectionProperty( '\CommonsBooking\Service\Upgrade', 'ajaxUpgradeTasks' ); - $this->ajaxTasks->setAccessible(true); - $this->ajaxTasks->setValue([]); + $this->ajaxTasks->setAccessible( true ); + $this->ajaxTasks->setValue( [] ); } @@ -227,7 +374,7 @@ protected function tearDown(): void { self::$functionAHasRun = false; self::$functionBHasRun = false; //resets version back to current version - update_option(\CommonsBooking\Service\Upgrade::VERSION_OPTION, COMMONSBOOKING_VERSION); + update_option( \CommonsBooking\Service\Upgrade::VERSION_OPTION, COMMONSBOOKING_VERSION ); parent::tearDown(); } } diff --git a/tests/php/View/CalendarTest.php b/tests/php/View/CalendarTest.php index 291cd6e98..e943c9542 100644 --- a/tests/php/View/CalendarTest.php +++ b/tests/php/View/CalendarTest.php @@ -309,6 +309,54 @@ public function provideGetClosestBookableTimeFrameForToday() { "end_time" => "06:00 PM" ] ], + "daily overlap with different times (present) and no end-date" => [ + "closest" => [ + "repetition" => "d", + "repetition_start" => strtotime( "-1 days", $currentTimestamp ), + "repetition_end" => null, + "start_time" => "8:00 AM", + "end_time" => "01:00 PM" + ], + "other" => [ + "repetition" => "d", + "repetition_start" => strtotime( "-1 days", $currentTimestamp ), + "repetition_end" => null, + "start_time" => "02:00 PM", + "end_time" => "06:00 PM" + ] + ], + "daily overlap when time has not been reached #1720" => [ + "closest" => [ + "repetition" => "d", + "repetition_start" => strtotime( "-1 days", $currentTimestamp ), + "repetition_end" => null, + "start_time" => "04:00 PM", + "end_time" => "05:00 PM" + ], + "other" => [ + "repetition" => "d", + "repetition_start" => strtotime( "-1 days", $currentTimestamp ), + "repetition_end" => null, + "start_time" => "07:00 PM", + "end_time" => "08:00 PM" + ], + ], + "daily not overlapping but hasn't started yet" => [ + "closest" => [ + "repetition" => "d", + "repetition_start" => strtotime( "+1 days", $currentTimestamp ), + "repetition_end" => strtotime( "+2 days", $currentTimestamp ), + 'start_time' => '4:00 PM', + 'end_time' => '5:00 PM' + ], + "other" => [ + "repetition" => "d", + "repetition_start" => strtotime( "+3 days", $currentTimestamp ), + "repetition_end" => strtotime( "+4 days", $currentTimestamp ), + 'start_time' => '7:00 PM', + 'end_time' => '8:00 PM' + ] + ], "daily overlap with different times (future)" => [ "closest" => [ "repetition" => "d", diff --git a/tests/php/Wordpress/CustomPostType/CustomPostTypeTest.php b/tests/php/Wordpress/CustomPostType/CustomPostTypeTest.php index e1412d3ee..fe93c5250 100644 --- a/tests/php/Wordpress/CustomPostType/CustomPostTypeTest.php +++ b/tests/php/Wordpress/CustomPostType/CustomPostTypeTest.php @@ -234,63 +234,7 @@ protected function setUp(): void { $this->restrictionModel = new Restriction( $this->restrictionId ); - $mapOptions = array ( - 'base_map' => 1, - 'show_scale' => true, - 'map_height' => 400, - 'custom_no_locations_message' => '', - 'custom_filterbutton_label' => '', - 'zoom_min' => 9, - 'zoom_max' => 19, - 'scrollWheelZoom' => true, - 'zoom_start' => 9, - 'lat_start' => 50.937531, - 'lon_start' => 6.960279, - 'marker_map_bounds_initial' => true, - 'marker_map_bounds_filter' => true, - 'max_cluster_radius' => 80, - 'marker_tooltip_permanent' => false, - 'custom_marker_media_id' => 0, - 'marker_icon_width' => 0.0, - 'marker_icon_height' => 0.0, - 'marker_icon_anchor_x' => 0.0, - 'marker_icon_anchor_y' => 0.0, - 'show_location_contact' => false, - 'label_location_contact' => '', - 'show_location_opening_hours' => false, - 'label_location_opening_hours' => '', - 'show_item_availability' => false, - 'custom_marker_cluster_media_id' => 0, - 'marker_cluster_icon_width' => 0.0, - 'marker_cluster_icon_height' => 0.0, - 'address_search_bounds_left_bottom_lon' => NULL, - 'address_search_bounds_left_bottom_lat' => NULL, - 'address_search_bounds_right_top_lon' => NULL, - 'address_search_bounds_right_top_lat' => NULL, - 'show_location_distance_filter' => false, - 'label_location_distance_filter' => '', - 'show_item_availability_filter' => false, - 'label_item_availability_filter' => '', - 'label_item_category_filter' => '', - 'item_draft_appearance' => '1', - 'marker_item_draft_media_id' => 0, - 'marker_item_draft_icon_width' => 0.0, - 'marker_item_draft_icon_height' => 0.0, - 'marker_item_draft_icon_anchor_x' => 0.0, - 'marker_item_draft_icon_anchor_y' => 0.0, - 'cb_items_available_categories' => - array ( - ), - 'cb_items_preset_categories' => - array ( - ), - 'cb_locations_preset_categories' => - array ( - ), - 'availability_max_days_to_show' => 11, - 'availability_max_day_count' => 14, - ); - $this->map = $this->createMap($mapOptions); + $this->map = $this->createMap(); $this->mapModel = new Map($this->map); } protected function tearDown(): void { diff --git a/tests/php/Wordpress/CustomPostTypeTest.php b/tests/php/Wordpress/CustomPostTypeTest.php index 96ad79f13..488c64d5a 100644 --- a/tests/php/Wordpress/CustomPostTypeTest.php +++ b/tests/php/Wordpress/CustomPostTypeTest.php @@ -49,6 +49,8 @@ abstract class CustomPostTypeTest extends BaseTestCase { protected $itemIds = []; + protected $mapIds = []; + protected $subscriberId; protected int $adminUserID; @@ -88,22 +90,20 @@ protected function createTimeframe( update_post_meta( $timeframeId, 'type', $type ); // we need to map the multi-location array and multi-item array on a string array because that is the way it is also saved from the WP-backend - if ( is_array($locationId) ) { + if ( is_array( $locationId ) ) { update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_LOCATION_ID_LIST, - array_map('strval',$locationId )); - } - else { + array_map( 'strval', $locationId ) ); + } else { update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_LOCATION_ID, $locationId ); } - if (is_array($itemId)) { + if ( is_array( $itemId ) ) { update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_ITEM_ID_LIST, - array_map('strval', $itemId )); - } - else { + array_map( 'strval', $itemId ) ); + } else { update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_ITEM_ID, $itemId ); @@ -123,11 +123,11 @@ protected function createTimeframe( update_post_meta( $timeframeId, 'end-time', $endTime ); update_post_meta( $timeframeId, 'grid', $grid ); update_post_meta( $timeframeId, 'weekdays', $weekdays ); - update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_MANUAL_SELECTION, $manualSelectionDays); + update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_MANUAL_SELECTION, $manualSelectionDays ); update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_SHOW_BOOKING_CODES, $showBookingCodes ); update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_CREATE_BOOKING_CODES, $createBookingCodes ); //TODO: Make this value configurable - update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_ITEM_SELECTION_TYPE, \CommonsBooking\Model\Timeframe::SELECTION_MANUAL_ID); + update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_ITEM_SELECTION_TYPE, \CommonsBooking\Model\Timeframe::SELECTION_MANUAL_ID ); $this->timeframeIds[] = $timeframeId; @@ -191,7 +191,7 @@ protected function createUnconfirmedBookingEndingTomorrow() { $this->locationId, $this->itemId, strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), - strtotime( '+2 days midnight', strtotime( self::CURRENT_DATE ) ) - 1, + strtotime( '+2 days midnight', strtotime( self::CURRENT_DATE ) ) - 1, null, null, 'unconfirmed' @@ -240,6 +240,7 @@ protected function createBooking( /** * This method is Unit Test specific. Because we need to flush the cache after cancelling. + * * @param \CommonsBooking\Model\Booking $b * * @return void @@ -256,18 +257,20 @@ protected function getEndOfDayTimestamp( $date ) { /** * Creates booking from midnight -> +2 days (relative to self::CURRENT_DATE) + * * @param $locationId * @param $itemId * * @return int|\WP_Error */ - protected function createConfirmedBookingStartingToday($locationId = null, $itemId = null) { + protected function createConfirmedBookingStartingToday( $locationId = null, $itemId = null ) { if ( $locationId === null ) { $locationId = $this->locationId; } if ( $itemId === null ) { $itemId = $this->itemId; } + return $this->createBooking( $locationId, $itemId, @@ -278,18 +281,20 @@ protected function createConfirmedBookingStartingToday($locationId = null, $item /** * Creates timeframe from -1 day -> +1 day (relative to self::CURRENT_DATE) + * * @param $locationId * @param $itemId * * @return int|\WP_Error */ - protected function createBookableTimeFrameIncludingCurrentDay($locationId = null, $itemId = null) { + protected function createBookableTimeFrameIncludingCurrentDay( $locationId = null, $itemId = null ) { if ( $locationId === null ) { $locationId = $this->locationId; } if ( $itemId === null ) { $itemId = $this->itemId; } + return $this->createTimeframe( $locationId, $itemId, @@ -299,7 +304,7 @@ protected function createBookableTimeFrameIncludingCurrentDay($locationId = null } protected function createHolidayTimeframeForAllItemsAndLocations() { - $timeframe = $this->createTimeframe( + $timeframe = $this->createTimeframe( $this->locationId, "", strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), @@ -317,7 +322,8 @@ protected function createHolidayTimeframeForAllItemsAndLocations() { \CommonsBooking\Model\Timeframe::SELECTION_ALL_ID ); //and run our function to update the information - \CommonsBooking\Wordpress\CustomPostType\Timeframe::manageTimeframeMeta($timeframe); + \CommonsBooking\Wordpress\CustomPostType\Timeframe::manageTimeframeMeta( $timeframe ); + return $timeframe; } @@ -331,7 +337,7 @@ protected function createHolidayTimeframeForAllItemsAndLocations() { * * @return array An array where the first element is the 10:00-15:00 timeframe and the second is the 15:00 - 18:00 timeframe. */ - protected function createTwoBookableTimeframeSlotsIncludingCurrentDay( $locationId = null, $itemId = null): array { + protected function createTwoBookableTimeframeSlotsIncludingCurrentDay( $locationId = null, $itemId = null ): array { if ( $locationId === null ) { $locationId = $this->locationId; } @@ -366,23 +372,26 @@ protected function createTwoBookableTimeframeSlotsIncludingCurrentDay( $location "publish", '', ); + return [ $tf1, $tf2 ]; } /** * Creates timeframe from +7 days -> +30 days (relative to self::CURRENT_DATE) + * * @param $locationId * @param $itemId * * @return int|\WP_Error */ - protected function createBookableTimeFrameStartingInAWeek($locationId = null, $itemId = null) { + protected function createBookableTimeFrameStartingInAWeek( $locationId = null, $itemId = null ) { if ( $locationId === null ) { $locationId = $this->locationId; } if ( $itemId === null ) { $itemId = $this->itemId; } + return $this->createTimeframe( $locationId, $itemId, @@ -392,7 +401,7 @@ protected function createBookableTimeFrameStartingInAWeek($locationId = null, $i } // Create Item - protected function createItem($title, $postStatus = 'publish', $admins = [], $postAuthor = self::USER_ID) { + protected function createItem( $title, $postStatus = 'publish', $admins = [], $postAuthor = self::USER_ID ) { $itemId = wp_insert_post( [ 'post_title' => $title, 'post_type' => Item::$postType, @@ -402,7 +411,7 @@ protected function createItem($title, $postStatus = 'publish', $admins = [], $po $this->itemIds[] = $itemId; - if (! empty($admins)) { + if ( ! empty( $admins ) ) { update_post_meta( $itemId, COMMONSBOOKING_METABOX_PREFIX . 'item_admins', $admins ); } @@ -410,7 +419,7 @@ protected function createItem($title, $postStatus = 'publish', $admins = [], $po } // Create Location - protected function createLocation($title, $postStatus = 'publish', $admins = [], $postAuthor = self::USER_ID) { + protected function createLocation( $title, $postStatus = 'publish', $admins = [], $postAuthor = self::USER_ID ) { $locationId = wp_insert_post( [ 'post_title' => $title, 'post_type' => Location::$postType, @@ -420,21 +429,36 @@ protected function createLocation($title, $postStatus = 'publish', $admins = [], $this->locationIds[] = $locationId; - if (! empty($admins)) { + if ( ! empty( $admins ) ) { update_post_meta( $locationId, COMMONSBOOKING_METABOX_PREFIX . 'location_admins', $admins ); } return $locationId; } - protected function createMap($options) { + protected function createMap() { $mapId = wp_insert_post( [ 'post_title' => 'Map', 'post_type' => Map::$postType, 'post_status' => 'publish' ] ); - update_post_meta( $mapId, 'cb_map_options', $options ); + //setup map in new format + $defaultValues = array_reduce( + Map::getCustomFields(), + function ( $result, $option ) { + if ( isset( $option['default'] ) ) { + $result[ $option['id'] ] = $option['default']; + } + + return $result; + }, + array() + ); + foreach ( $defaultValues as $key => $value ) { + update_post_meta( $mapId, $key, $value ); + } + $this->mapIds[] = $mapId; return $mapId; } @@ -444,12 +468,11 @@ protected function createMap($options) { * In that case, the unit tests would fail, because there is already the user with this ID in the database. * @return void */ - protected function createSubscriber(){ - $wp_user = get_user_by('email',"a@a.de"); - if (! $wp_user){ - $this->subscriberId = wp_create_user("normaluser","normal","a@a.de"); - } - else { + protected function createSubscriber() { + $wp_user = get_user_by( 'email', "a@a.de" ); + if ( ! $wp_user ) { + $this->subscriberId = wp_create_user( "normaluser", "normal", "a@a.de" ); + } else { $this->subscriberId = $wp_user->ID; } } @@ -459,14 +482,13 @@ protected function createSubscriber(){ * In that case, the unit tests would fail, because there is already the user with this ID in the database. * @return void */ - public function createAdministrator(){ - $wp_user = get_user_by('email',"admin@admin.de"); - if (! $wp_user) { + public function createAdministrator() { + $wp_user = get_user_by( 'email', "admin@admin.de" ); + if ( ! $wp_user ) { $this->adminUserID = wp_create_user( "adminuser", "admin", "admin@admin.de" ); - $user = new \WP_User( $this->adminUserID ); + $user = new \WP_User( $this->adminUserID ); $user->set_role( 'administrator' ); - } - else { + } else { $this->adminUserID = $wp_user->ID; } } @@ -475,47 +497,45 @@ public function createAdministrator(){ * We use this role to test assigning capabilities to other roles than the CBManager. * @return void */ - protected function createEditor(){ - $wp_user = get_user_by('email',"editor@editor.de"); - if (! $wp_user) { + protected function createEditor() { + $wp_user = get_user_by( 'email', "editor@editor.de" ); + if ( ! $wp_user ) { $this->editorUserID = wp_create_user( "editoruser", "editor", "editor@editor.de" ); $user = new \WP_User( $this->editorUserID ); $user->set_role( 'editor' ); - } - else { + } else { $this->editorUserID = $wp_user->ID; } } - public function createCBManager(){ + public function createCBManager() { //we need to run the functions that add the custom user role and assign it to the user Plugin::addCustomUserRoles(); //and add the caps for each of our custom post types Plugin::addCPTRoleCaps(); - $wp_user = get_user_by('email',"cbmanager@cbmanager.de"); - if (! $wp_user) { + $wp_user = get_user_by( 'email', "cbmanager@cbmanager.de" ); + if ( ! $wp_user ) { $this->cbManagerUserID = wp_create_user( "cbmanager", "cbmanager", "cbmanager@cbmanager.de" ); - $user = new \WP_User( $this->cbManagerUserID ); + $user = new \WP_User( $this->cbManagerUserID ); $user->set_role( Plugin::$CB_MANAGER_ID ); - } - else { + } else { $this->cbManagerUserID = $wp_user->ID; } } - protected function setUp() : void { + protected function setUp(): void { parent::setUp(); - $this->dateFormatted = date( 'Y-m-d', strtotime( self::CURRENT_DATE ) ); + $this->dateFormatted = date( 'Y-m-d', strtotime( self::CURRENT_DATE ) ); - $this->setUpBookingCodesTable(); + $this->setUpBookingCodesTable(); // Create location - $this->locationId = self::createLocation('Testlocation', 'publish'); + $this->locationId = self::createLocation( 'Testlocation', 'publish' ); // Create Item - $this->itemId = self::createItem('TestItem', 'publish'); + $this->itemId = self::createItem( 'TestItem', 'publish' ); } protected function setUpBookingCodesTable() { @@ -534,7 +554,7 @@ protected function setUpBookingCodesTable() { $wpdb->query( $sql ); } - protected function tearDown() : void { + protected function tearDown(): void { parent::tearDown(); ClockMock::reset(); @@ -543,6 +563,7 @@ protected function tearDown() : void { $this->tearDownAllTimeframes(); $this->tearDownAllBookings(); $this->tearDownAllRestrictions(); + $this->tearDownAllMaps(); $this->tearDownBookingCodesTable(); wp_logout(); @@ -578,6 +599,12 @@ protected function tearDownAllRestrictions() { } } + protected function tearDownAllMaps() { + foreach ( $this->mapIds as $id ) { + wp_delete_post( $id, true ); + } + } + protected function tearDownBookingCodesTable() { global $wpdb; $table_name = $wpdb->prefix . BookingCodes::$tablename;