From c933bc94fae9c8e57f2c5b25c1c90b449522b67c Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Wed, 1 Apr 2026 15:13:32 +0200 Subject: [PATCH 001/148] fix #2126 filter commonsbooking_isCurrentUserAdmin not granting edit permissions --- .../hooks-and-filters.md | 2 +- .../basics/permission-management.md | 4 +-- .../hooks-and-filters.md | 2 +- .../basics/permission-management.md | 4 +-- includes/Users.php | 28 ++++++++++--------- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/docs/de/documentation/advanced-functionality/hooks-and-filters.md b/docs/de/documentation/advanced-functionality/hooks-and-filters.md index 9d7a1980d..ccb75ebdd 100644 --- a/docs/de/documentation/advanced-functionality/hooks-and-filters.md +++ b/docs/de/documentation/advanced-functionality/hooks-and-filters.md @@ -84,7 +84,7 @@ zurückgibt. ### Alle Filter Hooks im Überblick: - * [commonsbooking_isCurrentUserAdmin](../basics/permission-management#filterhook-isCurrentUserAdmin) + * [commonsbooking_isUserAdmin](../basics/permission-management#filterhook-isUserAdmin) * commonsbooking_isCurrentUserSubscriber * commonsbooking_get_template_part * commonsbooking_template_tag diff --git a/docs/de/documentation/basics/permission-management.md b/docs/de/documentation/basics/permission-management.md index af22ab9f6..7415c1fc2 100644 --- a/docs/de/documentation/basics/permission-management.md +++ b/docs/de/documentation/basics/permission-management.md @@ -60,14 +60,14 @@ Folgende Dinge darf der CommonsBooking Manager zum Beispiel nicht: * Das Design der Seite ändern * usw. -## CommonsBooking Manager zum Manager für alle Artikel / Standorte machen {#filterhook-isCurrentUserAdmin} +## CommonsBooking Manager zum Manager für alle Artikel / Standorte machen {#filterhook-isUserAdmin} Mithilfe eines [Filter Hooks](../advanced-functionality/hooks-and-filters) kannst du eine bestimmte Rolle so einstellen, dass sie automatisch Manager für alle Artikel / Standorte wird. Das unten genannte Beispiel macht das mit der Rolle 'cb_manager', also konfiguriert den CB-Manager so, dass er automatisch allen Artikeln und Standorten der Instanz zugerechnet wird. Falls das mit einer anderen Rolle passieren soll, muss diese Rolle auch den Manager Rollen mit einem [weiteren Codeschnipsel hinzugefügt werden](#filterhook-manager-roles). ```php add_filter( - 'commonsbooking_isCurrentUserAdmin', + 'commonsbooking_isUserAdmin', function ( bool $isAdmin, WP_User $user ) { return in_array( 'cb_manager', $user->roles, true ) ? true : $isAdmin; }, diff --git a/docs/en/documentation/advanced-functionality/hooks-and-filters.md b/docs/en/documentation/advanced-functionality/hooks-and-filters.md index 9f3e1e074..994bd6faf 100644 --- a/docs/en/documentation/advanced-functionality/hooks-and-filters.md +++ b/docs/en/documentation/advanced-functionality/hooks-and-filters.md @@ -76,7 +76,7 @@ receives a value, modifies it, and then returns it. ### Overview of all filter hooks - * [commonsbooking_isCurrentUserAdmin](../basics/permission-management#filterhook-isCurrentUserAdmin) + * [commonsbooking_isUserAdmin](../basics/permission-management#filterhook-isUserAdmin) * commonsbooking_isCurrentUserSubscriber * commonsbooking_get_template_part * commonsbooking_template_tag diff --git a/docs/en/documentation/basics/permission-management.md b/docs/en/documentation/basics/permission-management.md index b45b586d8..888a95ad5 100644 --- a/docs/en/documentation/basics/permission-management.md +++ b/docs/en/documentation/basics/permission-management.md @@ -47,7 +47,7 @@ In addition, CommonsBooking Managers have no special permissions regarding other * Change the site design * etc. -## Make a CommonsBooking Manager a manager for all items / locations {#filterhook-isCurrentUserAdmin} +## Make a CommonsBooking Manager a manager for all items / locations {#filterhook-isUserAdmin} With a [filter hook](../advanced-functionality/hooks-and-filters) you can set a specific role so that it automatically becomes a manager for all items / locations. The example below does this for the role 'cb_manager', i.e. it configures the CB Manager to be automatically assigned to all items and locations in the instance. @@ -55,7 +55,7 @@ If this should happen with a different role, that role must also be added to the ```php add_filter( - 'commonsbooking_isCurrentUserAdmin', + 'commonsbooking_isUserAdmin', function ( bool $isAdmin, WP_User $user ) { return in_array( 'cb_manager', $user->roles, true ) ? true : $isAdmin; }, diff --git a/includes/Users.php b/includes/Users.php index c3220544b..9b9f5272a 100644 --- a/includes/Users.php +++ b/includes/Users.php @@ -171,17 +171,7 @@ function commonsbooking_isCurrentUserAdmin() { return false; } $user = wp_get_current_user(); - $isAdmin = commonsbooking_isUserAdmin( $user ); - /** - * Default value if current user is admin. - * - * @since 2.10.0 add $user param - * @since 2.4.3 - * - * @param bool $isAdmin true or false, if current user is admin - * @param null|WP_User $user current user - */ - return apply_filters( 'commonsbooking_isCurrentUserAdmin', $isAdmin, $user ); + return commonsbooking_isUserAdmin( $user ); } /** @@ -195,12 +185,24 @@ function commonsbooking_isCurrentUserAdmin() { * @return bool */ function commonsbooking_isUserAdmin( \WP_User $user ) { + $isAdmin = false; foreach ( \CommonsBooking\Repository\UserRepository::getAdminRoles() as $adminRole ) { if ( in_array( $adminRole, $user->roles ) ) { - return true; + $isAdmin = true; + break; } } - return false; + /** + * Default value if user is admin. + * + * @since 2.11 changed from commonsbooking_isCurrentUserAdmin to commonsbooking_isUserAdmin + * @since 2.10.0 add $user param + * @since 2.4.3 + * + * @param bool $isAdmin true or false, if current user is admin + * @param null|WP_User $user current user + */ + return apply_filters( 'commonsbooking_isUserAdmin', $isAdmin, $user ); } /** From 87a55679629c689046885f66c786b1e126425712 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Wed, 15 Apr 2026 11:47:53 +0200 Subject: [PATCH 002/148] #2143 filter hook for gbfs feed announcement --- .../hooks-and-filters.md | 1 + .../hooks-and-filters.md | 1 + src/API/GBFS/Discovery.php | 22 +++++++++++++++---- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/docs/de/documentation/advanced-functionality/hooks-and-filters.md b/docs/de/documentation/advanced-functionality/hooks-and-filters.md index 01f7587be..d1346efc7 100644 --- a/docs/de/documentation/advanced-functionality/hooks-and-filters.md +++ b/docs/de/documentation/advanced-functionality/hooks-and-filters.md @@ -96,6 +96,7 @@ zurückgibt. * commonsbooking_mail_body * commonsbooking_mail_attachment * commonsbooking_disableCache + * commonsbooking_gbfs_feeds Es gibt auch Filter Hooks, mit denen du zusätzliche Benutzerrollen, die zusätzlich zum CB Manager Artikel und Standorte administrieren können, diff --git a/docs/en/documentation/advanced-functionality/hooks-and-filters.md b/docs/en/documentation/advanced-functionality/hooks-and-filters.md index fa83c1623..f95a42434 100644 --- a/docs/en/documentation/advanced-functionality/hooks-and-filters.md +++ b/docs/en/documentation/advanced-functionality/hooks-and-filters.md @@ -88,6 +88,7 @@ receives a value, modifies it, and then returns it. * commonsbooking_mail_body * commonsbooking_mail_attachment * commonsbooking_disableCache + * commonsbooking_gbfs_feeds There are also filter hooks that allow you to add additional user roles akin to the CB Manager that can manage items and locations. diff --git a/src/API/GBFS/Discovery.php b/src/API/GBFS/Discovery.php index 0a31b16e9..4f66b51f0 100644 --- a/src/API/GBFS/Discovery.php +++ b/src/API/GBFS/Discovery.php @@ -34,10 +34,24 @@ class Discovery extends \CommonsBooking\API\BaseRoute { */ public function get_items( $request ): WP_REST_Response { - $feeds = array(); - $feeds[] = $this->get_feed( 'system_information' ); - $feeds[] = $this->get_feed( 'station_information' ); - $feeds[] = $this->get_feed( 'station_status' ); + /** + * The names of the feeds that are available in the GBFS route. + * They will be announced through the gbfs.json. + * The routes still need to be registered using register_rest_route. + * + * @since 2.11 + * + * @param String[] $raw_feeds the names of the feeds without a .json suffix + */ + $raw_feeds = apply_filters( + 'commonsbooking_gbfs_feeds', + [ + 'system_information', + 'station_information', + 'station_status', + ] + ); + $feeds = array_map( fn( $feed ) => $this->get_feed( $feed ), $raw_feeds ); $response = new stdClass(); $response->data = new stdClass(); From 1f5dddc6a2d6b0df4abc0b6650045972039a7518 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Wed, 15 Apr 2026 19:23:09 +0200 Subject: [PATCH 003/148] GBFS: refactor every response to go through same validation function --- src/API/GBFS/BaseRoute.php | 6 +----- src/API/GBFS/Discovery.php | 6 +----- src/API/GBFS/SystemInformation.php | 6 +----- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/API/GBFS/BaseRoute.php b/src/API/GBFS/BaseRoute.php index f44c3ecfc..75b143fcf 100644 --- a/src/API/GBFS/BaseRoute.php +++ b/src/API/GBFS/BaseRoute.php @@ -33,11 +33,7 @@ public function get_items( $request ): WP_REST_Response { $response->ttl = 60; $response->version = '3.1-RC2'; - if ( WP_DEBUG ) { - $this->validateData( $response ); - } - - return new WP_REST_Response( $response, 200 ); + return $this->respond_with_validation( $response ); } /** diff --git a/src/API/GBFS/Discovery.php b/src/API/GBFS/Discovery.php index 4f66b51f0..5bdad3964 100644 --- a/src/API/GBFS/Discovery.php +++ b/src/API/GBFS/Discovery.php @@ -60,11 +60,7 @@ public function get_items( $request ): WP_REST_Response { $response->ttl = 86400; $response->version = '3.1-RC2'; - if ( WP_DEBUG ) { - $this->validateData( $response ); - } - - return new WP_REST_Response( $response, 200 ); + return $this->respond_with_validation( $response ); } private function get_feed( $name ): stdClass { diff --git a/src/API/GBFS/SystemInformation.php b/src/API/GBFS/SystemInformation.php index 7eb4e4ad1..d40a67a61 100644 --- a/src/API/GBFS/SystemInformation.php +++ b/src/API/GBFS/SystemInformation.php @@ -45,10 +45,6 @@ public function get_items( $request ): WP_REST_Response { $response->ttl = 86400; $response->version = '3.1-RC2'; - if ( WP_DEBUG ) { - $this->validateData( $response ); - } - - return new WP_REST_Response( $response, 200 ); + return $this->respond_with_validation( $response ); } } From ee21cdb9e20be068f4e2fa50a98ad33011ed84f4 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Thu, 16 Apr 2026 00:29:17 +0200 Subject: [PATCH 004/148] test for #2158 BookingRule::checkMaxBookingDays does not work for uneven amount of days --- tests/php/Service/BookingRuleTest.php | 52 +++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests/php/Service/BookingRuleTest.php b/tests/php/Service/BookingRuleTest.php index 50d0b9142..64f9f2a93 100644 --- a/tests/php/Service/BookingRuleTest.php +++ b/tests/php/Service/BookingRuleTest.php @@ -277,6 +277,58 @@ public function testCheckMaxBookingDays_earlyCancel() { $this->assertNull( BookingRule::checkMaxBookingDays( $allowedBooking, array( 4, 30 ) ) ); } + /** + * Regression test for #2158 + * @return void + */ + public function testCheckMaxBookingDays_unevenDays() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + $testBookingOne = new Booking( + get_post( + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '+1 day' ), + strtotime( '+2 days' ), + '8:00 AM', + '12:00 PM', + 'confirmed', + $this->subscriberId + ) + ) + ); + $testBookingTwo = new Booking( + get_post( + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '+4 day' ), + strtotime( '+5 days' ), + '8:00 AM', + '12:00 PM', + 'confirmed', + $this->subscriberId + ) + ) + ); + + $testBookingThree = new Booking( + get_post( + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '+6 day' ), + strtotime( '+7 days' ), + '8:00 AM', + '12:00 PM', + 'unconfirmed', + $this->subscriberId + ) + ) + ); + $this->assertBookingsPresent( array( $testBookingOne, $testBookingTwo ), BookingRule::checkMaxBookingDays( $testBookingThree, array( 2, 25 ) ) ); + } + public function testCheckMaxBookingDaysPerWeek() { // rule settings $allowedPerWeek = 2; From 53fa4b03c1592ee9fe91cd5de9029bd3f8a86eca Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Thu, 16 Apr 2026 00:30:22 +0200 Subject: [PATCH 005/148] fix #2158 BookingRule::checkMaxBookingDays does not work for uneven amount of days --- src/Service/BookingRule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Service/BookingRule.php b/src/Service/BookingRule.php index bbe26f427..47299519c 100644 --- a/src/Service/BookingRule.php +++ b/src/Service/BookingRule.php @@ -443,7 +443,7 @@ public static function checkMaxBookingDays( Booking $booking, array $args, $appl $allowedBookedDays = $args[0]; $periodDays = $args[1]; // split the period in half, when it is an uneven number, the left side will be one day longer - $daysHalf = $periodDays / 2; + $daysHalf = floor( $periodDays / 2 ); if ( $periodDays % 2 ) { $daysLeft = $daysHalf + 1; $daysRight = $daysHalf - 1; From a12713a4806b35b15d1cd919ff7cac994231adbd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 23:17:36 +0200 Subject: [PATCH 006/148] npm(deps-dev): bump @wordpress/env from 11.3.0 to 11.4.0 (#2167) Bumps [@wordpress/env](https://github.com/WordPress/gutenberg/tree/HEAD/packages/env) from 11.3.0 to 11.4.0. - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/env/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/env@11.4.0/packages/env) --- updated-dependencies: - dependency-name: "@wordpress/env" dependency-version: 11.4.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 910 +++++++++++++++++++++++++++++++++++++++++++++- package.json | 2 +- 2 files changed, 892 insertions(+), 20 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3433b16f0..28071c2e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ }, "devDependencies": { "@babel/preset-env": "^7.29.2", - "@wordpress/env": "^11.0.0", + "@wordpress/env": "^11.4.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", "cypress": "^15.13.1", "editorconfig": "^3.0.2", @@ -1934,6 +1934,278 @@ } } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/linux-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", @@ -1950,6 +2222,108 @@ "node": ">=12" } }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@headlessui/vue": { "version": "1.7.16", "resolved": "https://registry.npmjs.org/@headlessui/vue/-/vue-1.7.16.tgz", @@ -3102,21 +3476,189 @@ "funding": { "type": "opencollective", "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.0", - "@parcel/watcher-darwin-arm64": "2.5.0", - "@parcel/watcher-darwin-x64": "2.5.0", - "@parcel/watcher-freebsd-x64": "2.5.0", - "@parcel/watcher-linux-arm-glibc": "2.5.0", - "@parcel/watcher-linux-arm-musl": "2.5.0", - "@parcel/watcher-linux-arm64-glibc": "2.5.0", - "@parcel/watcher-linux-arm64-musl": "2.5.0", - "@parcel/watcher-linux-x64-glibc": "2.5.0", - "@parcel/watcher-linux-x64-musl": "2.5.0", - "@parcel/watcher-win32-arm64": "2.5.0", - "@parcel/watcher-win32-ia32": "2.5.0", - "@parcel/watcher-win32-x64": "2.5.0" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.0", + "@parcel/watcher-darwin-arm64": "2.5.0", + "@parcel/watcher-darwin-x64": "2.5.0", + "@parcel/watcher-freebsd-x64": "2.5.0", + "@parcel/watcher-linux-arm-glibc": "2.5.0", + "@parcel/watcher-linux-arm-musl": "2.5.0", + "@parcel/watcher-linux-arm64-glibc": "2.5.0", + "@parcel/watcher-linux-arm64-musl": "2.5.0", + "@parcel/watcher-linux-x64-glibc": "2.5.0", + "@parcel/watcher-linux-x64-musl": "2.5.0", + "@parcel/watcher-win32-arm64": "2.5.0", + "@parcel/watcher-win32-ia32": "2.5.0", + "@parcel/watcher-win32-x64": "2.5.0" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.0.tgz", + "integrity": "sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.0.tgz", + "integrity": "sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.0.tgz", + "integrity": "sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.0.tgz", + "integrity": "sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.0.tgz", + "integrity": "sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.0.tgz", + "integrity": "sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.0.tgz", + "integrity": "sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.0.tgz", + "integrity": "sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, "node_modules/@parcel/watcher-linux-x64-glibc": { @@ -3159,6 +3701,69 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.0.tgz", + "integrity": "sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.0.tgz", + "integrity": "sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.0.tgz", + "integrity": "sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@peculiar/asn1-cms": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.6.1.tgz", @@ -4084,6 +4689,216 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.41.1.tgz", + "integrity": "sha512-NELNvyEWZ6R9QMkiytB4/L4zSEaBC03KIXEghptLGLZWJ6VPrL63ooZQCOnlx36aQPGhzuOMwDerC1Eb2VmrLw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.41.1.tgz", + "integrity": "sha512-DXdQe1BJ6TK47ukAoZLehRHhfKnKg9BjnQYUu9gzhI8Mwa1d2fzxA1aw2JixHVl403bwp1+/o/NhhHtxWJBgEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.41.1.tgz", + "integrity": "sha512-5afxvwszzdulsU2w8JKWwY8/sJOLPzf0e1bFuvcW5h9zsEg+RQAojdW0ux2zyYAz7R8HvvzKCjLNJhVq965U7w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.41.1.tgz", + "integrity": "sha512-egpJACny8QOdHNNMZKf8xY0Is6gIMz+tuqXlusxquWu3F833DcMwmGM7WlvCO9sB3OsPjdC4U0wHw5FabzCGZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.41.1.tgz", + "integrity": "sha512-DBVMZH5vbjgRk3r0OzgjS38z+atlupJ7xfKIDJdZZL6sM6wjfDNo64aowcLPKIx7LMQi8vybB56uh1Ftck/Atg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.41.1.tgz", + "integrity": "sha512-3FkydeohozEskBxNWEIbPfOE0aqQgB6ttTkJ159uWOFn42VLyfAiyD9UK5mhu+ItWzft60DycIN1Xdgiy8o/SA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.41.1.tgz", + "integrity": "sha512-wC53ZNDgt0pqx5xCAgNunkTzFE8GTgdZ9EwYGVcg+jEjJdZGtq9xPjDnFgfFozQI/Xm1mh+D9YlYtl+ueswNEg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.41.1.tgz", + "integrity": "sha512-jwKCca1gbZkZLhLRtsrka5N8sFAaxrGz/7wRJ8Wwvq3jug7toO21vWlViihG85ei7uJTpzbXZRcORotE+xyrLA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.41.1.tgz", + "integrity": "sha512-g0UBcNknsmmNQ8V2d/zD2P7WWfJKU0F1nu0k5pW4rvdb+BIqMm8ToluW/eeRmxCared5dD76lS04uL4UaNgpNA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.41.1.tgz", + "integrity": "sha512-XZpeGB5TKEZWzIrj7sXr+BEaSgo/ma/kCgrZgL0oo5qdB1JlTzIYQKel/RmhT6vMAvOdM2teYlAaOGJpJ9lahg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.41.1.tgz", + "integrity": "sha512-bkCfDJ4qzWfFRCNt5RVV4DOw6KEgFTUZi2r2RuYhGWC8WhCA8lCAJhDeAmrM/fdiAH54m0mA0Vk2FGRPyzI+tw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.41.1.tgz", + "integrity": "sha512-3mr3Xm+gvMX+/8EKogIZSIEF0WUu0HL9di+YWlJpO8CQBnoLAEL/roTCxuLncEdgcfJcvA4UMOf+2dnjl4Ut1A==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.41.1.tgz", + "integrity": "sha512-3rwCIh6MQ1LGrvKJitQjZFuQnT2wxfU+ivhNBzmxXTXPllewOF7JR1s2vMX/tWtUYFgphygxjqMl76q4aMotGw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.41.1.tgz", + "integrity": "sha512-LdIUOb3gvfmpkgFZuccNa2uYiqtgZAz3PTzjuM5bH3nvuy9ty6RGc/Q0+HDFrHrizJGVpjnTZ1yS5TNNjFlklw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.41.1.tgz", + "integrity": "sha512-oIE6M8WC9ma6xYqjvPhzZYk6NbobIURvP/lEbh7FWplcMO6gn7MM2yHKA1eC/GvYwzNKK/1LYgqzdkZ8YFxR8g==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-x64-gnu": { "version": "4.41.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.41.1.tgz", @@ -4110,6 +4925,48 @@ "linux" ] }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.41.1.tgz", + "integrity": "sha512-lZkCxIrjlJlMt1dLO/FbpZbzt6J/A8p4DnqzSa4PWqPEUUUnzXLeki/iyPLfV0BmHItlYgHUqJe+3KiyydmiNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.41.1.tgz", + "integrity": "sha512-+psFT9+pIh2iuGsxFYYa/LhS5MFKmuivRsx9iPJWNSGbh2XVEjk90fmpUEjCnILPEPJnikAU6SFDiEUyOv90Pg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.41.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.41.1.tgz", + "integrity": "sha512-Wq2zpapRYLfi4aKxf2Xff0tN+7slj2d4R87WEzqw7ZLsVvO5zwYCIuEGSZYiK41+GlwUo1HiR+GdkLEJnCKTCw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@shikijs/core": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-2.5.0.tgz", @@ -4732,9 +5589,9 @@ } }, "node_modules/@wordpress/env": { - "version": "11.3.0", - "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-11.3.0.tgz", - "integrity": "sha512-LxJGteosQmrOV8JEqEIeh3N8/poplFexJjW2M0b+GpKfd7Njt6zoEZhONo01YIR01gk2d21HPBApBw5goa84Xg==", + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-11.4.0.tgz", + "integrity": "sha512-Rk25QAVr1diXIT7HPhRSTfyP5s3+dNYSfYEgVyt1HYeO1u5sqHwMBT+KH82HSvfxgPQv4e3JZCK4B+11Bw7ozQ==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -8574,6 +9431,21 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", diff --git a/package.json b/package.json index 64700cc75..86f72c2a8 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "devDependencies": { "@babel/preset-env": "^7.29.2", - "@wordpress/env": "^11.0.0", + "@wordpress/env": "^11.4.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", "cypress": "^15.13.1", "editorconfig": "^3.0.2", From 6bc635029ab061bc209609659f5d8130fa10e35b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Apr 2026 23:17:51 +0200 Subject: [PATCH 007/148] npm(deps-dev): bump cypress from 15.13.1 to 15.14.0 (#2166) Bumps [cypress](https://github.com/cypress-io/cypress) from 15.13.1 to 15.14.0. - [Release notes](https://github.com/cypress-io/cypress/releases) - [Changelog](https://github.com/cypress-io/cypress/blob/develop/CHANGELOG.md) - [Commits](https://github.com/cypress-io/cypress/compare/v15.13.1...v15.14.0) --- updated-dependencies: - dependency-name: cypress dependency-version: 15.14.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 28071c2e4..01ff74d4f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,7 @@ "@babel/preset-env": "^7.29.2", "@wordpress/env": "^11.4.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", - "cypress": "^15.13.1", + "cypress": "^15.14.0", "editorconfig": "^3.0.2", "grunt": "^1.6.1", "grunt-babel": "^8.0.0", @@ -7706,9 +7706,9 @@ "license": "MIT" }, "node_modules/cypress": { - "version": "15.13.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.13.1.tgz", - "integrity": "sha512-jLkgo75zlwo7PhXp0XJot+zIfFSDzN1SvTml6Xf3ETM1XHRWnH3Q4LAR3orCo/BsnxPnhjG3m5HYSvn9DAtwBg==", + "version": "15.14.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.14.0.tgz", + "integrity": "sha512-AHt9YLKVl6uOFfXsLM3+LSZFwsx36BJRyFv4CjsqcRgr+V9kir0IPVRZUgqZVNudRalx771A1c4yR3DmXvSiBQ==", "dev": true, "hasInstallScript": true, "license": "MIT", diff --git a/package.json b/package.json index 86f72c2a8..47c836c0b 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "@babel/preset-env": "^7.29.2", "@wordpress/env": "^11.4.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", - "cypress": "^15.13.1", + "cypress": "^15.14.0", "editorconfig": "^3.0.2", "grunt": "^1.6.1", "grunt-babel": "^8.0.0", From 36bf4420b2424bf03fe775ab07d0b475b92b561b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 07:36:28 +0200 Subject: [PATCH 008/148] npm(deps-dev): bump grunt from 1.6.1 to 1.6.2 (#2165) Bumps [grunt](https://github.com/gruntjs/grunt) from 1.6.1 to 1.6.2. - [Release notes](https://github.com/gruntjs/grunt/releases) - [Changelog](https://github.com/gruntjs/grunt/blob/main/CHANGELOG) - [Commits](https://github.com/gruntjs/grunt/compare/v1.6.1...v1.6.2) --- updated-dependencies: - dependency-name: grunt dependency-version: 1.6.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 132 +++++++--------------------------------------- package.json | 2 +- 2 files changed, 20 insertions(+), 114 deletions(-) diff --git a/package-lock.json b/package-lock.json index 01ff74d4f..932a4d962 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "commons-api": "git+https://github.com/wielebenwir/commons-api.git", "cypress": "^15.14.0", "editorconfig": "^3.0.2", - "grunt": "^1.6.1", + "grunt": "^1.6.2", "grunt-babel": "^8.0.0", "grunt-cli": "^1.5.0", "grunt-contrib-clean": "^2.0.1", @@ -9769,24 +9769,25 @@ "dev": true }, "node_modules/grunt": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.6.1.tgz", - "integrity": "sha512-/ABUy3gYWu5iBmrUSRBP97JLpQUm0GgVveDCp6t3yRNIoltIYw7rEj3g5y1o2PGPR2vfTRGa7WC/LZHLTXnEzA==", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.6.2.tgz", + "integrity": "sha512-bUzh5nA/P5L66ihXTDP6J5BGnMB/8lXJXejYWSbH4Y4TvWM9t2S39sggQDYYQlx06cYcCsmu63HMYHGCIzUVfg==", "dev": true, + "license": "MIT", "dependencies": { "dateformat": "~4.6.2", "eventemitter2": "~0.4.13", "exit": "~0.1.2", "findup-sync": "~5.0.0", "glob": "~7.1.6", - "grunt-cli": "~1.4.3", + "grunt-cli": "^1.4.3", "grunt-known-options": "~2.0.0", "grunt-legacy-log": "~3.0.0", "grunt-legacy-util": "~2.0.1", "iconv-lite": "~0.6.3", "js-yaml": "~3.14.0", - "minimatch": "~3.0.4", - "nopt": "~3.0.6" + "minimatch": "^3.1.5", + "nopt": "^5.0.0" }, "bin": { "grunt": "bin/grunt" @@ -9827,21 +9828,6 @@ "node": ">=10" } }, - "node_modules/grunt-cli/node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dev": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/grunt-contrib-clean": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/grunt-contrib-clean/-/grunt-contrib-clean-2.0.1.tgz", @@ -10397,62 +10383,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/grunt/node_modules/grunt-cli": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.3.tgz", - "integrity": "sha512-9Dtx/AhVeB4LYzsViCjUQkd0Kw0McN2gYpdmGYKtE2a5Yt7v1Q+HYZVWhqXc/kGnxlMtqKDxSwotiGeFmkrCoQ==", - "dev": true, - "dependencies": { - "grunt-known-options": "~2.0.0", - "interpret": "~1.1.0", - "liftup": "~3.0.1", - "nopt": "~4.0.1", - "v8flags": "~3.2.0" - }, - "bin": { - "grunt": "bin/grunt" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/grunt/node_modules/grunt-cli/node_modules/nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", - "dev": true, - "dependencies": { - "abbrev": "1", - "osenv": "^0.1.4" - }, - "bin": { - "nopt": "bin/nopt.js" - } - }, - "node_modules/grunt/node_modules/minimatch": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", - "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/grunt/node_modules/v8flags": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", - "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/gzip-size": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", @@ -12739,10 +12669,11 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -12956,15 +12887,19 @@ } }, "node_modules/nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", "dev": true, + "license": "ISC", "dependencies": { "abbrev": "1" }, "bin": { "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" } }, "node_modules/normalize-path": { @@ -13432,35 +13367,6 @@ "node": ">=8" } }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "deprecated": "This package is no longer supported.", - "dev": true, - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, "node_modules/ospath": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", diff --git a/package.json b/package.json index 47c836c0b..065cae702 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "commons-api": "git+https://github.com/wielebenwir/commons-api.git", "cypress": "^15.14.0", "editorconfig": "^3.0.2", - "grunt": "^1.6.1", + "grunt": "^1.6.2", "grunt-babel": "^8.0.0", "grunt-cli": "^1.5.0", "grunt-contrib-clean": "^2.0.1", From a95a48b1e231df92e4650b9dbc0fbf8c83b0b036 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 09:53:32 +0200 Subject: [PATCH 009/148] npm(deps-dev): bump prettier from 3.8.1 to 3.8.3 (#2164) Bumps [prettier](https://github.com/prettier/prettier) from 3.8.1 to 3.8.3. - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/3.8.1...3.8.3) --- updated-dependencies: - dependency-name: prettier dependency-version: 3.8.3 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 932a4d962..e4fe101ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ "grunt-dart-sass": "^2.0.1", "matchdep": "^2.0.0", "medium-zoom": "^1.1.0", - "prettier": "^3.3.3", + "prettier": "^3.8.3", "sass": "^1.97.3", "vitepress": "^1.6.4" } @@ -13754,9 +13754,9 @@ } }, "node_modules/prettier": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", - "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", "dev": true, "license": "MIT", "bin": { diff --git a/package.json b/package.json index 065cae702..ee68585dd 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "medium-zoom": "^1.1.0", "sass": "^1.97.3", "vitepress": "^1.6.4", - "prettier": "^3.3.3" + "prettier": "^3.8.3" }, "scripts": { "start": "composer install --ignore-platform-reqs && npm install && npm run dist", From 535b18ab9b51eeca4357ea2a9e95d187416b17ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Apr 2026 07:54:35 +0000 Subject: [PATCH 010/148] npm(deps-dev): bump sass from 1.97.3 to 1.99.0 Bumps [sass](https://github.com/sass/dart-sass) from 1.97.3 to 1.99.0. - [Release notes](https://github.com/sass/dart-sass/releases) - [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md) - [Commits](https://github.com/sass/dart-sass/compare/1.97.3...1.99.0) --- updated-dependencies: - dependency-name: sass dependency-version: 1.99.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 19 ++++++++++--------- package.json | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index e4fe101ab..28a30a661 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,7 @@ "matchdep": "^2.0.0", "medium-zoom": "^1.1.0", "prettier": "^3.8.3", - "sass": "^1.97.3", + "sass": "^1.99.0", "vitepress": "^1.6.4" } }, @@ -10813,10 +10813,11 @@ } }, "node_modules/immutable": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.3.tgz", - "integrity": "sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==", - "dev": true + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", + "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", + "dev": true, + "license": "MIT" }, "node_modules/imurmurhash": { "version": "0.1.4", @@ -14329,14 +14330,14 @@ "dev": true }, "node_modules/sass": { - "version": "1.97.3", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.3.tgz", - "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==", + "version": "1.99.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.99.0.tgz", + "integrity": "sha512-kgW13M54DUB7IsIRM5LvJkNlpH+WhMpooUcaWGFARkF1Tc82v9mIWkCbCYf+MBvpIUBSeSOTilpZjEPr2VYE6Q==", "dev": true, "license": "MIT", "dependencies": { "chokidar": "^4.0.0", - "immutable": "^5.0.2", + "immutable": "^5.1.5", "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { diff --git a/package.json b/package.json index ee68585dd..29732559f 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "grunt-dart-sass": "^2.0.1", "matchdep": "^2.0.0", "medium-zoom": "^1.1.0", - "sass": "^1.97.3", + "sass": "^1.99.0", "vitepress": "^1.6.4", "prettier": "^3.8.3" }, From cce6fde67313dee6eed7282e213fbe84fa87c797 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Tue, 21 Apr 2026 17:18:03 +0200 Subject: [PATCH 011/148] unify test dates --- tests/php/API/AvailabilityRouteTest.php | 8 ++++++-- tests/php/API/CB_REST_Route_UnitTestCase.php | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/php/API/AvailabilityRouteTest.php b/tests/php/API/AvailabilityRouteTest.php index 475ee313f..3697d7396 100644 --- a/tests/php/API/AvailabilityRouteTest.php +++ b/tests/php/API/AvailabilityRouteTest.php @@ -43,11 +43,15 @@ public function testsAvailabilitySuccess() { $this->assertSame( 200, $response->get_status() ); $this->assertSame( 2, count( $response->get_data()->availability ) ); + $availabilityStart = new \DateTime( self::CURRENT_DATE ); + $availabilityEnd = new \DateTime( self::CURRENT_DATE ); + $availabilityEnd->modify( '23:59:59' ); + // Checks availability for the first day $this->assertEquals( $this->locationId, $response->get_data()->availability[0]->locationId ); $this->assertEquals( $this->itemId, $response->get_data()->availability[0]->itemId ); - $this->assertEquals( self::CURRENT_DATE . 'T00:00:00+00:00', $response->get_data()->availability[0]->start ); - $this->assertEquals( self::CURRENT_DATE . 'T23:59:59+00:00', $response->get_data()->availability[0]->end ); + $this->assertEquals( $availabilityStart->format( 'c' ), $response->get_data()->availability[0]->start ); + $this->assertEquals( $availabilityEnd->format( 'c' ), $response->get_data()->availability[0]->end ); ClockMock::reset(); } diff --git a/tests/php/API/CB_REST_Route_UnitTestCase.php b/tests/php/API/CB_REST_Route_UnitTestCase.php index 8292e463b..02ab5b103 100644 --- a/tests/php/API/CB_REST_Route_UnitTestCase.php +++ b/tests/php/API/CB_REST_Route_UnitTestCase.php @@ -3,6 +3,7 @@ namespace CommonsBooking\Tests\API; use CommonsBooking\Tests\CPTCreationTrait; +use CommonsBooking\Tests\Wordpress\CustomPostTypeTest; /** * Abstract test case which implicitly tests REST Routes @@ -12,7 +13,7 @@ class CB_REST_Route_UnitTestCase extends CB_REST_UnitTestCase { use CPTCreationTrait; - const CURRENT_DATE = '2021-05-21'; + const CURRENT_DATE = CustomPostTypeTest::CURRENT_DATE; protected $ENDPOINT; From 86ddb10b044539bb68dbd96cee0853cdd1dcf95b Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Tue, 21 Apr 2026 17:19:16 +0200 Subject: [PATCH 012/148] add test for gbfs discovery route --- tests/php/API/GBFS/DiscoveryRouteTest.php | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/tests/php/API/GBFS/DiscoveryRouteTest.php b/tests/php/API/GBFS/DiscoveryRouteTest.php index dea527f80..28a9cb075 100644 --- a/tests/php/API/GBFS/DiscoveryRouteTest.php +++ b/tests/php/API/GBFS/DiscoveryRouteTest.php @@ -4,10 +4,25 @@ use CommonsBooking\Tests\API\CB_REST_Route_UnitTestCase; -/** - * TODO: add result unit test - */ class DiscoveryRouteTest extends CB_REST_Route_UnitTestCase { protected $ENDPOINT = '/commonsbooking/v1/gbfs.json'; + + public function testRoute() { + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertNotEmpty( $data->feeds ); + $this->assertIsArray( $data->feeds ); + + $header = $response->get_data(); // the top level info that is always present + + $this->assertNotFalse( \DateTime::createFromFormat( \DateTime::ATOM, $header->last_updated ) ); + $this->assertIsInt( $header->ttl ); + $this->assertIsString( $header->version ); + + parent::testRoute(); + } } From b8cdf1f217af992cec92808056f5ed61d3ebf0a5 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Wed, 22 Apr 2026 14:14:05 +0200 Subject: [PATCH 013/148] replace StationStatusTest with StationStatusRouteTest --- tests/php/API/GBFS/StationStatusRouteTest.php | 127 +++++++++++++++++- tests/php/API/GBFS/StationStatusTest.php | 124 ----------------- 2 files changed, 124 insertions(+), 127 deletions(-) delete mode 100644 tests/php/API/GBFS/StationStatusTest.php diff --git a/tests/php/API/GBFS/StationStatusRouteTest.php b/tests/php/API/GBFS/StationStatusRouteTest.php index 12fb49807..498674365 100644 --- a/tests/php/API/GBFS/StationStatusRouteTest.php +++ b/tests/php/API/GBFS/StationStatusRouteTest.php @@ -3,11 +3,132 @@ namespace CommonsBooking\Tests\API\GBFS; use CommonsBooking\Tests\API\CB_REST_Route_UnitTestCase; +use CommonsBooking\Tests\Wordpress\CustomPostTypeTest; +use SlopeIt\ClockMock\ClockMock; -/** - * TODO: add result unit test - */ class StationStatusRouteTest extends CB_REST_Route_UnitTestCase { protected $ENDPOINT = '/commonsbooking/v1/station_status.json'; + public function testBasicStationStatus() { + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + + $this->assertSame( 200, $response->get_status() ); + + $data = $response->get_data()->data; + + $this->assertNotEmpty( $data->stations ); + $this->assertCount( 1, $data->stations ); + + $station = $data->stations[0]; + + $this->assertEquals( (string) $this->locationId, $station->station_id ); + $this->assertEquals( 1, $station->num_vehicles_available ); + $this->assertTrue( $station->is_installed ); + $this->assertTrue( $station->is_renting ); + $this->assertTrue( $station->is_returning ); + + $reported = new \DateTime( $station->last_reported ); + $now = new \DateTime( self::CURRENT_DATE ); + + $this->assertEqualsWithDelta( $now->getTimestamp(), $reported->getTimestamp(), 1.0 ); + } + + public function testStationStatus_whenBooked_isEmpty() { + $booking = $this->createConfirmedBookingStartingToday(); + + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + + $data = $response->get_data()->data; + $station = $data->stations[0]; + + $this->assertEquals( 0, $station->num_vehicles_available ); + } + + public function testStationStatus_afterTimeframeEnd_isEmpty() { + $future = new \DateTime( self::CURRENT_DATE ); + $future->modify( '+11 days' ); + ClockMock::freeze( $future ); + + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + + $data = $response->get_data()->data; + $station = $data->stations[0]; + + $this->assertEquals( 0, $station->num_vehicles_available ); + } + + public function testStationStatus_withBookingOffset() { + $otherLocationId = $this->createLocation( 'Other Location', ); + $otherItemId = $this->createItem( 'Other Item', ); + + $timeframeID = $this->createTimeframe( + $otherLocationId, + $otherItemId, + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ), + \CommonsBooking\Wordpress\CustomPostType\Timeframe::BOOKABLE_ID, + 'on', + 'd', + 0, + '8:00 AM', + '12:00 PM', + 'publish', + [], + '', + CustomPostTypeTest::USER_ID, + 3, + 30, + 2 + ); + + // with offset → unavailable + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + + $relevantStation = array_find( + $data->stations, + function ( $station ) use ( $otherLocationId ) { + return $station->station_id === (string) $otherLocationId; + } + ); + $this->assertEquals( 0, $relevantStation->num_vehicles_available ); + + // remove offset → available + update_post_meta( $timeframeID, \CommonsBooking\Model\Timeframe::META_BOOKING_START_DAY_OFFSET, 0 ); + + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + $relevantStation = array_find( + $data->stations, + function ( $station ) use ( $otherLocationId ) { + return $station->station_id === (string) $otherLocationId; + } + ); + $this->assertEquals( 1, $relevantStation->num_vehicles_available ); + } + + public function setUp(): void { + parent::setUp(); + + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + + $this->locationId = $this->createLocation( 'Testlocation', 'publish' ); + $this->itemId = $this->createItem( 'TestItem', 'publish' ); + + $this->timeframe = $this->createTimeframe( + $this->locationId, + $this->itemId, + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ) + ); + } + + public function tearDown(): void { + ClockMock::reset(); + parent::tearDown(); + } } diff --git a/tests/php/API/GBFS/StationStatusTest.php b/tests/php/API/GBFS/StationStatusTest.php deleted file mode 100644 index 9bac7d5f3..000000000 --- a/tests/php/API/GBFS/StationStatusTest.php +++ /dev/null @@ -1,124 +0,0 @@ -locationId ); - ClockMock::freeze( $currDate ); - $routeObject = new StationStatus(); - $spanningTimeframe = $this->createTimeframe( - $this->locationId, - $this->itemId, - strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), - strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ) - ); - $stationStatus = $routeObject->prepare_item_for_response( $locationObject, null )->get_data(); - $this->assertEquals( $this->locationId, $stationStatus->station_id ); - $this->assertEquals( 1, $stationStatus->num_vehicles_available ); - $this->assertTrue( $stationStatus->is_installed ); - $this->assertTrue( $stationStatus->is_renting ); - $this->assertTrue( $stationStatus->is_returning ); - $this->assertEquals( date( 'c' ), $stationStatus->last_reported ); - - // now let's book the current day and check, that the station is empty - $this->createConfirmedBookingStartingToday(); - $this->assertEquals( 0, $routeObject->prepare_item_for_response( $locationObject, null )->get_data()->num_vehicles_available ); - - // the timeframe has ended now, so the station should be empty - $currDate->modify( '+11 days' ); - ClockMock::freeze( $currDate ); - $this->assertEquals( 0, $routeObject->prepare_item_for_response( $locationObject, null )->get_data()->num_vehicles_available ); - - // very important for GBFS: when bookings are only allowed with a certain offset (time difference between booking and start of booking), the station should be empty - ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); - $otherLocationId = $this->createLocation( 'Other Location', 'publish' ); - $otherItemId = $this->createItem( 'Other Item', 'publish' ); - $timeframeID = $this->createTimeframe( - $otherLocationId, - $otherItemId, - strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), - strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ), - \CommonsBooking\Wordpress\CustomPostType\Timeframe::BOOKABLE_ID, - 'on', - 'd', - 0, - '8:00 AM', - '12:00 PM', - 'publish', - [], - '', - self::USER_ID, - 3, - 30, - 2 - ); - $this->assertEquals( 0, $routeObject->prepare_item_for_response( new Location( $otherLocationId ), null )->get_data()->num_vehicles_available ); - // remove the offset and the station should have the item - update_post_meta( $timeframeID, 'booking-startday-offset', 0 ); - $this->assertEquals( 1, $routeObject->prepare_item_for_response( new Location( $otherLocationId ), null )->get_data()->num_vehicles_available ); - } - - public function testPrepare_item_for_response_hourly() { - $currDate = new \DateTime( self::CURRENT_DATE ); - $currDate->setTime( 8, 0, 0 ); - $locationObject = new Location( $this->locationId ); - ClockMock::freeze( $currDate ); - $routeObject = new StationStatus(); - $hourlyTimeframe = $this->createTimeframe( - $this->locationId, - $this->itemId, - strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), - strtotime( '+2 days', strtotime( self::CURRENT_DATE ) ), - \CommonsBooking\Wordpress\CustomPostType\Timeframe::BOOKABLE_ID, - 'off', - 'd', - 1, - '8:00 AM', - '11:59 PM' - ); - $this->assertEquals( 1, $routeObject->prepare_item_for_response( $locationObject, null )->get_data()->num_vehicles_available ); - - // before 08:00AM the bike is not available - $currDate->setTime( 6, 0, 0 ); - ClockMock::freeze( $currDate ); - $this->assertEquals( 0, $routeObject->prepare_item_for_response( $locationObject, null )->get_data()->num_vehicles_available ); - - // now let's book two hours out of the timeframe and check that the station is empty for those two hours - $startBooking = new \DateTime( self::CURRENT_DATE ); - $startBooking->setTime( 10, 0, 0 ); - $endBooking = clone $startBooking; - $endBooking->setTime( 13, 0, 0 ); - $this->createBooking( - $this->locationId, - $this->itemId, - strtotime( '10:00 AM', strtotime( self::CURRENT_DATE ) ), - strtotime( '01:00 PM', strtotime( self::CURRENT_DATE ) ), - '10:00 AM', - '01:00 PM' - ); - ClockMock::freeze( $startBooking ); - $this->assertEquals( 0, $routeObject->prepare_item_for_response( $locationObject, null )->get_data()->num_vehicles_available ); - $startBooking->modify( '+1 hour' ); - ClockMock::freeze( $startBooking ); - $this->assertEquals( 0, $routeObject->prepare_item_for_response( $locationObject, null )->get_data()->num_vehicles_available ); - ClockMock::freeze( $endBooking ); - $this->assertEquals( 1, $routeObject->prepare_item_for_response( $locationObject, null )->get_data()->num_vehicles_available ); - } - - protected function setUp(): void { - parent::setUp(); - } - - protected function tearDown(): void { - parent::tearDown(); - } -} From 238aba2f32fde5ae5e5bf9740e386be0f6b079fe Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Wed, 22 Apr 2026 14:43:09 +0200 Subject: [PATCH 014/148] test compatible with all php version --- tests/php/API/GBFS/StationStatusRouteTest.php | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/tests/php/API/GBFS/StationStatusRouteTest.php b/tests/php/API/GBFS/StationStatusRouteTest.php index 498674365..d3dfad0ee 100644 --- a/tests/php/API/GBFS/StationStatusRouteTest.php +++ b/tests/php/API/GBFS/StationStatusRouteTest.php @@ -89,11 +89,13 @@ public function testStationStatus_withBookingOffset() { $response = rest_do_request( $request ); $data = $response->get_data()->data; - $relevantStation = array_find( - $data->stations, - function ( $station ) use ( $otherLocationId ) { - return $station->station_id === (string) $otherLocationId; - } + $relevantStation = current( + array_filter( + $data->stations, + function ( $station ) use ( $otherLocationId ) { + return $station->station_id === (string) $otherLocationId; + } + ) ); $this->assertEquals( 0, $relevantStation->num_vehicles_available ); @@ -102,11 +104,13 @@ function ( $station ) use ( $otherLocationId ) { $response = rest_do_request( $request ); $data = $response->get_data()->data; - $relevantStation = array_find( - $data->stations, - function ( $station ) use ( $otherLocationId ) { - return $station->station_id === (string) $otherLocationId; - } + $relevantStation = current( + array_filter( + $data->stations, + function ( $station ) use ( $otherLocationId ) { + return $station->station_id === (string) $otherLocationId; + } + ) ); $this->assertEquals( 1, $relevantStation->num_vehicles_available ); } From 56d5c87c59f5a106adaa66f4722f5030962c9e24 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 26 Apr 2026 15:52:45 +0000 Subject: [PATCH 015/148] npm(deps): bump vue from 3.5.30 to 3.5.33 Bumps [vue](https://github.com/vuejs/core) from 3.5.30 to 3.5.33. - [Release notes](https://github.com/vuejs/core/releases) - [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md) - [Commits](https://github.com/vuejs/core/compare/v3.5.30...v3.5.33) --- updated-dependencies: - dependency-name: vue dependency-version: 3.5.33 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 126 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 64 insertions(+), 64 deletions(-) diff --git a/package-lock.json b/package-lock.json index e4fe101ab..97c41c50a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "select2": "^4.0.13", "shufflejs": "^6.1.1", "spin.js": "^2.3.2", - "vue": "^3.5.30" + "vue": "^3.5.33" }, "devDependencies": { "@babel/preset-env": "^7.29.2", @@ -636,9 +636,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", "license": "MIT", "dependencies": { "@babel/types": "^7.29.0" @@ -5253,13 +5253,13 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.30.tgz", - "integrity": "sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.33.tgz", + "integrity": "sha512-3PZLQwFw4Za3TC8t0FvTy3wI16Kt+pmwcgNZca4Pj9iWL2E72a/gZlpBtAJvEdDMdCxdG/qq0C7PN0bsJuv0Rw==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@vue/shared": "3.5.30", + "@babel/parser": "^7.29.2", + "@vue/shared": "3.5.33", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" @@ -5278,40 +5278,40 @@ } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.30.tgz", - "integrity": "sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.33.tgz", + "integrity": "sha512-PXq0yrfCLzzL07rbXO4awtXY1Z06LG2eu6Adg3RJFa/j3Cii217XxxLXG22N330gw7GmALCY0Z8RgXEviwgpjA==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-core": "3.5.33", + "@vue/shared": "3.5.33" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.30.tgz", - "integrity": "sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.33.tgz", + "integrity": "sha512-UTUvRO9cY+rROrx/pvN9P5Z7FgA6QGfokUCfhQE4EnmUj3rVnK+CHI0LsEO1pg+I7//iRYMUfcNcCPe7tg0CoA==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@vue/compiler-core": "3.5.30", - "@vue/compiler-dom": "3.5.30", - "@vue/compiler-ssr": "3.5.30", - "@vue/shared": "3.5.30", + "@babel/parser": "^7.29.2", + "@vue/compiler-core": "3.5.33", + "@vue/compiler-dom": "3.5.33", + "@vue/compiler-ssr": "3.5.33", + "@vue/shared": "3.5.33", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", - "postcss": "^8.5.8", + "postcss": "^8.5.10", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.30.tgz", - "integrity": "sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.33.tgz", + "integrity": "sha512-IErjYdnj1qIupG5xxiVIYiiRvDhGWV4zuh/RCrwfYpuL+HWQzeU6lCk/nF9r7olWMnjKxCAkOctT2qFWFkzb1A==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-dom": "3.5.33", + "@vue/shared": "3.5.33" } }, "node_modules/@vue/devtools-api": { @@ -5348,53 +5348,53 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.30.tgz", - "integrity": "sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.33.tgz", + "integrity": "sha512-p8UfIqyIhb0rYGlSgSBV+lPhF2iUSBcRy7enhTmPqKWadHy9kcOFYF1AejYBP9P+avnd3OBbD49DU4pLWX/94A==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.30" + "@vue/shared": "3.5.33" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.30.tgz", - "integrity": "sha512-e0Z+8PQsUTdwV8TtEsLzUM7SzC7lQwYKePydb7K2ZnmS6jjND+WJXkmmfh/swYzRyfP1EY3fpdesyYoymCzYfg==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.33.tgz", + "integrity": "sha512-UpFF45RI9//a7rvq7RdOQblb4tup7hHG9QsmIrxkFQLzQ7R8/iNQ5LE15NhLZ1/WcHMU2b47u6P33CPUelHyIQ==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/reactivity": "3.5.33", + "@vue/shared": "3.5.33" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.30.tgz", - "integrity": "sha512-2UIGakjU4WSQ0T4iwDEW0W7vQj6n7AFn7taqZ9Cvm0Q/RA2FFOziLESrDL4GmtI1wV3jXg5nMoJSYO66egDUBw==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.33.tgz", + "integrity": "sha512-IOxMsAOwquhfITgmOgaPYl7/j8gKUxUFoflRc+u4LxyD3+783xne8vNta1PONVCvCV9A0w7hkyEepINDqfO0tw==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.30", - "@vue/runtime-core": "3.5.30", - "@vue/shared": "3.5.30", + "@vue/reactivity": "3.5.33", + "@vue/runtime-core": "3.5.33", + "@vue/shared": "3.5.33", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.30.tgz", - "integrity": "sha512-v+R34icapydRwbZRD0sXwtHqrQJv38JuMB4JxbOxd8NEpGLny7cncMp53W9UH/zo4j8eDHjQ1dEJXwzFQknjtQ==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.33.tgz", + "integrity": "sha512-0xylq/8/h44lVG0pZFknv1XIdEgymq2E9n59uTWJBG+dIgiT0TMCSsxrN7nO16Z0MU0MPjFcguBbZV8Itk52Hw==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-ssr": "3.5.33", + "@vue/shared": "3.5.33" }, "peerDependencies": { - "vue": "3.5.30" + "vue": "3.5.33" } }, "node_modules/@vue/shared": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.30.tgz", - "integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.33.tgz", + "integrity": "sha512-5vR2QIlmaLG77Ygd4pMP6+SGQ5yox9VhtnbDWTy9DzMzdmeLxZ1QqxrywEZ9sa1AVubfIJyaCG3ytyWU81ufcQ==", "license": "MIT" }, "node_modules/@vueuse/core": { @@ -13715,9 +13715,9 @@ } }, "node_modules/postcss": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", - "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "version": "8.5.12", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.12.tgz", + "integrity": "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==", "funding": [ { "type": "opencollective", @@ -18364,16 +18364,16 @@ } }, "node_modules/vue": { - "version": "3.5.30", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.30.tgz", - "integrity": "sha512-hTHLc6VNZyzzEH/l7PFGjpcTvUgiaPK5mdLkbjrTeWSRcEfxFrv56g/XckIYlE9ckuobsdwqd5mk2g1sBkMewg==", + "version": "3.5.33", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.33.tgz", + "integrity": "sha512-1AgChhx5w3ALgT4oK3acm2Es/7jyZhWSVUfs3rOBlGQC0rjEDkS7G4lWlJJGGNQD+BV3reCwbQrOe1mPNwKHBQ==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.30", - "@vue/compiler-sfc": "3.5.30", - "@vue/runtime-dom": "3.5.30", - "@vue/server-renderer": "3.5.30", - "@vue/shared": "3.5.30" + "@vue/compiler-dom": "3.5.33", + "@vue/compiler-sfc": "3.5.33", + "@vue/runtime-dom": "3.5.33", + "@vue/server-renderer": "3.5.33", + "@vue/shared": "3.5.33" }, "peerDependencies": { "typescript": "*" diff --git a/package.json b/package.json index ee68585dd..ee0fca3ad 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,6 @@ "select2": "^4.0.13", "shufflejs": "^6.1.1", "spin.js": "^2.3.2", - "vue": "^3.5.30" + "vue": "^3.5.33" } } From 8a5f43015885e8aca429bf16dd948dd54a29a296 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Mon, 27 Apr 2026 14:45:30 +0200 Subject: [PATCH 016/148] add unit tests for GBFS routes station_information and system_information --- .../API/GBFS/StationInformationRouteTest.php | 56 ++++++++++++++++++- .../API/GBFS/SystemInformationRouteTest.php | 20 +++++++ 2 files changed, 73 insertions(+), 3 deletions(-) diff --git a/tests/php/API/GBFS/StationInformationRouteTest.php b/tests/php/API/GBFS/StationInformationRouteTest.php index fd9bd65d8..dfd211d8c 100644 --- a/tests/php/API/GBFS/StationInformationRouteTest.php +++ b/tests/php/API/GBFS/StationInformationRouteTest.php @@ -3,11 +3,61 @@ namespace CommonsBooking\Tests\API\GBFS; use CommonsBooking\Tests\API\CB_REST_Route_UnitTestCase; +use CommonsBooking\Tests\Helper\GeoHelperTest; +use WP_REST_Request; -/** - * TODO: add result unit test - */ class StationInformationRouteTest extends CB_REST_Route_UnitTestCase { protected $ENDPOINT = '/commonsbooking/v1/station_information.json'; + + public function testBasicStationInformation_withLatLonMeta() { + update_post_meta( $this->locationId, 'geo_latitude', '50.123' ); + update_post_meta( $this->locationId, 'geo_longitude', '8.123' ); + + $request = new WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + + $this->assertSame( 200, $response->get_status() ); + + $data = $response->get_data()->data; + $this->assertNotEmpty( $data->stations ); + $this->assertCount( 1, $data->stations ); + + $station = $data->stations[0]; + + $this->assertEquals( (string) $this->locationId, $station->station_id ); + $this->assertNotEmpty( $station->name ); + $this->assertNotEmpty( $station->rental_uris->web ); + + $this->assertEquals( 50.123, $station->lat ); + $this->assertEquals( 8.123, $station->lon ); + } + + // no gps data and no address defined, skip location + public function testStationInformation_geocodingNonExistent() { + delete_post_meta( $this->locationId, 'geo_latitude' ); + delete_post_meta( $this->locationId, 'geo_longitude' ); + + $mockedLocationCoordinates = GeoHelperTest::mockedLocation()->getCoordinates(); + + $request = new WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + + $data = $response->get_data()->data; + $this->assertEmpty( $data->stations ); + } + + public function setUp(): void { + parent::setUp(); + + $this->locationId = $this->createLocation( 'Test Location', 'publish' ); + $this->itemId = $this->createItem( 'TestItem', 'publish' ); + + $this->timeframe = $this->createTimeframe( + $this->locationId, + $this->itemId, + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ) + ); + } } diff --git a/tests/php/API/GBFS/SystemInformationRouteTest.php b/tests/php/API/GBFS/SystemInformationRouteTest.php index 0dc4b8b26..0988126c7 100644 --- a/tests/php/API/GBFS/SystemInformationRouteTest.php +++ b/tests/php/API/GBFS/SystemInformationRouteTest.php @@ -10,4 +10,24 @@ class SystemInformationRouteTest extends CB_REST_Route_UnitTestCase { protected $ENDPOINT = '/commonsbooking/v1/system_information.json'; + + public function testRoute() { + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + + $data = $response->get_data()->data; + $this->assertNotEmpty( $data->name ); + $this->assertNotEmpty( $data->system_id ); + + $header = $response->get_data(); // the top level info that is always present + + $this->assertNotFalse( \DateTime::createFromFormat( \DateTime::ATOM, $header->last_updated ) ); + $this->assertIsInt( $header->ttl ); + $this->assertIsString( $header->version ); + parent::testRoute(); + } + + public function setUp(): void { + parent::setUp(); + } } From 08956ec599ad37279a09b23199d9c329f0cee9ef Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 09:30:41 +0200 Subject: [PATCH 017/148] npm(deps-dev): bump cypress from 15.14.0 to 15.14.1 (#2172) Bumps [cypress](https://github.com/cypress-io/cypress) from 15.14.0 to 15.14.1. - [Release notes](https://github.com/cypress-io/cypress/releases) - [Changelog](https://github.com/cypress-io/cypress/blob/develop/CHANGELOG.md) - [Commits](https://github.com/cypress-io/cypress/compare/v15.14.0...v15.14.1) --- updated-dependencies: - dependency-name: cypress dependency-version: 15.14.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index e4fe101ab..0e6cf43ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,7 @@ "@babel/preset-env": "^7.29.2", "@wordpress/env": "^11.4.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", - "cypress": "^15.14.0", + "cypress": "^15.14.1", "editorconfig": "^3.0.2", "grunt": "^1.6.2", "grunt-babel": "^8.0.0", @@ -7706,9 +7706,9 @@ "license": "MIT" }, "node_modules/cypress": { - "version": "15.14.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.14.0.tgz", - "integrity": "sha512-AHt9YLKVl6uOFfXsLM3+LSZFwsx36BJRyFv4CjsqcRgr+V9kir0IPVRZUgqZVNudRalx771A1c4yR3DmXvSiBQ==", + "version": "15.14.1", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.14.1.tgz", + "integrity": "sha512-AkuiHNSnmm0a+h/horcvbjmY6dWpCe1Ebp1R0LjMP5I6pjMaNA50Mw1YP/d07pLHJ/sV8FZoGecUWFCJ/Nifpw==", "dev": true, "hasInstallScript": true, "license": "MIT", diff --git a/package.json b/package.json index ee68585dd..15dcb66b6 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "@babel/preset-env": "^7.29.2", "@wordpress/env": "^11.4.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", - "cypress": "^15.14.0", + "cypress": "^15.14.1", "editorconfig": "^3.0.2", "grunt": "^1.6.2", "grunt-babel": "^8.0.0", From 86f640d66fc11faee8118eefaf42520f8deff17e Mon Sep 17 00:00:00 2001 From: Stefan Bomsdorf Date: Fri, 1 May 2026 09:25:24 +0200 Subject: [PATCH 018/148] Restructured FAQs as per #2047 and reformulated headers that were not a question before for consistency. Co-authored-by: Copilot --- .../faq/avoid-spam-registrations.md | 10 +- docs/de/documentation/faq/block-users.md | 13 ++ .../faq/booking-comment-emails.md | 8 +- .../faq/booking-through-closed-days.md | 9 + .../faq/increase-items-per-page.md | 13 ++ docs/de/documentation/faq/index.md | 177 ++++++++++++------ docs/de/documentation/faq/lock-codes-email.md | 16 +- .../faq/organise-article-page.md | 14 +- .../documentation/faq/problems-and-answers.md | 74 ++++++-- docs/de/documentation/faq/site-slow.md | 6 +- .../faq/avoid-spam-registrations.md | 8 +- docs/en/documentation/faq/block-users.md | 13 ++ .../faq/booking-comment-emails.md | 4 + .../faq/booking-through-closed-days.md | 9 + .../faq/increase-items-per-page.md | 13 ++ docs/en/documentation/faq/index.md | 134 ++++++++++--- docs/en/documentation/faq/lock-codes-email.md | 5 +- .../faq/organise-article-page.md | 4 +- .../documentation/faq/problems-and-answers.md | 57 +++++- docs/en/documentation/faq/site-slow.md | 4 + 20 files changed, 451 insertions(+), 140 deletions(-) create mode 100644 docs/de/documentation/faq/block-users.md create mode 100644 docs/de/documentation/faq/booking-through-closed-days.md create mode 100644 docs/de/documentation/faq/increase-items-per-page.md create mode 100644 docs/en/documentation/faq/block-users.md create mode 100644 docs/en/documentation/faq/booking-through-closed-days.md create mode 100644 docs/en/documentation/faq/increase-items-per-page.md diff --git a/docs/de/documentation/faq/avoid-spam-registrations.md b/docs/de/documentation/faq/avoid-spam-registrations.md index 475a5f90f..01246ba26 100644 --- a/docs/de/documentation/faq/avoid-spam-registrations.md +++ b/docs/de/documentation/faq/avoid-spam-registrations.md @@ -1,9 +1,13 @@ -# Wie verhindere ich Spam Registrierungen +# Wie verhindere ich Spam-Registrierungen? +## Wie verhindere ich Spam-Registrierungen? + +::: details Antwort anzeigen Dafür gibt es verschiedene Möglichkeiten (Vorschläge aus der Community): -* Ein HoneyPot lenkt Bots ab, ohne Menschen zu nerven: https://wordpress.org/plugins/honeypot/ +* Ein HoneyPot lenkt Bots ab, ohne Menschen zu nerven: [Honeypot Plugin](https://wordpress.org/plugins/honeypot/) * "Ich hatte mal für **UltimateMember ein winziges Plugin geschrieben mit dem man einfach einen Text eingeben muss um sich zu registrieren**. Barrierearm und hält alle Bots ab: [Download von Github](https://github.com/hansmorb/um-captchaquiz/raw/refs/heads/master/um-captchaquiz.zip). Dazu einfach eine Textbox erstellen und den Metaschlüssel in den Plugin Einstellungen eintragen." -* "Wir nutzen Hcaptcha für wordpress. Nach der installation in den Einstellungen des Plugins die von euch genutzte Registrierung (z.B. UltraMember auswählen, standardmäßig sollte die WordPress-eigene Registrierung gewählt werden). Für die Nutzung muss ein Hcaptcha Account erstellt werden. Sie werben mit Privacy-First und das keine Nutzerdaten verkauft werden. Ich selber habe das nicht geprüft." — [Download aus dem Plugin-Verzeichnis](https://wordpress.org/plugins/hcaptcha-for-forms-and-more) +* "Wir nutzen Hcaptcha für wordpress. Nach der Installation in den Einstellungen des Plugins die von euch genutzte Registrierung (z.B. UltimateMember) auswählen. Für die Nutzung muss ein Hcaptcha Account erstellt werden. Sie werben mit Privacy-First und das keine Nutzerdaten verkauft werden. Ich selber habe das nicht geprüft." — [Download aus dem Plugin-Verzeichnis](https://wordpress.org/plugins/hcaptcha-for-forms-and-more) +::: diff --git a/docs/de/documentation/faq/block-users.md b/docs/de/documentation/faq/block-users.md new file mode 100644 index 000000000..75a5cd2d0 --- /dev/null +++ b/docs/de/documentation/faq/block-users.md @@ -0,0 +1,13 @@ +# Wie sperre ich einzelne Nutzer vorübergehend? + +## Wie sperre ich einzelne Nutzer vorübergehend? + +::: details Antwort anzeigen +Möchtest du Nutzende vorübergehend für einen bestimmten Zeitraum sperren, weil diese z.B. die Ausleihe übermäßig nutzen oder gegen Ausleihbedingungen verstoßen? + +Wir empfehlen, ein dediziertes WordPress-Plugin zum Blockieren von Nutzenden zu verwenden. Wenn deine Nutzenden auf der Seite sowieso nichts anderes tun können als buchen, ist das auch die einfachste Lösung. + +Das Plugin [User Blocker](https://wordpress.org/plugins/user-blocker/) wurde getestet und funktioniert problemlos, auch mit einer Zeitschaltfunktion. Es gibt weitere Plugins mit dieser Funktionalität. + +Das Blockieren bestimmter Benutzergruppen ist kein eingebautes Feature von CommonsBooking und wird wahrscheinlich auch in naher Zukunft nicht kommen, da es bereits WordPress-Plugins gibt, die genau das abdecken. +::: diff --git a/docs/de/documentation/faq/booking-comment-emails.md b/docs/de/documentation/faq/booking-comment-emails.md index 6a80d0592..d5254e7f2 100644 --- a/docs/de/documentation/faq/booking-comment-emails.md +++ b/docs/de/documentation/faq/booking-comment-emails.md @@ -1,5 +1,7 @@ -# Wie bekomme ich den Buchungskommentar auf die Seite und in die Email? +# Wie bekomme ich den Buchungskommentar auf die Seite und in die Email? -In den Einstellungen kannst du die Buchungskommentare aktivieren. In den email -Vorlagen musst du dann folgenden Code einfügen: `{{booking:returnComment}}` +## Wie bekomme ich den Buchungskommentar auf die Seite und in die Email? +::: details Antwort anzeigen +In den Einstellungen kannst du die Buchungskommentare aktivieren. In den E-Mail-Vorlagen musst du dann folgenden Code einfügen: `{{booking:returnComment}}` +::: diff --git a/docs/de/documentation/faq/booking-through-closed-days.md b/docs/de/documentation/faq/booking-through-closed-days.md new file mode 100644 index 000000000..3c708f602 --- /dev/null +++ b/docs/de/documentation/faq/booking-through-closed-days.md @@ -0,0 +1,9 @@ +# Wie erlaube ich Buchungen über geschlossene Tage hinweg? + +## Wie erlaube ich Buchungen über geschlossene Tage hinweg? + +::: details Antwort anzeigen +Wenn du deinen Nutzenden ermöglichen möchtest, einen Artikel über geschlossene Tage hinweg zu buchen (z.B. über das Wochenende, wenn die Station geschlossen ist), kannst du das in den Standort-Einstellungen konfigurieren. + +Ausführliche Informationen findest du unter [Standorte anlegen](../first-steps/create-location). +::: diff --git a/docs/de/documentation/faq/increase-items-per-page.md b/docs/de/documentation/faq/increase-items-per-page.md new file mode 100644 index 000000000..211db1fb3 --- /dev/null +++ b/docs/de/documentation/faq/increase-items-per-page.md @@ -0,0 +1,13 @@ +# Wie erhöhe ich die Anzahl der Artikel in der cb_items-Liste? + +## Wie erhöhe ich die Anzahl der Artikel in der cb_items-Liste? + +::: details Antwort anzeigen +Die Anzahl der Artikel pro Seite wird über die globalen WordPress-Leseeinstellungen übernommen. + +So änderst du sie: + +1. Als WordPress-Administrator einloggen +2. **Einstellungen → Lesen** aufrufen +3. Den Wert bei **Blogseiten zeigen maximal** anpassen +::: diff --git a/docs/de/documentation/faq/index.md b/docs/de/documentation/faq/index.md index 973d42c8c..306fa8089 100644 --- a/docs/de/documentation/faq/index.md +++ b/docs/de/documentation/faq/index.md @@ -1,105 +1,164 @@ -# Häufige Fragen (FAQ) +# Häufige Fragen (FAQ) +## Wie bekomme ich den Buchungskommentar auf die Seite und in die Email? -### Artikel +::: details Antwort anzeigen +In den Einstellungen kannst du die Buchungskommentare aktivieren. In den E-Mail-Vorlagen musst du dann folgenden Code einfügen: `{{booking:returnComment}}` +::: + +## Wie kann ich die Artikeldetailseite übersichtlicher gestalten? + +::: details Antwort anzeigen +Lange Artikelseiten bedeuten, dass Menschen lange bis zum Buchungskalender scrollen müssen. + +Hier empfiehlt sich ein Plugin wie [Show-Hide/Collapse-Expand](https://de.wordpress.org/plugins/show-hidecollapse-expand) zu nutzen, mit dem Informationen eingeklappt werden können. + +![](/img/item-collapse.png) +::: + +## Meine Seite ist sehr langsam – was kann ich tun? + +:::: details Antwort anzeigen +Wenn deine CommonsBooking Seite sehr langsam ist, kann das verschiedene Gründe haben. +Wir nutzen eine Technologie namens Caching, mit der wir häufig gestellte Anfragen in einem Zwischenspeicher +zurückhalten, um Serverkapazitäten einzusparen. + +Das Caching kann unter Umständen nicht funktionieren, wenn: + + * [WP_DEBUG](https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/) aktiviert ist, dafür musst du deine wp-config.php bearbeiten + * Der Ordner /tmp/ auf deinem Server nicht beschreibbar ist. Falls dies der Fall sein sollte, dann kontaktiere bitte deinen Webhoster und bitte ihn darum den Ordner beschreibbar zu machen. + * Falls das nicht möglich sein sollte, kannst du in den CommonsBooking Einstellungen unter "Erweiterte Optionen" den Pfad für den Dateisystem-Cache einstellen. Bitte frage bei deinem Webhoster nach, welche Ordner auf dem Server für temporäre Dateien verfügbar sind. + * Falls das auch nicht möglich sein sollte: Gehe zu deiner [Webseiten-Info](https://wordpress.org/documentation/article/site-health-screen/) unter (http://DEINE-URL/wp-admin/site-health.php?tab=debug). + Dort findest du unter **Verzeichnisse** den Pfad deines WordPress-Verzeichnisses. Wähle alternativ einen Ordner im Format `DEIN_VERZEICHNIS/symfony` als Cache-Ziel. + :::danger Achtung + Dies kann dazu führen, dass dein WordPress-Verzeichnis sehr groß wird. + ::: + +Alternativ kannst du auch [REDIS](https://redis.io) auf deinem Server installieren und den Cache durch REDIS verwalten lassen. +Da REDIS den Cache im RAM speichert, statt im Dateisystem, ist das meistens etwas schneller. +:::: + +## Wie kann ich Konfigurationsprobleme debuggen? + +:::: details Antwort anzeigen +:::warning Technische Expertise nötig! +::: + +Mit dem Plugin `query-monitor` kannst du Anfragen deiner Seite live überwachen. Damit ist es z.B. möglich einen +falsch konfigurierten Cache schnell zu identifizieren. +:::: + +## Wie füge ich Zahlenschloss-Codes in E-Mails ein? + +::: details Antwort anzeigen +Eine häufige Frage ist, ob Codes für Zahlenschlösser an Artikeln oder Standorten hinzugefügt werden können, um sie in den versendeten E-Mails anzuzeigen. + +Das funktioniert über sog. Meta-Felder, welche Artikel und Standort zugewiesen werden. Diese Felder können dann auch in den E-Mail-Templates verwendet werden. + +Der Artikel [Template-Tags](../administration/template-tags#eigene-metafelder-fur-standorte-und-artikel-verwenden) der Dokumentation enthält eine ausführliche Anleitung. +::: - * [ Wie bekomme ich den Buchungskommentar auf die Seite und in die Email? ](booking-comment-emails) - * [ Wie kann ich die Artikeldetailseite übersichtlicher gestalten? ](organise-article-page) - * [ Die Seite ist sehr langsam ](site-slow) - * [ Wie füge ich Zahlenschloss-Codes in E-Mails ein? ](lock-codes-email) +## Wie sperre ich einzelne Nutzer vorübergehend? +::: details Antwort anzeigen +Möchtest du Nutzende vorübergehend für einen bestimmten Zeitraum sperren, weil diese z.B. die Ausleihe üdermäßig nutzen oder gegen Ausleihbedingungen verstoßen? -## Ich möchte einzelne Nutzer vorübergehend sperren +Wir empfehlen, ein dediziertes WordPress-Plugin zum Blockieren von Nutzenden zu verwenden. Wenn deine Nutzenden auf der Seite sowieso nichts anderes tun können als buchen, ist das auch die einfachste Lösung. -Ihr möchtet Nutzende vorübergehend für einen bestimmten Zeitraum sperren, weil diese z.B. die Ausleihe übermäßig nutzen oder gegen Ausleihbedingungen verstoßen? +Das Plugin [User Blocker](https://wordpress.org/plugins/user-blocker/) wurde getestet und funktioniert problemlos, auch mit einer Zeitschaltfunktion. Es gibt weitere Plugins mit dieser Funktionalität. -Ich würde euch dazu raten mit einem entsprechenden Plugin zum Blockieren von Nutzenden für einen bestimmten Zeitraum einfach den gesamten Login zu blockieren. Da gibt es auch schon einige Plugins dafür. Wenn eure Nutzenden sowieso nichts anderes auf der Seite machen können als Räder zu buchen erscheint mir das auch sinnvoll es auf diese Art und Weise zu machen. +Das Blockieren bestimmter Benutzergruppen ist kein eingebautes Feature von CommonsBooking und wird wahrscheinlich auch in naher Zukunft nicht kommen, da es bereits WordPress-Plugins gibt, die genau das abdecken. +::: + +## Wie erlaube ich Buchungen über geschlossene Tage hinweg? + +::: details Antwort anzeigen +Wenn du deinen Nutzenden ermöglichen möchtest, einen Artikel über geschlossene Tage hinweg zu buchen (z.B. über das Wochenende, wenn die Station geschlossen ist), kannst du das in den Standort-Einstellungen konfigurieren. + +Ausführliche Informationen findest du unter [Standorte anlegen](../first-steps/create-location). +::: -Ich habe nur kurz bei mir mal das Plugin https://wordpress.org/plugins/user-blocker/ ausprobiert und das hat problemlos funktioniert, auch mit einer Zeitschaltfunktion. Das ist aber nicht das einzige Plugin, was diese Funktion hat. +## Wie erhöhe ich die Anzahl der Artikel in der cb_items-Liste? -Das Blockieren bestimmter Benutzergruppen ist kein Feature in CommonsBooking und wird wahrscheinlich auch so bald nicht als Feature kommen, da es schon einige Plugins gibt die genau das erledigen. +::: details Antwort anzeigen +Die Anzahl der Artikel pro Seite wird über die globalen WordPress-Leseeinstellungen übernommen. -## Überbuchbare Tage erlauben / Buchung übers Wochenende +So änderst du sie: -Wenn ihr euren Nutzenden ermöglichen wollt, den Artikel z.B. über das Wochenende zu buchen, könnt ihr diese Einstellung in den Standort-Einstellungen vornehmen. +1. Als WordPress-Administrator einloggen +2. **Einstellungen -> Lesen** aufrufen +3. Den Wert bei **Blogseiten zeigen maximal** anpassen +::: -Infos dazu unter: https://commonsbooking.org/documentation/first-steps/create-location/ +## Wie verhindere ich Spam-Registrierungen? -## Anzahl der Artikel in der cb_items Liste erhöhen +::: details Antwort anzeigen +Dafür gibt es verschiedene Möglichkeiten (Vorschläge aus der Community): -Die Anzahl der Artikel pro Seite wird über die globalen Einstellungen von Wordpress übernommen. +* Ein HoneyPot lenkt Bots ab, ohne Menschen zu nerven: [Honeypot Plugin](https://wordpress.org/plugins/honeypot/) -Diese globale Einstellungen können hier geändert werden: +* "Ich hatte mal für **UltimateMember ein winziges Plugin geschrieben mit dem man einfach einen Text eingeben muss um sich zu registrieren**. Barrierearm und hält alle Bots ab: [Download von Github](https://github.com/hansmorb/um-captchaquiz/raw/refs/heads/master/um-captchaquiz.zip). Dazu einfach eine Textbox erstellen und den Metaschlüssel in den Plugin Einstellungen eintragen." -Als Wordpress Administrator einlogge: +* "Wir nutzen Hcaptcha für wordpress. Nach der Installation in den Einstellungen des Plugins die von euch genutzte Registrierung (z.B. UltimateMember) auswählen. Für die Nutzung muss ein Hcaptcha Account erstellt werden. Sie werben mit Privacy-First und das keine Nutzerdaten verkauft werden. Ich selber habe das nicht geprüft." - [Download aus dem Plugin-Verzeichnis](https://wordpress.org/plugins/hcaptcha-for-forms-and-more) +::: -Einstellungen -> Lesen -> Blogseiten zeigen maximal +## Plugin- und Theme-Inkompatibilitäten -## Fehlerhafte Anzeige des Kalender-Widget im Admin-Bereich +### Lightstart -Treten Probleme bei der Anzeige des Kalenders im Admin-Bereich der Buchungen -auf (sog. Admin-Backend), siehe das folgende Bild rechts unten, kann eine -mögliche Lösung sein, das [ Plugin "Lightstart" (wp-maintenance-mode) ](https://wordpress.org/plugins/wp-maintenance-mode) zu deaktivieren oder zu -entfernen und neu zu installieren. Das Problem ist eine Inkompatibilität von -Lightstart mit CommonsBooking und kein Fehler im Code von CommonsBooking. Das -Problem tritt nicht mehr auf, wenn eine Neuinstallation von Lightstart -vorgenommen wurde. Mehr dazu auf [ Github im CommonsBooking Quellcode-Repository ](https://github.com/wielebenwir/commonsbooking/issues/1646). +::: details Antwort anzeigen +Treten Probleme bei der Anzeige des Kalenders im Admin-Bereich der Buchungen auf (sog. Admin-Backend), kann eine mögliche Lösung sein, das [Plugin "Lightstart" (wp-maintenance-mode)](https://wordpress.org/plugins/wp-maintenance-mode) zu deaktivieren oder zu entfernen und neu zu installieren. Das Problem ist eine Inkompatibilität von Lightstart mit CommonsBooking und kein Fehler im Code von CommonsBooking. Das Problem tritt nicht mehr auf, wenn eine Neuinstallation von Lightstart vorgenommen wurde. Mehr dazu auf [Github im CommonsBooking Quellcode-Repository](https://github.com/wielebenwir/commonsbooking/issues/1646). ![](/img/backend-booking-list-bug.png) +::: + +### GridBulletin + +::: details Antwort anzeigen +In der letzten Version von [GridBulletin](https://wordpress.org/themes/gridbulletin) kommt es zu einer Inkompatibilität mit CommonsBooking. Probleme tauchen auf, wenn der Footer aktiviert ist. Konkrete Probleme sind z.B. das Fehlen des Buchungs-Kalenders auf der Artikelseite. Aus technischer Sicht liegt es daran, dass die nötigen Javascript-Quellen von CommonsBooking nicht ausgeliefert werden. Der Grund innerhalb des GridBulletin Themes oder eine Lösung konnte bisher nicht gefunden werden. +::: -## Inkompatibles Plugin All-in-one-Event Plugins +### All-in-one-Event +:::: details Antwort anzeigen :::info Behoben seit 2.7.2 (06.2022) Für Experten siehe [Issue 675](https://github.com/wielebenwir/commonsbooking/issues/675) ::: -Leider kommt es bei der gleichzeitigen Nutzung des Plugins "All-in-one-Event" zu Fehlern, sodass Seiten, die von CommonsBooking erzeugt werden nicht angezeigt werden. +Leider kommt es bei der gleichzeitigen Nutzung des Plugins "All-in-one-Event" zu Fehlern, sodass Seiten, die von CommonsBooking erzeugt werden, nicht angezeigt werden. Die Ursache ist leider auf eine schlechte Programmierung des All-in-one-Event-Plugins zurückzuführen, welches sich nicht an die Wordpress-Standards hält und so tief in Wordpress eingreift, dass es die Programmlogik von CommonsBooking quasi überschreibt. Wir haben einiges versucht, um eine parallele Nutzung zu ermöglichen, leider aber bisher keine Lösung gefunden. Wenn ihr das Problem auch habt, schreibt gerne direkt an den Support des Plugins, vielleicht passen sie ihr Plugin doch noch irgendwann an. +:::: -## Inkompatibles Plugin REDIS Object Cache - -Im Zusammenhang mit dem [Cache](../advanced-functionality/) gab -es in der Vergangenheit bereits Probleme mit anderen Wordpress-Plugins wie -z.B. 'REDIS Object Cache'. Aus diesem Grund raten wir von der Nutzung solcher -Plugins ab. +### REDIS Object Cache -Deshalb sollten die von CommonsBooking generierten Seiten von der Optimierung durch Dritt-Plugins ausgenommen werden. -CommonsBooking verwendet ein eigenes Caching. +::: details Antwort anzeigen +Im Zusammenhang mit dem [Cache](../advanced-functionality/) gab es in der Vergangenheit bereits Probleme mit anderen Wordpress-Plugins wie z.B. 'REDIS Object Cache'. Aus diesem Grund raten wir von der Nutzung solcher Plugins ab. +Die von CommonsBooking generierten Seiten sollten von der Optimierung durch Dritt-Plugins ausgenommen werden. CommonsBooking verwendet ein eigenes Caching. +::: -## Inkompatibles Plugin Ultimate Member +### Ultimate Member -Wenn ihr das Plugin Ultimate Member benutzt und die Benutzerrolle "CommonsBooking Manager" nutzen möchtet, müsst ihr in Ultimate Member für die Rolle cb_manager noch ein Häkchen setzen, um diese für den AP-Admin-Zugang zu aktivieren. +::: details Antwort anzeigen +Wenn ihr das Plugin Ultimate Member benutzt und die Benutzerrolle "CommonsBooking Manager" nutzen möchtet, müsst ihr in Ultimate Member für die Rolle `cb_manager` noch ein Häkchen setzen, um diese für den Admin-Zugang zu aktivieren. +::: -## Inkompatible Plugins: Autoptimize / Caching +### Autoptimize / Caching-Plugins -Optimierungs-Plugins oder weitere Caching-Plugins können dazu führen, dass CommonsBooking nicht alle Seiten anzeigen kann. +:::: details Antwort anzeigen +Optimierungs-Plugins oder weitere Caching-Plugins können dazu führen, dass CommonsBooking nicht alle Seiten korrekt anzeigen kann. -Nicht vollständige Liste: +Betroffene Plugins (nicht vollständig): * Autoptimize -Deshalb sollten die von CommonsBooking generierten Seiten von der Optimierung durch Dritt-Plugins ausgenommen werden. -CommonsBooking verwendet ein eigenes Caching. +Die von CommonsBooking generierten Seiten sollten von der Optimierung durch Dritt-Plugins ausgenommen werden. CommonsBooking verwendet ein eigenes Caching. -::: info Hast du ein Problem festgestellt? +:::info Hast du ein Problem festgestellt? Dann trage die Inkompatibilität hier ein! ::: - - -## Inkompatibles Theme Gridbulletin - -In der letzten Version von [ GridBulletin ](https://wordpress.org/themes/gridbulletin) kommt es zu einer -Inkompatibilität mit CommonsBooking. Probleme tauchen auf, wenn der Footer -aktiviert ist. Konkrete Probleme sind z.B. das Fehlen des Buchungs-Kalenders -auf der Artikelseite. Aus technischer Sicht liegt es daran, dass die nötigen -Javascript-Quellen von CommonsBooking nicht ausgeliefert werden. Der Grund -innerhalb des GridBulletin Themes oder eine Lösung konnte bisher nicht -gefunden werden. - - - +:::: diff --git a/docs/de/documentation/faq/lock-codes-email.md b/docs/de/documentation/faq/lock-codes-email.md index 1d000040d..0fda9b002 100644 --- a/docs/de/documentation/faq/lock-codes-email.md +++ b/docs/de/documentation/faq/lock-codes-email.md @@ -1,11 +1,11 @@ -# Wie füge ich Zahlenschloss-Codes in E-Mails ein? +# Wie füge ich Zahlenschloss-Codes in E-Mails ein? -Eine häufige Frage ist, ob Codes für Zahlenschlösser an Artikeln oder -Standorten hinzugefügt werden können um Sie in den versendeten E-Mails -anzuzeigen. +## Wie füge ich Zahlenschloss-Codes in E-Mails ein? -Das funktioniert über sog. Meta-Felder, welche Artikel und Standort zugewiesen -werden. Diese Felder können dann auch in den E-Mail Templates verwendet -werden. +::: details Antwort anzeigen +Eine häufige Frage ist, ob Codes für Zahlenschlösser an Artikeln oder Standorten hinzugefügt werden können, um sie in den versendeten E-Mails anzuzeigen. -Der Aritkel [Template-Tags](../administration/template-tags#eigene-metafelder-fur-standorte-und-artikel-verwenden) der Dokumentation enthält eine Ausführliche Anleitung. +Das funktioniert über sog. Meta-Felder, welche Artikel und Standort zugewiesen werden. Diese Felder können dann auch in den E-Mail-Templates verwendet werden. + +Der Artikel [Template-Tags](../administration/template-tags#eigene-metafelder-fur-standorte-und-artikel-verwenden) der Dokumentation enthält eine ausführliche Anleitung. +::: diff --git a/docs/de/documentation/faq/organise-article-page.md b/docs/de/documentation/faq/organise-article-page.md index cbce05f12..f689d293e 100644 --- a/docs/de/documentation/faq/organise-article-page.md +++ b/docs/de/documentation/faq/organise-article-page.md @@ -1,13 +1,11 @@ -# Wie kann ich die Artikeldetailseite übersichtlicher gestalten? +# Wie kann ich die Artikeldetailseite übersichtlicher gestalten? -## Informationen erst auf Klick anzeigen +## Wie kann ich die Artikeldetailseite übersichtlicher gestalten? -Lange Artikelseiten bedeuten, dass Menschen lange bis zum Buchungskalender -scrollen müssen. +::: details Antwort anzeigen +Lange Artikelseiten bedeuten, dass Menschen lange bis zum Buchungskalender scrollen müssen. -Hier empfiehlt sich ein Plugin wie [ Show-Hide/Collapse-Expand -](https://de.wordpress.org/plugins/show-hidecollapse-expand) zu nutzen, mit -dem Informationen eingeklappt werden können. +Hier empfiehlt sich ein Plugin wie [Show-Hide/Collapse-Expand](https://de.wordpress.org/plugins/show-hidecollapse-expand) zu nutzen, mit dem Informationen eingeklappt werden können. ![](/img/item-collapse.png) - +::: diff --git a/docs/de/documentation/faq/problems-and-answers.md b/docs/de/documentation/faq/problems-and-answers.md index aebab7705..74acf024e 100644 --- a/docs/de/documentation/faq/problems-and-answers.md +++ b/docs/de/documentation/faq/problems-and-answers.md @@ -1,27 +1,61 @@ -# Probleme und Antworten +# Probleme mit inkompatiblen Plugins oder Themes -### Anzeige Kalender-Widget im Admin-Bereich +## Kalender-Widget wird im Admin-Bereich nicht korrekt angezeigt -Treten Probleme bei der Anzeige des Kalenders im Admin-Bereich der Buchungen -auf (sog. Admin-Backend), siehe das folgende Bild rechts unten, kann eine -mögliche Lösung sein, das [ Plugin "Lightstart" (wp-maintenance-mode) -](https://wordpress.org/plugins/wp-maintenance-mode) zu deaktivieren oder zu -entfernen und neu zu installieren. Das Problem ist eine Inkompatibilität von -Lightstart mit CommonsBooking und kein Fehler im Code von CommonsBooking. Das -Problem tritt nicht mehr auf, wenn eine Neuinstallation von Lightstart -vorgenommen wurde. Mehr dazu auf [ Github im CommonsBooking Quellcode- -Repository ](https://github.com/wielebenwir/commonsbooking/issues/1646) . +::: details Antwort anzeigen +Treten Probleme bei der Anzeige des Kalenders im Admin-Bereich der Buchungen auf (sog. Admin-Backend), kann eine mögliche Lösung sein, das [Plugin "Lightstart" (wp-maintenance-mode)](https://wordpress.org/plugins/wp-maintenance-mode) zu deaktivieren oder zu entfernen und neu zu installieren. Das Problem ist eine Inkompatibilität von Lightstart mit CommonsBooking und kein Fehler im Code von CommonsBooking. Das Problem tritt nicht mehr auf, wenn eine Neuinstallation von Lightstart vorgenommen wurde. Mehr dazu auf [Github im CommonsBooking Quellcode-Repository](https://github.com/wielebenwir/commonsbooking/issues/1646). ![](/img/backend-booking-list-bug.png) +::: -### Inkompatibles Theme Gridbulletin +## Inkompatibles Theme: GridBulletin -In der letzten Version von [ GridBulletin -](https://wordpress.org/themes/gridbulletin) kommt es zu einer -Inkompatibilität mit CommonsBooking. Probleme tauchen auf, wenn der Footer -aktiviert ist. Konkrete Probleme sind z.B. das Fehlen des Buchungs-Kalenders -auf der Artikelseite. Aus technischer Sicht liegt es daran, dass die nötigen -Javascript-Quellen von CommonsBooking nicht ausgeliefert werden. Der Grund -innerhalb des GridBulletin Themes oder eine Lösung konnte bisher nicht -gefunden werden. +::: details Antwort anzeigen +In der letzten Version von [GridBulletin](https://wordpress.org/themes/gridbulletin) kommt es zu einer Inkompatibilität mit CommonsBooking. Probleme tauchen auf, wenn der Footer aktiviert ist. Konkrete Probleme sind z.B. das Fehlen des Buchungs-Kalenders auf der Artikelseite. Aus technischer Sicht liegt es daran, dass die nötigen Javascript-Quellen von CommonsBooking nicht ausgeliefert werden. Der Grund innerhalb des GridBulletin Themes oder eine Lösung konnte bisher nicht gefunden werden. +::: + +## Inkompatibles Plugin: All-in-one-Event + +::: details Antwort anzeigen +:::info Behoben seit 2.7.2 (06.2022) +Für Experten siehe [Issue 675](https://github.com/wielebenwir/commonsbooking/issues/675) +::: + +Leider kommt es bei der gleichzeitigen Nutzung des Plugins "All-in-one-Event" zu Fehlern, sodass Seiten, die von CommonsBooking erzeugt werden, nicht angezeigt werden. + +Die Ursache ist leider auf eine schlechte Programmierung des All-in-one-Event-Plugins zurückzuführen, welches sich nicht an die Wordpress-Standards hält und so tief in Wordpress eingreift, dass es die Programmlogik von CommonsBooking quasi überschreibt. + +Wir haben einiges versucht, um eine parallele Nutzung zu ermöglichen, leider aber bisher keine Lösung gefunden. + +Wenn ihr das Problem auch habt, schreibt gerne direkt an den Support des Plugins, vielleicht passen sie ihr Plugin doch noch irgendwann an. +::: + +## Inkompatibles Plugin: REDIS Object Cache + +::: details Antwort anzeigen +Im Zusammenhang mit dem [Cache](../advanced-functionality/) gab es in der Vergangenheit bereits Probleme mit anderen Wordpress-Plugins wie z.B. 'REDIS Object Cache'. Aus diesem Grund raten wir von der Nutzung solcher Plugins ab. + +Die von CommonsBooking generierten Seiten sollten von der Optimierung durch Dritt-Plugins ausgenommen werden. CommonsBooking verwendet ein eigenes Caching. +::: + +## Inkompatibles Plugin: Ultimate Member + +::: details Antwort anzeigen +Wenn ihr das Plugin Ultimate Member benutzt und die Benutzerrolle "CommonsBooking Manager" nutzen möchtet, müsst ihr in Ultimate Member für die Rolle `cb_manager` noch ein Häkchen setzen, um diese für den Admin-Zugang zu aktivieren. +::: + +## Inkompatible Plugins: Autoptimize / Caching-Plugins + +::: details Antwort anzeigen +Optimierungs-Plugins oder weitere Caching-Plugins können dazu führen, dass CommonsBooking nicht alle Seiten korrekt anzeigen kann. + +Betroffene Plugins (nicht vollständig): +* Autoptimize + +Die von CommonsBooking generierten Seiten sollten von der Optimierung durch Dritt-Plugins ausgenommen werden. CommonsBooking verwendet ein eigenes Caching. + +::: info Hast du ein Problem festgestellt? +Dann trage die Inkompatibilität hier ein! +::: +::: diff --git a/docs/de/documentation/faq/site-slow.md b/docs/de/documentation/faq/site-slow.md index 582b2f284..38fb575c9 100644 --- a/docs/de/documentation/faq/site-slow.md +++ b/docs/de/documentation/faq/site-slow.md @@ -1,5 +1,8 @@ -# Die Seite ist sehr langsam +# Die Seite ist sehr langsam +## Die Seite ist sehr langsam + +::: details Antwort anzeigen Wenn deine CommonsBooking Seite sehr langsam ist, kann das verschiedene Gründe haben. Wir nutzen eine Technologie namens Caching, mit der wir häufig gestellte Anfragen in einem Zwischenspeicher zurückhalten, um Serverkapazitäten einzusparen. @@ -17,6 +20,7 @@ Das Caching kann unter Umständen nicht funktionieren, wenn: Alternativ kannst du auch [REDIS](https://redis.io) auf deinem Server installieren und den Cache durch REDIS verwalten lassen. Da REDIS den Cache im RAM speichert, statt im Dateisystem, ist das meistens etwas schneller. +::: ## Troubleshooting diff --git a/docs/en/documentation/faq/avoid-spam-registrations.md b/docs/en/documentation/faq/avoid-spam-registrations.md index 8c0efe268..469f27d6b 100644 --- a/docs/en/documentation/faq/avoid-spam-registrations.md +++ b/docs/en/documentation/faq/avoid-spam-registrations.md @@ -1,9 +1,13 @@ -# How do I prevent spam registrations +# How do I prevent spam registrations? +## How do I prevent spam registrations? + +::: details Expand for answer There are several ways to do this (suggestions from the community): -* A honeypot diverts bots without bothering people: https://wordpress.org/plugins/honeypot/ +* A honeypot diverts bots without bothering people: [Honeypot plugin](https://wordpress.org/plugins/honeypot/) * "I once wrote a tiny plugin for **UltimateMember where you simply have to enter a text to register**. Accessible and it keeps all bots out: [Download from GitHub](https://github.com/hansmorb/um-captchaquiz/raw/refs/heads/master/um-captchaquiz.zip). Just create a text box and enter the meta key in the plugin settings." * "We use hCaptcha for WordPress. After installation, select the registration you use in the plugin settings (e.g., UltimateMember; by default the built-in WordPress registration should be selected). To use it, you need to create an hCaptcha account. They advertise Privacy-First and that no user data is sold. I have not checked this myself." — [Download from the plugin directory](https://wordpress.org/plugins/hcaptcha-for-forms-and-more) +::: diff --git a/docs/en/documentation/faq/block-users.md b/docs/en/documentation/faq/block-users.md new file mode 100644 index 000000000..dd98a1882 --- /dev/null +++ b/docs/en/documentation/faq/block-users.md @@ -0,0 +1,13 @@ +# How do I temporarily block individual users? + +## How do I temporarily block individual users? + +::: details Expand for answer +Do you want to temporarily block users for a certain period of time, e.g. because they use the rental service excessively or violate the rental conditions? + +The recommended approach is to use a dedicated WordPress plugin for blocking users. If your users cannot do anything on the site other than making bookings, this is also the simplest solution. + +The plugin [User Blocker](https://wordpress.org/plugins/user-blocker/) has been tested and works without issues, including a timer function. There are other plugins available with the same functionality. + +Blocking specific user groups is not a built-in feature of CommonsBooking and is unlikely to be added soon, as existing WordPress plugins already cover this use case well. +::: diff --git a/docs/en/documentation/faq/booking-comment-emails.md b/docs/en/documentation/faq/booking-comment-emails.md index 4598c49f1..493dc8ec9 100644 --- a/docs/en/documentation/faq/booking-comment-emails.md +++ b/docs/en/documentation/faq/booking-comment-emails.md @@ -1,3 +1,7 @@ # How do I show the booking comment on the page and in the email? +## How do I show the booking comment on the page and in the email? + +::: details Expand for answer In the settings you can enable booking comments. In the email templates you then need to insert the following code:
`{{booking:returnComment}}`
+::: diff --git a/docs/en/documentation/faq/booking-through-closed-days.md b/docs/en/documentation/faq/booking-through-closed-days.md new file mode 100644 index 000000000..644fa3412 --- /dev/null +++ b/docs/en/documentation/faq/booking-through-closed-days.md @@ -0,0 +1,9 @@ +# How do I allow booking across closed days? + +## How do I allow booking across closed days? + +::: details Expand for answer +If you want to allow your users to book an item across closed days (e.g. over a weekend when the station is closed), you can configure this in the location settings. + +For detailed instructions, see [Create Locations](../first-steps/create-location). +::: diff --git a/docs/en/documentation/faq/increase-items-per-page.md b/docs/en/documentation/faq/increase-items-per-page.md new file mode 100644 index 000000000..b63fb53b8 --- /dev/null +++ b/docs/en/documentation/faq/increase-items-per-page.md @@ -0,0 +1,13 @@ +# How do I increase the number of items shown in the cb_items list? + +## How do I increase the number of items shown in the cb_items list? + +::: details Expand for answer +The number of items shown per page is taken from the global WordPress reading settings. + +To change it: + +1. Log in as a WordPress administrator +2. Go to **Settings → Reading** +3. Change the value for **Blog pages show at most** +::: diff --git a/docs/en/documentation/faq/index.md b/docs/en/documentation/faq/index.md index 958700318..579ac7130 100644 --- a/docs/en/documentation/faq/index.md +++ b/docs/en/documentation/faq/index.md @@ -1,46 +1,113 @@ # Frequently Asked Questions (FAQ) -### Pages +## How do I show the booking comment on the page and in the email? - * [How do I show the booking comment on the page and in the email?](booking-comment-emails) - * [How can I make the item detail page clearer?](organise-article-page) - * [The site is very slow](site-slow) - * [How do I show lock codes in emails?](lock-codes-email) +::: details Expand for answer +In the settings you can enable booking comments. In the email templates you then need to insert the following code:
`{{booking:returnComment}}`
+::: + +## How can I make the item detail page clearer? + +::: details Expand for answer +Long item pages mean users have to scroll a long way to reach the booking calendar. + +A plugin such as [Show-Hide/Collapse-Expand](https://de.wordpress.org/plugins/show-hidecollapse-expand) can be used to collapse information. + +![](/img/item-collapse.png) +::: + +## My site is very slow, what can I do? + +::: details Expand for answer +If your CommonsBooking site is very slow, there may be several underlying causes. +We use a technology called caching, which keeps frequently requested data +in temporary storage to save server resources. +Caching may not work under certain conditions, for example when: + + * [WP_DEBUG](https://wordpress.org/documentation/article/debugging-in-wordpress) is enabled; in that case you need to edit your wp-config.php + * The /tmp/ folder on your server is not writable. If that is the case, contact your web host and ask them to make the folder writable. + * If that is not possible, you can set the path for the filesystem cache in the CommonsBooking settings under "Advanced Options". Ask your web host which folders on the server are available for temporary files. + * If that is also not possible: Go to your Site Health screen at (http://YOUR-URL/wp-admin/site-health.php?tab=debug). There you will find the path to your WordPress directory under **Directories**. Alternatively, choose a folder in the format `YOUR_DIRECTORY/symfony` as the cache target. **Warning:** This can cause your WordPress directory to grow very large. + +Alternatively, you can install [Redis](https://redis.io) on your server and let Redis manage the cache. Since Redis stores the cache in RAM instead of the filesystem, it is usually a bit faster. +::: + +## How do I show lock codes in emails? + +::: details Expand for answer +A frequent question is whether lock codes for combination locks can be added to items or locations so that they are displayed in the sent emails. + +This is possible via so-called meta fields, which are assigned to items and locations. These fields can then also be used in email templates. + +[This page of the documentation contains a detailed guide.](../administration/template-tags) +::: -## I want to temporarily block individual users +## How do I temporarily block individual users? +::: details Expand for answer Do you want to temporarily block users for a certain period of time, e.g. because they use the rental service excessively or violate the rental conditions? -I would advise you to simply block the entire login with an appropriate plugin for blocking users for a certain period of time. There are already some plugins for this. If your users can't do anything else on the site anyway other than booking bikes, it seems to make sense to do it this way. +The recommended approach is to use a dedicated WordPress plugin for blocking users. If your users cannot do anything on the site other than making bookings, this is also the simplest solution. -I just briefly tried the plugin https://wordpress.org/plugins/user-blocker/ and it worked without any problems, even with a timer function. But this is not the only plugin that has this function. +The plugin [User Blocker](https://wordpress.org/plugins/user-blocker/) has been tested and works without issues, including a timer function. There are other plugins available with the same functionality. -Blocking specific user groups is not a feature in CommonsBooking and probably won't be added as a feature anytime soon, as there are already some plugins that do exactly that. +Blocking specific user groups is not a built-in feature of CommonsBooking and is unlikely to be added soon, as existing WordPress plugins already cover this use case well. +::: + +## How do I allow booking across closed days? + +::: details Expand for answer +If you want to allow your users to book an item across closed days (e.g. over a weekend when the station is closed), you can configure this in the location settings. + +For detailed instructions, see [Create Locations](../first-steps/create-location). +::: + +## How do I increase the number of items shown in the cb_items list? -## Allow overbookable days / booking over the weekend +::: details Expand for answer +The number of items shown per page is taken from the global WordPress reading settings. -If you want to allow your users to book the item over the weekend, for example, you can make this setting in the location settings. +To change it: -More information at: https://commonsbooking.org/documentation/first-steps/create-location/ +1. Log in as a WordPress administrator +2. Go to **Settings -> Reading** +3. Change the value for **Blog pages show at most** +::: -## Increase the number of items in the cb_items list +## How do I prevent spam registrations? -The number of items per page is taken from the global WordPress settings. +::: details Expand for answer +There are several ways to do this (suggestions from the community): -These global settings can be changed here: +* A honeypot diverts bots without bothering people: [Honeypot plugin](https://wordpress.org/plugins/honeypot/) -Log in as WordPress administrator: +* "I once wrote a tiny plugin for **UltimateMember where you simply have to enter a text to register**. Accessible and it keeps all bots out: [Download from GitHub](https://github.com/hansmorb/um-captchaquiz/raw/refs/heads/master/um-captchaquiz.zip). Just create a text box and enter the meta key in the plugin settings." -Settings -> Reading -> Blog pages show at most +* "We use hCaptcha for WordPress. After installation, select the registration you use in the plugin settings (e.g., UltimateMember; by default the built-in WordPress registration should be selected). To use it, you need to create an hCaptcha account. They advertise Privacy-First and that no user data is sold. I have not checked this myself." - [Download from the plugin directory](https://wordpress.org/plugins/hcaptcha-for-forms-and-more) +::: -## Incorrect display of the calendar widget in the admin area +## Plugin & Theme Incompatibilities -If there are problems displaying the calendar in the admin area of the bookings (so-called admin backend), see the following picture on the bottom right, a possible solution can be to deactivate or remove and reinstall the [ "Lightstart" (wp-maintenance-mode) plugin ](https://wordpress.org/plugins/wp-maintenance-mode). The problem is an incompatibility of Lightstart with CommonsBooking and not an error in the CommonsBooking code. The problem no longer occurs if Lightstart has been reinstalled. Read more about this on [ Github in the CommonsBooking source code repository ](https://github.com/wielebenwir/commonsbooking/issues/1646). +### Lightstart + +::: details Expand for answer +If there are problems displaying the calendar in the booking admin area (the admin backend), see the image below on the right, one possible solution is to disable or remove and reinstall the ["Lightstart" (wp-maintenance-mode) plugin](https://wordpress.org/plugins/wp-maintenance-mode). +The issue is an incompatibility between Lightstart and CommonsBooking and not a bug in CommonsBooking's code. +The problem does not occur after reinstalling Lightstart. More details on [GitHub in the CommonsBooking source repository](https://github.com/wielebenwir/commonsbooking/issues/1646). ![](/img/backend-booking-list-bug.png) +::: -## Incompatible plugin All-in-one-Event Plugins +### GridBulletin + +::: details Expand for answer +The latest version of [GridBulletin](https://wordpress.org/themes/gridbulletin) is incompatible with CommonsBooking. +Problems occur when the footer is enabled. One concrete issue is the missing booking calendar on the item page. From a technical perspective, the required JavaScript sources from CommonsBooking are not being loaded. The root cause within the GridBulletin theme or a solution has not yet been found. +::: +### All-in-one-Event + +:::: details Expand for answer :::info Fixed since 2.7.2 (06.2022) For experts see [Issue 675](https://github.com/wielebenwir/commonsbooking/issues/675) ::: @@ -52,28 +119,35 @@ The cause is unfortunately due to poor programming of the All-in-one-Event plugi We have tried a few things to enable parallel use, but unfortunately have not found a solution yet. If you also have the problem, please write directly to the plugin's support, maybe they will adapt their plugin at some point. +:::: -## Incompatible plugin REDIS Object Cache +### REDIS Object Cache +::: details Expand for answer In connection with the [Cache](../advanced-functionality/), there have been problems with other WordPress plugins such as 'REDIS Object Cache' in the past. For this reason, we advise against using such plugins. -Therefore, the pages generated by CommonsBooking should be excluded from optimization by third-party plugins. +The pages generated by CommonsBooking should be excluded from optimization by third-party plugins. CommonsBooking uses its own caching. +::: -## Incompatible plugin Ultimate Member +### Ultimate Member -If you use the Ultimate Member plugin and want to use the "CommonsBooking Manager" user role, you have to check a box in Ultimate Member for the cb_manager role to activate it for AP admin access. +::: details Expand for answer +If you use the Ultimate Member plugin and want to use the "CommonsBooking Manager" user role, you have to check a box in Ultimate Member for the `cb_manager` role to activate it for admin access. +::: -## Incompatible plugins: Autoptimize / Caching +### Autoptimize / Caching plugins -Optimization plugins or other caching plugins can cause CommonsBooking to not be able to display all pages. +:::: details Expand for answer +Optimization plugins or other caching plugins can cause CommonsBooking to not display all pages correctly. -Incomplete list: +Affected plugins include (incomplete list): * Autoptimize -Therefore, the pages generated by CommonsBooking should be excluded from optimization by third-party plugins. +The pages generated by CommonsBooking should be excluded from optimization by third-party plugins. CommonsBooking uses its own caching. -::: info Have you noticed a problem? -Then enter the incompatibility here! +:::info Have you noticed a problem? +Add incompatible plugins or themes here! ::: +:::: diff --git a/docs/en/documentation/faq/lock-codes-email.md b/docs/en/documentation/faq/lock-codes-email.md index c3ddad0b3..273cf33f7 100644 --- a/docs/en/documentation/faq/lock-codes-email.md +++ b/docs/en/documentation/faq/lock-codes-email.md @@ -1,8 +1,11 @@ # How do I show lock codes in emails? +## How do I show lock codes in emails? + +::: details Expand for answer A frequent question is whether lock codes for combination locks can be added to items or locations so that they are displayed in the sent emails. This is possible via so-called meta fields, which are assigned to items and locations. These fields can then also be used in email templates. -werden. [This page of the documentation contains a detailed guide.](../administration/template-tags) +::: diff --git a/docs/en/documentation/faq/organise-article-page.md b/docs/en/documentation/faq/organise-article-page.md index a5794ecca..15811fa4f 100644 --- a/docs/en/documentation/faq/organise-article-page.md +++ b/docs/en/documentation/faq/organise-article-page.md @@ -1,9 +1,11 @@ # How can I make the item detail page clearer? -## Information only shown on click +## How can I make the item detail page clearer? +::: details Expand for answer Long item pages mean users have to scroll a long way to reach the booking calendar. A plugin such as [Show-Hide/Collapse-Expand](https://de.wordpress.org/plugins/show-hidecollapse-expand) can be used to collapse information. ![](/img/item-collapse.png) +::: diff --git a/docs/en/documentation/faq/problems-and-answers.md b/docs/en/documentation/faq/problems-and-answers.md index 3a8582ec6..7af86592b 100644 --- a/docs/en/documentation/faq/problems-and-answers.md +++ b/docs/en/documentation/faq/problems-and-answers.md @@ -1,14 +1,63 @@ -# Problems and answers +# Problems with incompatible plugins or themes -### Calendar widget display in the admin area +## Calendar widget not displaying correctly in the admin area -If there are problems displaying the calendar in the booking admin area (the admin backend), see the image below on the right, one possible solution is to disable or remove and reinstall the ["Lightstart" (wp-maintenance-mode) plugin](https://wordpress.org/plugins/wp-maintenance-mode). +::: details Expand for answer +If there are problems displaying the calendar in the booking admin area (the admin backend), see the image below on the right, one possible solution is to disable or remove and reinstall the ["Lightstart" (wp-maintenance-mode) plugin](https://wordpress.org/plugins/wp-maintenance-mode). The issue is an incompatibility between Lightstart and CommonsBooking and not a bug in CommonsBooking's code. The problem does not occur after reinstalling Lightstart. More details on [GitHub in the CommonsBooking source repository](https://github.com/wielebenwir/commonsbooking/issues/1646). ![](/img/backend-booking-list-bug.png) +::: -### Incompatible theme: GridBulletin +## Incompatible theme: GridBulletin +::: details Expand for answer The latest version of [GridBulletin](https://wordpress.org/themes/gridbulletin) is incompatible with CommonsBooking. Problems occur when the footer is enabled. One concrete issue is the missing booking calendar on the item page. From a technical perspective, the required JavaScript sources from CommonsBooking are not being loaded. The root cause within the GridBulletin theme or a solution has not yet been found. +::: + +## Incompatible plugin: All-in-one-Event + +::: details Expand for answer +:::info Fixed since 2.7.2 (06.2022) +For experts see [Issue 675](https://github.com/wielebenwir/commonsbooking/issues/675) +::: + +Unfortunately, using the "All-in-one-Event" plugin at the same time causes errors, so that pages generated by CommonsBooking are not displayed. + +The cause is unfortunately due to poor programming of the All-in-one-Event plugin, which does not adhere to WordPress standards and intervenes so deeply in WordPress that it virtually overwrites the program logic of CommonsBooking. + +We have tried a few things to enable parallel use, but unfortunately have not found a solution yet. + +If you also have the problem, please write directly to the plugin's support, maybe they will adapt their plugin at some point. +::: + +## Incompatible plugin: REDIS Object Cache + +::: details Expand for answer +In connection with the [Cache](../advanced-functionality/), there have been problems with other WordPress plugins such as 'REDIS Object Cache' in the past. For this reason, we advise against using such plugins. + +The pages generated by CommonsBooking should be excluded from optimization by third-party plugins. CommonsBooking uses its own caching. +::: + +## Incompatible plugin: Ultimate Member + +::: details Expand for answer +If you use the Ultimate Member plugin and want to use the "CommonsBooking Manager" user role, you have to check a box in Ultimate Member for the `cb_manager` role to activate it for admin access. +::: + +## Incompatible plugins: Autoptimize / Caching plugins + +::: details Expand for answer +Optimization plugins or other caching plugins can cause CommonsBooking to not display all pages correctly. + +Affected plugins include (incomplete list): +* Autoptimize + +The pages generated by CommonsBooking should be excluded from optimization by third-party plugins. CommonsBooking uses its own caching. + +::: info Have you noticed a problem? +Add incompatible plugins or themes here! +::: +::: diff --git a/docs/en/documentation/faq/site-slow.md b/docs/en/documentation/faq/site-slow.md index a2c19002b..fb7ed4934 100644 --- a/docs/en/documentation/faq/site-slow.md +++ b/docs/en/documentation/faq/site-slow.md @@ -1,5 +1,8 @@ # The site is very slow +## The site is very slow + +::: details Expand for answer If your CommonsBooking site is very slow, there may be several underlying causes. We use a technology called caching, which keeps frequently requested data in temporary storage to save server resources. @@ -11,3 +14,4 @@ Caching may not work under certain conditions, for example when: * If that is also not possible: Go to your Site Health screen at (http://YOUR-URL/wp-admin/site-health.php?tab=debug). There you will find the path to your WordPress directory under **Directories**. Alternatively, choose a folder in the format `YOUR_DIRECTORY/symfony` as the cache target. **Warning:** This can cause your WordPress directory to grow very large. Alternatively, you can install [Redis](https://redis.io) on your server and let Redis manage the cache. Since Redis stores the cache in RAM instead of the filesystem, it is usually a bit faster. +::: From 7f77ec7397833e6e3acc416e88e0a533e396486a Mon Sep 17 00:00:00 2001 From: Stefan Bomsdorf Date: Fri, 1 May 2026 09:26:55 +0200 Subject: [PATCH 019/148] Adds a hint about FAQ vs. knwon incompatibilities. Co-authored-by: Copilot --- docs/de/documentation/faq/index.md | 2 ++ docs/en/documentation/faq/index.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/docs/de/documentation/faq/index.md b/docs/de/documentation/faq/index.md index 306fa8089..04f65d3fe 100644 --- a/docs/de/documentation/faq/index.md +++ b/docs/de/documentation/faq/index.md @@ -1,5 +1,7 @@ # Häufige Fragen (FAQ) +Diese Seite ist in zwei Bereiche unterteilt: allgemeine **FAQ** mit häufigen Fragen zur Nutzung, und **Plugin- und Theme-Inkompatibilitäten** mit bekannten Problemen durch Drittanbieter-Software. + ## Wie bekomme ich den Buchungskommentar auf die Seite und in die Email? ::: details Antwort anzeigen diff --git a/docs/en/documentation/faq/index.md b/docs/en/documentation/faq/index.md index 579ac7130..14ebd1f0b 100644 --- a/docs/en/documentation/faq/index.md +++ b/docs/en/documentation/faq/index.md @@ -1,5 +1,7 @@ # Frequently Asked Questions (FAQ) +This page is split into two sections: general **FAQ** with common how-to questions, and **Plugin & Theme Incompatibilities** listing known issues with third-party software. + ## How do I show the booking comment on the page and in the email? ::: details Expand for answer From 920e3a44ce1f6fe3bce0dd8bd3406bb017948594 Mon Sep 17 00:00:00 2001 From: Stefan Bomsdorf Date: Fri, 1 May 2026 09:29:50 +0200 Subject: [PATCH 020/148] Removes old subpages. They have been merged into a single FAQ page. Co-authored-by: Copilot --- docs/.vitepress/config.mts | 28 +-------- .../faq/avoid-spam-registrations.md | 13 ---- docs/de/documentation/faq/block-users.md | 13 ---- .../faq/booking-comment-emails.md | 7 --- .../faq/booking-through-closed-days.md | 9 --- .../faq/increase-items-per-page.md | 13 ---- docs/de/documentation/faq/lock-codes-email.md | 11 ---- .../faq/organise-article-page.md | 11 ---- .../documentation/faq/problems-and-answers.md | 61 ------------------ docs/de/documentation/faq/site-slow.md | 32 ---------- .../faq/avoid-spam-registrations.md | 13 ---- docs/en/documentation/faq/block-users.md | 13 ---- .../faq/booking-comment-emails.md | 7 --- .../faq/booking-through-closed-days.md | 9 --- .../faq/increase-items-per-page.md | 13 ---- docs/en/documentation/faq/lock-codes-email.md | 11 ---- .../faq/organise-article-page.md | 11 ---- .../documentation/faq/problems-and-answers.md | 63 ------------------- docs/en/documentation/faq/site-slow.md | 17 ----- 19 files changed, 2 insertions(+), 353 deletions(-) delete mode 100644 docs/de/documentation/faq/avoid-spam-registrations.md delete mode 100644 docs/de/documentation/faq/block-users.md delete mode 100644 docs/de/documentation/faq/booking-comment-emails.md delete mode 100644 docs/de/documentation/faq/booking-through-closed-days.md delete mode 100644 docs/de/documentation/faq/increase-items-per-page.md delete mode 100644 docs/de/documentation/faq/lock-codes-email.md delete mode 100644 docs/de/documentation/faq/organise-article-page.md delete mode 100644 docs/de/documentation/faq/problems-and-answers.md delete mode 100644 docs/de/documentation/faq/site-slow.md delete mode 100644 docs/en/documentation/faq/avoid-spam-registrations.md delete mode 100644 docs/en/documentation/faq/block-users.md delete mode 100644 docs/en/documentation/faq/booking-comment-emails.md delete mode 100644 docs/en/documentation/faq/booking-through-closed-days.md delete mode 100644 docs/en/documentation/faq/increase-items-per-page.md delete mode 100644 docs/en/documentation/faq/lock-codes-email.md delete mode 100644 docs/en/documentation/faq/organise-article-page.md delete mode 100644 docs/en/documentation/faq/problems-and-answers.md delete mode 100644 docs/en/documentation/faq/site-slow.md diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index cbf4fdbc8..9d8091088 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -273,19 +273,7 @@ export function sidebarDocs_de(): DefaultTheme.SidebarItem[] { { text: 'Häufige Fragen (Version 0.9.x)', link: 'faq' } ] }, - { - text: 'Häufige Fragen (FAQ)', base: '/de/documentation/faq/', - link: '/', - collapsed: true, - items: [ - { text: 'Die Seite ist sehr langsam', link: 'site-slow' }, - { text: 'Probleme und Antworten', link: 'problems-and-answers' }, - { text: 'Wie bekomme ich den Buchungskommentar ...', link: 'booking-comment-emails' }, - { text: 'Kann ich Zahlenschloss-Codes in E-Mails einfügen?', link: 'lock-codes-email' }, - { text: 'Artikeldetailseite übersichtlicher gestalten', link: 'organise-article-page' }, - { text: 'Wie verhindere ich Spam Registrierungen', link: 'avoid-spam-registrations'} - ] - }, + { text: 'Häufige Fragen (FAQ)', link: '/de/documentation/faq/' }, ] } @@ -395,19 +383,7 @@ export function sidebarDocs_en(): DefaultTheme.SidebarItem[] { { text: 'Overview of releases and planned further development', link: 'release-overview' } ] }, - { - text: 'Frequently Asked Questions (FAQ)', base: '/en/documentation/faq/', - link: '/', - collapsed: true, - items: [ - { text: 'The site is very slow', link: 'site-slow' }, - { text: 'Problems and answers', link: 'problems-and-answers' }, - { text: 'How do I show the booking comment on the page and in the email?', link: 'booking-comment-emails' }, - { text: 'How do I show lock codes in emails?', link: 'lock-codes-email' }, - { text: 'How can I make the item detail page clearer?', link: 'organise-article-page' }, - { text: 'How do I prevent spam registrations?', link: 'avoid-spam-registrations'} - ] - }, + { text: 'Frequently Asked Questions (FAQ)', link: '/en/documentation/faq/' }, ] } diff --git a/docs/de/documentation/faq/avoid-spam-registrations.md b/docs/de/documentation/faq/avoid-spam-registrations.md deleted file mode 100644 index 01246ba26..000000000 --- a/docs/de/documentation/faq/avoid-spam-registrations.md +++ /dev/null @@ -1,13 +0,0 @@ -# Wie verhindere ich Spam-Registrierungen? - -## Wie verhindere ich Spam-Registrierungen? - -::: details Antwort anzeigen -Dafür gibt es verschiedene Möglichkeiten (Vorschläge aus der Community): - -* Ein HoneyPot lenkt Bots ab, ohne Menschen zu nerven: [Honeypot Plugin](https://wordpress.org/plugins/honeypot/) - -* "Ich hatte mal für **UltimateMember ein winziges Plugin geschrieben mit dem man einfach einen Text eingeben muss um sich zu registrieren**. Barrierearm und hält alle Bots ab: [Download von Github](https://github.com/hansmorb/um-captchaquiz/raw/refs/heads/master/um-captchaquiz.zip). Dazu einfach eine Textbox erstellen und den Metaschlüssel in den Plugin Einstellungen eintragen." - -* "Wir nutzen Hcaptcha für wordpress. Nach der Installation in den Einstellungen des Plugins die von euch genutzte Registrierung (z.B. UltimateMember) auswählen. Für die Nutzung muss ein Hcaptcha Account erstellt werden. Sie werben mit Privacy-First und das keine Nutzerdaten verkauft werden. Ich selber habe das nicht geprüft." — [Download aus dem Plugin-Verzeichnis](https://wordpress.org/plugins/hcaptcha-for-forms-and-more) -::: diff --git a/docs/de/documentation/faq/block-users.md b/docs/de/documentation/faq/block-users.md deleted file mode 100644 index 75a5cd2d0..000000000 --- a/docs/de/documentation/faq/block-users.md +++ /dev/null @@ -1,13 +0,0 @@ -# Wie sperre ich einzelne Nutzer vorübergehend? - -## Wie sperre ich einzelne Nutzer vorübergehend? - -::: details Antwort anzeigen -Möchtest du Nutzende vorübergehend für einen bestimmten Zeitraum sperren, weil diese z.B. die Ausleihe übermäßig nutzen oder gegen Ausleihbedingungen verstoßen? - -Wir empfehlen, ein dediziertes WordPress-Plugin zum Blockieren von Nutzenden zu verwenden. Wenn deine Nutzenden auf der Seite sowieso nichts anderes tun können als buchen, ist das auch die einfachste Lösung. - -Das Plugin [User Blocker](https://wordpress.org/plugins/user-blocker/) wurde getestet und funktioniert problemlos, auch mit einer Zeitschaltfunktion. Es gibt weitere Plugins mit dieser Funktionalität. - -Das Blockieren bestimmter Benutzergruppen ist kein eingebautes Feature von CommonsBooking und wird wahrscheinlich auch in naher Zukunft nicht kommen, da es bereits WordPress-Plugins gibt, die genau das abdecken. -::: diff --git a/docs/de/documentation/faq/booking-comment-emails.md b/docs/de/documentation/faq/booking-comment-emails.md deleted file mode 100644 index d5254e7f2..000000000 --- a/docs/de/documentation/faq/booking-comment-emails.md +++ /dev/null @@ -1,7 +0,0 @@ -# Wie bekomme ich den Buchungskommentar auf die Seite und in die Email? - -## Wie bekomme ich den Buchungskommentar auf die Seite und in die Email? - -::: details Antwort anzeigen -In den Einstellungen kannst du die Buchungskommentare aktivieren. In den E-Mail-Vorlagen musst du dann folgenden Code einfügen: `{{booking:returnComment}}` -::: diff --git a/docs/de/documentation/faq/booking-through-closed-days.md b/docs/de/documentation/faq/booking-through-closed-days.md deleted file mode 100644 index 3c708f602..000000000 --- a/docs/de/documentation/faq/booking-through-closed-days.md +++ /dev/null @@ -1,9 +0,0 @@ -# Wie erlaube ich Buchungen über geschlossene Tage hinweg? - -## Wie erlaube ich Buchungen über geschlossene Tage hinweg? - -::: details Antwort anzeigen -Wenn du deinen Nutzenden ermöglichen möchtest, einen Artikel über geschlossene Tage hinweg zu buchen (z.B. über das Wochenende, wenn die Station geschlossen ist), kannst du das in den Standort-Einstellungen konfigurieren. - -Ausführliche Informationen findest du unter [Standorte anlegen](../first-steps/create-location). -::: diff --git a/docs/de/documentation/faq/increase-items-per-page.md b/docs/de/documentation/faq/increase-items-per-page.md deleted file mode 100644 index 211db1fb3..000000000 --- a/docs/de/documentation/faq/increase-items-per-page.md +++ /dev/null @@ -1,13 +0,0 @@ -# Wie erhöhe ich die Anzahl der Artikel in der cb_items-Liste? - -## Wie erhöhe ich die Anzahl der Artikel in der cb_items-Liste? - -::: details Antwort anzeigen -Die Anzahl der Artikel pro Seite wird über die globalen WordPress-Leseeinstellungen übernommen. - -So änderst du sie: - -1. Als WordPress-Administrator einloggen -2. **Einstellungen → Lesen** aufrufen -3. Den Wert bei **Blogseiten zeigen maximal** anpassen -::: diff --git a/docs/de/documentation/faq/lock-codes-email.md b/docs/de/documentation/faq/lock-codes-email.md deleted file mode 100644 index 0fda9b002..000000000 --- a/docs/de/documentation/faq/lock-codes-email.md +++ /dev/null @@ -1,11 +0,0 @@ -# Wie füge ich Zahlenschloss-Codes in E-Mails ein? - -## Wie füge ich Zahlenschloss-Codes in E-Mails ein? - -::: details Antwort anzeigen -Eine häufige Frage ist, ob Codes für Zahlenschlösser an Artikeln oder Standorten hinzugefügt werden können, um sie in den versendeten E-Mails anzuzeigen. - -Das funktioniert über sog. Meta-Felder, welche Artikel und Standort zugewiesen werden. Diese Felder können dann auch in den E-Mail-Templates verwendet werden. - -Der Artikel [Template-Tags](../administration/template-tags#eigene-metafelder-fur-standorte-und-artikel-verwenden) der Dokumentation enthält eine ausführliche Anleitung. -::: diff --git a/docs/de/documentation/faq/organise-article-page.md b/docs/de/documentation/faq/organise-article-page.md deleted file mode 100644 index f689d293e..000000000 --- a/docs/de/documentation/faq/organise-article-page.md +++ /dev/null @@ -1,11 +0,0 @@ -# Wie kann ich die Artikeldetailseite übersichtlicher gestalten? - -## Wie kann ich die Artikeldetailseite übersichtlicher gestalten? - -::: details Antwort anzeigen -Lange Artikelseiten bedeuten, dass Menschen lange bis zum Buchungskalender scrollen müssen. - -Hier empfiehlt sich ein Plugin wie [Show-Hide/Collapse-Expand](https://de.wordpress.org/plugins/show-hidecollapse-expand) zu nutzen, mit dem Informationen eingeklappt werden können. - -![](/img/item-collapse.png) -::: diff --git a/docs/de/documentation/faq/problems-and-answers.md b/docs/de/documentation/faq/problems-and-answers.md deleted file mode 100644 index 74acf024e..000000000 --- a/docs/de/documentation/faq/problems-and-answers.md +++ /dev/null @@ -1,61 +0,0 @@ -# Probleme mit inkompatiblen Plugins oder Themes - -## Kalender-Widget wird im Admin-Bereich nicht korrekt angezeigt - -::: details Antwort anzeigen -Treten Probleme bei der Anzeige des Kalenders im Admin-Bereich der Buchungen auf (sog. Admin-Backend), kann eine mögliche Lösung sein, das [Plugin "Lightstart" (wp-maintenance-mode)](https://wordpress.org/plugins/wp-maintenance-mode) zu deaktivieren oder zu entfernen und neu zu installieren. Das Problem ist eine Inkompatibilität von Lightstart mit CommonsBooking und kein Fehler im Code von CommonsBooking. Das Problem tritt nicht mehr auf, wenn eine Neuinstallation von Lightstart vorgenommen wurde. Mehr dazu auf [Github im CommonsBooking Quellcode-Repository](https://github.com/wielebenwir/commonsbooking/issues/1646). - -![](/img/backend-booking-list-bug.png) -::: - -## Inkompatibles Theme: GridBulletin - -::: details Antwort anzeigen -In der letzten Version von [GridBulletin](https://wordpress.org/themes/gridbulletin) kommt es zu einer Inkompatibilität mit CommonsBooking. Probleme tauchen auf, wenn der Footer aktiviert ist. Konkrete Probleme sind z.B. das Fehlen des Buchungs-Kalenders auf der Artikelseite. Aus technischer Sicht liegt es daran, dass die nötigen Javascript-Quellen von CommonsBooking nicht ausgeliefert werden. Der Grund innerhalb des GridBulletin Themes oder eine Lösung konnte bisher nicht gefunden werden. -::: - -## Inkompatibles Plugin: All-in-one-Event - -::: details Antwort anzeigen -:::info Behoben seit 2.7.2 (06.2022) -Für Experten siehe [Issue 675](https://github.com/wielebenwir/commonsbooking/issues/675) -::: - -Leider kommt es bei der gleichzeitigen Nutzung des Plugins "All-in-one-Event" zu Fehlern, sodass Seiten, die von CommonsBooking erzeugt werden, nicht angezeigt werden. - -Die Ursache ist leider auf eine schlechte Programmierung des All-in-one-Event-Plugins zurückzuführen, welches sich nicht an die Wordpress-Standards hält und so tief in Wordpress eingreift, dass es die Programmlogik von CommonsBooking quasi überschreibt. - -Wir haben einiges versucht, um eine parallele Nutzung zu ermöglichen, leider aber bisher keine Lösung gefunden. - -Wenn ihr das Problem auch habt, schreibt gerne direkt an den Support des Plugins, vielleicht passen sie ihr Plugin doch noch irgendwann an. -::: - -## Inkompatibles Plugin: REDIS Object Cache - -::: details Antwort anzeigen -Im Zusammenhang mit dem [Cache](../advanced-functionality/) gab es in der Vergangenheit bereits Probleme mit anderen Wordpress-Plugins wie z.B. 'REDIS Object Cache'. Aus diesem Grund raten wir von der Nutzung solcher Plugins ab. - -Die von CommonsBooking generierten Seiten sollten von der Optimierung durch Dritt-Plugins ausgenommen werden. CommonsBooking verwendet ein eigenes Caching. -::: - -## Inkompatibles Plugin: Ultimate Member - -::: details Antwort anzeigen -Wenn ihr das Plugin Ultimate Member benutzt und die Benutzerrolle "CommonsBooking Manager" nutzen möchtet, müsst ihr in Ultimate Member für die Rolle `cb_manager` noch ein Häkchen setzen, um diese für den Admin-Zugang zu aktivieren. -::: - -## Inkompatible Plugins: Autoptimize / Caching-Plugins - -::: details Antwort anzeigen -Optimierungs-Plugins oder weitere Caching-Plugins können dazu führen, dass CommonsBooking nicht alle Seiten korrekt anzeigen kann. - -Betroffene Plugins (nicht vollständig): -* Autoptimize - -Die von CommonsBooking generierten Seiten sollten von der Optimierung durch Dritt-Plugins ausgenommen werden. CommonsBooking verwendet ein eigenes Caching. - -::: info Hast du ein Problem festgestellt? -Dann trage die Inkompatibilität hier ein! -::: -::: - diff --git a/docs/de/documentation/faq/site-slow.md b/docs/de/documentation/faq/site-slow.md deleted file mode 100644 index 38fb575c9..000000000 --- a/docs/de/documentation/faq/site-slow.md +++ /dev/null @@ -1,32 +0,0 @@ -# Die Seite ist sehr langsam - -## Die Seite ist sehr langsam - -::: details Antwort anzeigen -Wenn deine CommonsBooking Seite sehr langsam ist, kann das verschiedene Gründe haben. -Wir nutzen eine Technologie namens Caching, mit der wir häufig gestellte Anfragen in einem Zwischenspeicher -zurückhalten, um Serverkapazitäten einzusparen. - -Das Caching kann unter Umständen nicht funktionieren, wenn: - - * [WP_DEBUG](https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/) aktiviert ist, dafür musst du deine wp-config.php bearbeiten - * Der Ordner /tmp/ auf deinem Server nicht beschreibbar ist. Falls dies der Fall sein sollte, dann kontaktiere bitte deinen Webhoster und bitte ihn darum den Ordner beschreibbar zu machen. - * Falls das nicht möglich sein sollte, kannst du in den CommonsBooking Einstellungen unter “Erweiterte Optionen” den Pfad für den Dateisystem-Cache einstellen. Bitte frage bei deinem Webhoster nach, welche Ordner auf dem Server für temporäre Dateien verfügbar sind. - * Falls das auch nicht möglich sein sollte: Gehe zu deiner [Webseiten-Info](https://wordpress.org/documentation/article/site-health-screen/) unter (http://DEINE-URL/wp-admin/site-health.php?tab=debug). - Dort findest du unter **Verzeichnisse** den Pfad deines WordPress-Verzeichnisses. Wähle alternativ einen Ordner im Format `DEIN_VERZEICHNIS/symfony` als Cache-Ziel. - ::: danger Achtung - Dies kann dazu führen, dass dein WordPress-Verzeichnis sehr groß wird. - ::: - -Alternativ kannst du auch [REDIS](https://redis.io) auf deinem Server installieren und den Cache durch REDIS verwalten lassen. -Da REDIS den Cache im RAM speichert, statt im Dateisystem, ist das meistens etwas schneller. -::: - -## Troubleshooting - -::: warning Technische Expertise nötig! -::: - -Mit dem Plugin `query-monitor` kannst du Anfragen deiner Seite live überwachen. Damit es es z.B. möglich ein -falsch konfigurierten Cache schnell zu identifizieren. - diff --git a/docs/en/documentation/faq/avoid-spam-registrations.md b/docs/en/documentation/faq/avoid-spam-registrations.md deleted file mode 100644 index 469f27d6b..000000000 --- a/docs/en/documentation/faq/avoid-spam-registrations.md +++ /dev/null @@ -1,13 +0,0 @@ -# How do I prevent spam registrations? - -## How do I prevent spam registrations? - -::: details Expand for answer -There are several ways to do this (suggestions from the community): - -* A honeypot diverts bots without bothering people: [Honeypot plugin](https://wordpress.org/plugins/honeypot/) - -* "I once wrote a tiny plugin for **UltimateMember where you simply have to enter a text to register**. Accessible and it keeps all bots out: [Download from GitHub](https://github.com/hansmorb/um-captchaquiz/raw/refs/heads/master/um-captchaquiz.zip). Just create a text box and enter the meta key in the plugin settings." - -* "We use hCaptcha for WordPress. After installation, select the registration you use in the plugin settings (e.g., UltimateMember; by default the built-in WordPress registration should be selected). To use it, you need to create an hCaptcha account. They advertise Privacy-First and that no user data is sold. I have not checked this myself." — [Download from the plugin directory](https://wordpress.org/plugins/hcaptcha-for-forms-and-more) -::: diff --git a/docs/en/documentation/faq/block-users.md b/docs/en/documentation/faq/block-users.md deleted file mode 100644 index dd98a1882..000000000 --- a/docs/en/documentation/faq/block-users.md +++ /dev/null @@ -1,13 +0,0 @@ -# How do I temporarily block individual users? - -## How do I temporarily block individual users? - -::: details Expand for answer -Do you want to temporarily block users for a certain period of time, e.g. because they use the rental service excessively or violate the rental conditions? - -The recommended approach is to use a dedicated WordPress plugin for blocking users. If your users cannot do anything on the site other than making bookings, this is also the simplest solution. - -The plugin [User Blocker](https://wordpress.org/plugins/user-blocker/) has been tested and works without issues, including a timer function. There are other plugins available with the same functionality. - -Blocking specific user groups is not a built-in feature of CommonsBooking and is unlikely to be added soon, as existing WordPress plugins already cover this use case well. -::: diff --git a/docs/en/documentation/faq/booking-comment-emails.md b/docs/en/documentation/faq/booking-comment-emails.md deleted file mode 100644 index 493dc8ec9..000000000 --- a/docs/en/documentation/faq/booking-comment-emails.md +++ /dev/null @@ -1,7 +0,0 @@ -# How do I show the booking comment on the page and in the email? - -## How do I show the booking comment on the page and in the email? - -::: details Expand for answer -In the settings you can enable booking comments. In the email templates you then need to insert the following code:
`{{booking:returnComment}}`
-::: diff --git a/docs/en/documentation/faq/booking-through-closed-days.md b/docs/en/documentation/faq/booking-through-closed-days.md deleted file mode 100644 index 644fa3412..000000000 --- a/docs/en/documentation/faq/booking-through-closed-days.md +++ /dev/null @@ -1,9 +0,0 @@ -# How do I allow booking across closed days? - -## How do I allow booking across closed days? - -::: details Expand for answer -If you want to allow your users to book an item across closed days (e.g. over a weekend when the station is closed), you can configure this in the location settings. - -For detailed instructions, see [Create Locations](../first-steps/create-location). -::: diff --git a/docs/en/documentation/faq/increase-items-per-page.md b/docs/en/documentation/faq/increase-items-per-page.md deleted file mode 100644 index b63fb53b8..000000000 --- a/docs/en/documentation/faq/increase-items-per-page.md +++ /dev/null @@ -1,13 +0,0 @@ -# How do I increase the number of items shown in the cb_items list? - -## How do I increase the number of items shown in the cb_items list? - -::: details Expand for answer -The number of items shown per page is taken from the global WordPress reading settings. - -To change it: - -1. Log in as a WordPress administrator -2. Go to **Settings → Reading** -3. Change the value for **Blog pages show at most** -::: diff --git a/docs/en/documentation/faq/lock-codes-email.md b/docs/en/documentation/faq/lock-codes-email.md deleted file mode 100644 index 273cf33f7..000000000 --- a/docs/en/documentation/faq/lock-codes-email.md +++ /dev/null @@ -1,11 +0,0 @@ -# How do I show lock codes in emails? - -## How do I show lock codes in emails? - -::: details Expand for answer -A frequent question is whether lock codes for combination locks can be added to items or locations so that they are displayed in the sent emails. - -This is possible via so-called meta fields, which are assigned to items and locations. These fields can then also be used in email templates. - -[This page of the documentation contains a detailed guide.](../administration/template-tags) -::: diff --git a/docs/en/documentation/faq/organise-article-page.md b/docs/en/documentation/faq/organise-article-page.md deleted file mode 100644 index 15811fa4f..000000000 --- a/docs/en/documentation/faq/organise-article-page.md +++ /dev/null @@ -1,11 +0,0 @@ -# How can I make the item detail page clearer? - -## How can I make the item detail page clearer? - -::: details Expand for answer -Long item pages mean users have to scroll a long way to reach the booking calendar. - -A plugin such as [Show-Hide/Collapse-Expand](https://de.wordpress.org/plugins/show-hidecollapse-expand) can be used to collapse information. - -![](/img/item-collapse.png) -::: diff --git a/docs/en/documentation/faq/problems-and-answers.md b/docs/en/documentation/faq/problems-and-answers.md deleted file mode 100644 index 7af86592b..000000000 --- a/docs/en/documentation/faq/problems-and-answers.md +++ /dev/null @@ -1,63 +0,0 @@ -# Problems with incompatible plugins or themes - -## Calendar widget not displaying correctly in the admin area - -::: details Expand for answer -If there are problems displaying the calendar in the booking admin area (the admin backend), see the image below on the right, one possible solution is to disable or remove and reinstall the ["Lightstart" (wp-maintenance-mode) plugin](https://wordpress.org/plugins/wp-maintenance-mode). -The issue is an incompatibility between Lightstart and CommonsBooking and not a bug in CommonsBooking's code. -The problem does not occur after reinstalling Lightstart. More details on [GitHub in the CommonsBooking source repository](https://github.com/wielebenwir/commonsbooking/issues/1646). - -![](/img/backend-booking-list-bug.png) -::: - -## Incompatible theme: GridBulletin - -::: details Expand for answer -The latest version of [GridBulletin](https://wordpress.org/themes/gridbulletin) is incompatible with CommonsBooking. -Problems occur when the footer is enabled. One concrete issue is the missing booking calendar on the item page. From a technical perspective, the required JavaScript sources from CommonsBooking are not being loaded. The root cause within the GridBulletin theme or a solution has not yet been found. -::: - -## Incompatible plugin: All-in-one-Event - -::: details Expand for answer -:::info Fixed since 2.7.2 (06.2022) -For experts see [Issue 675](https://github.com/wielebenwir/commonsbooking/issues/675) -::: - -Unfortunately, using the "All-in-one-Event" plugin at the same time causes errors, so that pages generated by CommonsBooking are not displayed. - -The cause is unfortunately due to poor programming of the All-in-one-Event plugin, which does not adhere to WordPress standards and intervenes so deeply in WordPress that it virtually overwrites the program logic of CommonsBooking. - -We have tried a few things to enable parallel use, but unfortunately have not found a solution yet. - -If you also have the problem, please write directly to the plugin's support, maybe they will adapt their plugin at some point. -::: - -## Incompatible plugin: REDIS Object Cache - -::: details Expand for answer -In connection with the [Cache](../advanced-functionality/), there have been problems with other WordPress plugins such as 'REDIS Object Cache' in the past. For this reason, we advise against using such plugins. - -The pages generated by CommonsBooking should be excluded from optimization by third-party plugins. CommonsBooking uses its own caching. -::: - -## Incompatible plugin: Ultimate Member - -::: details Expand for answer -If you use the Ultimate Member plugin and want to use the "CommonsBooking Manager" user role, you have to check a box in Ultimate Member for the `cb_manager` role to activate it for admin access. -::: - -## Incompatible plugins: Autoptimize / Caching plugins - -::: details Expand for answer -Optimization plugins or other caching plugins can cause CommonsBooking to not display all pages correctly. - -Affected plugins include (incomplete list): -* Autoptimize - -The pages generated by CommonsBooking should be excluded from optimization by third-party plugins. CommonsBooking uses its own caching. - -::: info Have you noticed a problem? -Add incompatible plugins or themes here! -::: -::: diff --git a/docs/en/documentation/faq/site-slow.md b/docs/en/documentation/faq/site-slow.md deleted file mode 100644 index fb7ed4934..000000000 --- a/docs/en/documentation/faq/site-slow.md +++ /dev/null @@ -1,17 +0,0 @@ -# The site is very slow - -## The site is very slow - -::: details Expand for answer -If your CommonsBooking site is very slow, there may be several underlying causes. -We use a technology called caching, which keeps frequently requested data -in temporary storage to save server resources. -Caching may not work under certain conditions, for example when: - - * [WP_DEBUG](https://wordpress.org/documentation/article/debugging-in-wordpress) is enabled; in that case you need to edit your wp-config.php - * The /tmp/ folder on your server is not writable. If that is the case, contact your web host and ask them to make the folder writable. - * If that is not possible, you can set the path for the filesystem cache in the CommonsBooking settings under "Advanced Options". Ask your web host which folders on the server are available for temporary files. - * If that is also not possible: Go to your Site Health screen at (http://YOUR-URL/wp-admin/site-health.php?tab=debug). There you will find the path to your WordPress directory under **Directories**. Alternatively, choose a folder in the format `YOUR_DIRECTORY/symfony` as the cache target. **Warning:** This can cause your WordPress directory to grow very large. - -Alternatively, you can install [Redis](https://redis.io) on your server and let Redis manage the cache. Since Redis stores the cache in RAM instead of the filesystem, it is usually a bit faster. -::: From 337f92507e8b885a3ac740ec597d8ef146a274c5 Mon Sep 17 00:00:00 2001 From: Stefan Bomsdorf Date: Sat, 2 May 2026 14:44:20 +0200 Subject: [PATCH 021/148] Removes hasBookingCodes() and replaces calls by identical function usesBookingCodes(). --- src/Model/Timeframe.php | 9 --------- src/View/BookingCodes.php | 8 ++++---- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/src/Model/Timeframe.php b/src/Model/Timeframe.php index 6b135ce72..0e27f49e5 100644 --- a/src/Model/Timeframe.php +++ b/src/Model/Timeframe.php @@ -1023,15 +1023,6 @@ public function usesBookingCodes(): bool { return $this->getMeta( self::META_CREATE_BOOKING_CODES ) == 'on'; } - /** - * Returns true if booking codes were enabled for this timeframe - * - * @return bool - */ - public function hasBookingCodes(): bool { - return $this->getMeta( 'create-booking-codes' ) == 'on'; - } - /** * Returns repetition-start \DateTime. * This function contains a weird hotfix for full day timeframes. diff --git a/src/View/BookingCodes.php b/src/View/BookingCodes.php index 02a1b917d..93c900ebe 100644 --- a/src/View/BookingCodes.php +++ b/src/View/BookingCodes.php @@ -181,7 +181,7 @@ public static function renderCronEmailFields( $field, $escaped_value, $object_id __( 'Unable to send Emails. No location email(s) configured, check location', 'commonsbooking' ) . sprintf( ' %s', esc_url( get_edit_post_link( $location->ID ) ), commonsbooking_sanitizeHTML( $location->post_title ) ) ); - } elseif ( ! $timeframe->hasBookingCodes() ) { + } elseif ( ! $timeframe->usesBookingCodes() ) { $errMsg = commonsbooking_sanitizeHTML( __( 'This timeframe has no booking codes. To generate booking codes you need to save the timeframe.', 'commonsbooking' ) ); } @@ -290,7 +290,7 @@ public static function renderDirectEmailRow( $field_args, $field ) { __( 'Unable to send Emails. No location email(s) configured, check location', 'commonsbooking' ) . sprintf( ' %s', esc_url( get_edit_post_link( $location->ID ) ), commonsbooking_sanitizeHTML( $location->post_title ) ) ); - } elseif ( ! $timeframe->hasBookingCodes() ) { + } elseif ( ! $timeframe->usesBookingCodes() ) { echo commonsbooking_sanitizeHTML( __( 'This timeframe has no booking codes. To generate booking codes you need to save the timeframe.', 'commonsbooking' ) ); } else { echo ' @@ -386,7 +386,7 @@ public static function renderTable( $timeframeId ) {
-
' . ( $timeframe->hasBookingCodes() ? ' +
' . ( $timeframe->usesBookingCodes() ? ' Download booking codes

' . @@ -410,7 +410,7 @@ public static function renderTable( $timeframeId ) {

'; - if ( $timeframe->hasBookingCodes() ) { + if ( $timeframe->usesBookingCodes() ) { echo self::renderTableFor( 'timeframe_form', $bookingCodes ); echo '
'; From 6811294a3292b73306c85574645da02d428a9ddb Mon Sep 17 00:00:00 2001 From: Stefan Bomsdorf Date: Sun, 3 May 2026 18:08:57 +0200 Subject: [PATCH 022/148] Fixed broken references. --- docs/de/documentation/advanced-functionality/cache.md | 2 +- docs/de/documentation/faq/index.md | 2 +- docs/en/documentation/advanced-functionality/cache.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/de/documentation/advanced-functionality/cache.md b/docs/de/documentation/advanced-functionality/cache.md index 8e280ba5b..b1f37169d 100644 --- a/docs/de/documentation/advanced-functionality/cache.md +++ b/docs/de/documentation/advanced-functionality/cache.md @@ -36,7 +36,7 @@ Ein falsch konfigurierter Cache kann deine Seite verlangsamen. Probiere dann einen anderen Pfad für den Cache oder einen anderen Cache Adapter. * Falls deine Seite sehr langsam ist, kann das auch auf Problem mit dem Cache hindeuten. - Mehr dazu: [Die Seite ist sehr langsam](../faq/site-slow). + Mehr dazu: [Die Seite ist sehr langsam](../faq/index#my-site-is-very-slow-what-can-i-do). * Siehe auch die Seite [Häufige Fragen](../faq/) für bekannte Inkompatibilitäten. * **Regelmäßiges Aufwärmen des Caches durch Cronjob**: diff --git a/docs/de/documentation/faq/index.md b/docs/de/documentation/faq/index.md index 04f65d3fe..3f860026e 100644 --- a/docs/de/documentation/faq/index.md +++ b/docs/de/documentation/faq/index.md @@ -18,7 +18,7 @@ Hier empfiehlt sich ein Plugin wie [Show-Hide/Collapse-Expand](https://de.wordpr ![](/img/item-collapse.png) ::: -## Meine Seite ist sehr langsam – was kann ich tun? +## Meine Seite ist sehr langsam – was kann ich tun? {#my-site-is-very-slow-what-can-i-do} :::: details Antwort anzeigen Wenn deine CommonsBooking Seite sehr langsam ist, kann das verschiedene Gründe haben. diff --git a/docs/en/documentation/advanced-functionality/cache.md b/docs/en/documentation/advanced-functionality/cache.md index 03fa863d0..a6dc8563d 100644 --- a/docs/en/documentation/advanced-functionality/cache.md +++ b/docs/en/documentation/advanced-functionality/cache.md @@ -36,7 +36,7 @@ A misconfigured cache can slow down your site! working properly. In that case, try a different path for the cache or a different cache adapter. * If your site is very slow, this may also indicate a problem with the cache. - More about this: [The site is very slow](../faq/site-slow). + More about this: [The site is very slow](../faq/index#my-site-is-very-slow-what-can-i-do). * **Periodical cache warmup through cron job**: :::warning From ab9fb743818aa0812263d6b63f3c806772c6db9f Mon Sep 17 00:00:00 2001 From: Stefan Bomsdorf Date: Sun, 3 May 2026 20:40:45 +0200 Subject: [PATCH 023/148] Overwrite standard settings for bold menu entry w/out arrow --- docs/.vitepress/config.mts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 9d8091088..a1ae2fa7d 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -273,7 +273,7 @@ export function sidebarDocs_de(): DefaultTheme.SidebarItem[] { { text: 'Häufige Fragen (Version 0.9.x)', link: 'faq' } ] }, - { text: 'Häufige Fragen (FAQ)', link: '/de/documentation/faq/' }, + { text: 'Häufige Fragen (FAQ)', link: '/de/documentation/faq/', items: [] }, ] } @@ -383,7 +383,7 @@ export function sidebarDocs_en(): DefaultTheme.SidebarItem[] { { text: 'Overview of releases and planned further development', link: 'release-overview' } ] }, - { text: 'Frequently Asked Questions (FAQ)', link: '/en/documentation/faq/' }, + { text: 'Frequently Asked Questions (FAQ)', link: '/en/documentation/faq/', items: [] }, ] } From 05508ce48cbb10363b323b410bf92ba913bf27a0 Mon Sep 17 00:00:00 2001 From: Stefan Bomsdorf Date: Mon, 4 May 2026 10:28:25 +0200 Subject: [PATCH 024/148] Adds an "Expand/Collapse all"-button --- docs/.vitepress/components/ExpandAll.vue | 53 ++++++++++++++++++++++++ docs/de/documentation/faq/index.md | 6 +++ docs/en/documentation/faq/index.md | 6 +++ 3 files changed, 65 insertions(+) create mode 100644 docs/.vitepress/components/ExpandAll.vue diff --git a/docs/.vitepress/components/ExpandAll.vue b/docs/.vitepress/components/ExpandAll.vue new file mode 100644 index 000000000..85c12a95b --- /dev/null +++ b/docs/.vitepress/components/ExpandAll.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/docs/de/documentation/faq/index.md b/docs/de/documentation/faq/index.md index 3f860026e..10a8db9eb 100644 --- a/docs/de/documentation/faq/index.md +++ b/docs/de/documentation/faq/index.md @@ -1,7 +1,13 @@ # Häufige Fragen (FAQ) + + Diese Seite ist in zwei Bereiche unterteilt: allgemeine **FAQ** mit häufigen Fragen zur Nutzung, und **Plugin- und Theme-Inkompatibilitäten** mit bekannten Problemen durch Drittanbieter-Software. + + ## Wie bekomme ich den Buchungskommentar auf die Seite und in die Email? ::: details Antwort anzeigen diff --git a/docs/en/documentation/faq/index.md b/docs/en/documentation/faq/index.md index 14ebd1f0b..c00c80376 100644 --- a/docs/en/documentation/faq/index.md +++ b/docs/en/documentation/faq/index.md @@ -1,7 +1,13 @@ # Frequently Asked Questions (FAQ) + + This page is split into two sections: general **FAQ** with common how-to questions, and **Plugin & Theme Incompatibilities** listing known issues with third-party software. + + ## How do I show the booking comment on the page and in the email? ::: details Expand for answer From 85f6da12e0de23b85a8ff0cf028fe640b07da701 Mon Sep 17 00:00:00 2001 From: Stefan Bomsdorf Date: Mon, 4 May 2026 10:31:19 +0200 Subject: [PATCH 025/148] Adds references to anchors in the intro paragraph --- docs/de/documentation/faq/index.md | 6 ++++-- docs/en/documentation/faq/index.md | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/de/documentation/faq/index.md b/docs/de/documentation/faq/index.md index 10a8db9eb..e356491f8 100644 --- a/docs/de/documentation/faq/index.md +++ b/docs/de/documentation/faq/index.md @@ -4,10 +4,12 @@ import ExpandAll from '/.vitepress/components/ExpandAll.vue' -Diese Seite ist in zwei Bereiche unterteilt: allgemeine **FAQ** mit häufigen Fragen zur Nutzung, und **Plugin- und Theme-Inkompatibilitäten** mit bekannten Problemen durch Drittanbieter-Software. +Diese Seite ist in zwei Bereiche unterteilt: [allgemeine **FAQ**](#faq) mit häufigen Fragen zur Nutzung, und [**Plugin- und Theme-Inkompatibilitäten**](#plugin-incompatibilities) mit bekannten Problemen durch Drittanbieter-Software. +## Allgemeine FAQ {#faq} + ## Wie bekomme ich den Buchungskommentar auf die Seite und in die Email? ::: details Antwort anzeigen @@ -110,7 +112,7 @@ Dafür gibt es verschiedene Möglichkeiten (Vorschläge aus der Community): * "Wir nutzen Hcaptcha für wordpress. Nach der Installation in den Einstellungen des Plugins die von euch genutzte Registrierung (z.B. UltimateMember) auswählen. Für die Nutzung muss ein Hcaptcha Account erstellt werden. Sie werben mit Privacy-First und das keine Nutzerdaten verkauft werden. Ich selber habe das nicht geprüft." - [Download aus dem Plugin-Verzeichnis](https://wordpress.org/plugins/hcaptcha-for-forms-and-more) ::: -## Plugin- und Theme-Inkompatibilitäten +## Plugin- und Theme-Inkompatibilitäten {#plugin-incompatibilities} ### Lightstart diff --git a/docs/en/documentation/faq/index.md b/docs/en/documentation/faq/index.md index c00c80376..ca995203d 100644 --- a/docs/en/documentation/faq/index.md +++ b/docs/en/documentation/faq/index.md @@ -4,10 +4,12 @@ import ExpandAll from '/.vitepress/components/ExpandAll.vue' -This page is split into two sections: general **FAQ** with common how-to questions, and **Plugin & Theme Incompatibilities** listing known issues with third-party software. +This page is split into two sections: [general **FAQ**](#faq) with common how-to questions, and [**Plugin & Theme Incompatibilities**](#plugin-incompatibilities) listing known issues with third-party software. +## General FAQ {#faq} + ## How do I show the booking comment on the page and in the email? ::: details Expand for answer @@ -94,7 +96,7 @@ There are several ways to do this (suggestions from the community): * "We use hCaptcha for WordPress. After installation, select the registration you use in the plugin settings (e.g., UltimateMember; by default the built-in WordPress registration should be selected). To use it, you need to create an hCaptcha account. They advertise Privacy-First and that no user data is sold. I have not checked this myself." - [Download from the plugin directory](https://wordpress.org/plugins/hcaptcha-for-forms-and-more) ::: -## Plugin & Theme Incompatibilities +## Plugin & Theme Incompatibilities {#plugin-incompatibilities} ### Lightstart From 88106c2cf9bbc30b7a196d2db64af79483b65ff7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 May 2026 00:00:15 +0200 Subject: [PATCH 026/148] Merge pull request #2182 from wielebenwir/dependabot/npm_and_yarn/wordpress/env-11.5.0 npm(deps-dev): bump @wordpress/env from 11.4.0 to 11.5.0 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0e6cf43ac..b818daec6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ }, "devDependencies": { "@babel/preset-env": "^7.29.2", - "@wordpress/env": "^11.4.0", + "@wordpress/env": "^11.5.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", "cypress": "^15.14.1", "editorconfig": "^3.0.2", @@ -5589,9 +5589,9 @@ } }, "node_modules/@wordpress/env": { - "version": "11.4.0", - "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-11.4.0.tgz", - "integrity": "sha512-Rk25QAVr1diXIT7HPhRSTfyP5s3+dNYSfYEgVyt1HYeO1u5sqHwMBT+KH82HSvfxgPQv4e3JZCK4B+11Bw7ozQ==", + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-11.5.0.tgz", + "integrity": "sha512-JWtSqja0yGa5F2LM5OwFnc0d1nXRXQt6TdGne+jBU5gcRfxj4+c/Sn+fheBFDBU0xLkTsefeJqJSafQZ66F1UA==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 15dcb66b6..35cc6ad84 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "devDependencies": { "@babel/preset-env": "^7.29.2", - "@wordpress/env": "^11.4.0", + "@wordpress/env": "^11.5.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", "cypress": "^15.14.1", "editorconfig": "^3.0.2", From 8df395636bfa89dfebb51828fd4289fa6f63cf9a Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Thu, 7 May 2026 20:45:47 +0200 Subject: [PATCH 027/148] GBFS: made item that base-route iterates over customizable --- src/API/AvailabilityRoute.php | 4 +-- src/API/GBFS/BaseRoute.php | 51 +++++++++++++++++++++++-------- src/Model/CustomPost.php | 8 +++++ src/Repository/BookablePost.php | 6 ++-- src/Repository/Booking.php | 4 +-- src/Repository/Location.php | 2 +- src/Repository/PostRepository.php | 2 ++ 7 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/API/AvailabilityRoute.php b/src/API/AvailabilityRoute.php index 026256be6..5eeecfe3e 100644 --- a/src/API/AvailabilityRoute.php +++ b/src/API/AvailabilityRoute.php @@ -38,12 +38,12 @@ class AvailabilityRoute extends BaseRoute { /** * This retrieves bookable timeframes and the different items assigned, with their respective availability. * - * @param bool $id The id of a {@see \CommonsBooking\Wordpress\CustomPostType\Item::post_type} post to search for + * @param ?int $id The id of a {@see \CommonsBooking\Wordpress\CustomPostType\Item::post_type} post to search for * * @return array * @throws Exception */ - public function getItemData( $id = false ): array { + public static function getItemData( $id = null ): array { $calendar = new Calendar( new Day( date( 'Y-m-d', time() ) ), new Day( date( 'Y-m-d', strtotime( '+2 weeks' ) ) ), // TODO why two weeks? seems like a configurable option diff --git a/src/API/GBFS/BaseRoute.php b/src/API/GBFS/BaseRoute.php index 75b143fcf..327db0bd2 100644 --- a/src/API/GBFS/BaseRoute.php +++ b/src/API/GBFS/BaseRoute.php @@ -4,6 +4,7 @@ namespace CommonsBooking\API\GBFS; use CommonsBooking\Repository\Location; +use CommonsBooking\Repository\PostRepository; use Exception; use stdClass; use WP_REST_Request; @@ -11,10 +12,15 @@ /** * Base class which implements retrieval of basic data attributes of - * GBFS spec. + * GBFS spec. Derive from this class, when you want to have a route that iterates over CustomPosts. * - * Note: When deriving from this class, implement \WP_REST_Controller::prepare_item_for_response, - * which is called in \BaseRoute::getItemData + * Note: When deriving from this class + * - implement \WP_REST_Controller::prepare_item_for_response, + * which is called in \BaseRoute::getItemData + * - implement $rest_base + * - implement $schemaUrl + * - (if necessary) overwrite getRepository + * - (if necessary) overwrite getListName */ class BaseRoute extends \CommonsBooking\API\BaseRoute { @@ -26,12 +32,12 @@ class BaseRoute extends \CommonsBooking\API\BaseRoute { * @return WP_REST_Response */ public function get_items( $request ): WP_REST_Response { - $response = new stdClass(); - $response->data = new stdClass(); - $response->data->stations = $this->getItemData( $request ); - $response->last_updated = date( 'c' ); // ISO-8601 timestamp - $response->ttl = 60; - $response->version = '3.1-RC2'; + $response = new stdClass(); + $response->data = new stdClass(); + $response->data->{static::getListName()} = $this->getItemData( $request ); + $response->last_updated = date( 'c' ); // ISO-8601 timestamp + $response->ttl = 60; + $response->version = '3.1-RC2'; return $this->respond_with_validation( $response ); } @@ -44,12 +50,12 @@ public function get_items( $request ): WP_REST_Response { * @return array */ public function getItemData( $request ): array { - $data = []; - $locations = Location::get(); + $data = []; + $items = static::getRepository()::get(); - foreach ( $locations as $location ) { + foreach ( $items as $item ) { try { - $itemdata = $this->prepare_item_for_response( $location, $request ); + $itemdata = $this->prepare_item_for_response( $item, $request ); $data[] = $itemdata->data; } catch ( Exception $exception ) { if ( WP_DEBUG ) { @@ -60,4 +66,23 @@ public function getItemData( $request ): array { return $data; } + + /** + * Overwrite this, if you don't iterate over stations but need the resulting items in a list with a different name + * + * @return string + */ + protected static function getListName(): string { + return 'stations'; + } + + /** + * The post type that the route will iterate over. + * By default, these are all the locations. + * + * @return PostRepository + */ + protected static function getRepository(): PostRepository { + return new Location(); + } } diff --git a/src/Model/CustomPost.php b/src/Model/CustomPost.php index ec47fd928..0cd2ea4d0 100644 --- a/src/Model/CustomPost.php +++ b/src/Model/CustomPost.php @@ -29,6 +29,13 @@ class CustomPost { */ protected $post; + /** + * The post ID of the WordPress post + * + * @var int + */ + protected int $ID; + /** * @var string */ @@ -49,6 +56,7 @@ public function __construct( $post ) { } else { throw new Exception( 'Invalid post param. Needed WP_Post or ID (int)' ); } + $this->ID = $this->post->ID; } /** diff --git a/src/Repository/BookablePost.php b/src/Repository/BookablePost.php index 924eed4a6..a0203edce 100644 --- a/src/Repository/BookablePost.php +++ b/src/Repository/BookablePost.php @@ -217,9 +217,9 @@ abstract protected static function getModelClass(); * @param array $args WP Post args * @param bool $bookable * - * @return array + * @return \CommonsBooking\Model\Location[]|\CommonsBooking\Model\Item[] */ - public static function get( array $args = array(), bool $bookable = false ) { + public static function get( array $args = array(), bool $bookable = false ): array { $posts = []; $args['post_type'] = static::getPostType(); $args['nopaging'] = true; @@ -273,7 +273,7 @@ public static function get( array $args = array(), bool $bookable = false ) { * @param $relatedType * @param bool $bookable * - * @return int[] Array of post ids + * @return \CommonsBooking\Model\Location[] | \CommonsBooking\Model\Item[] * @throws Exception */ protected static function getByRelatedPost( $postId, $originType, $relatedType, bool $bookable = false ): array { diff --git a/src/Repository/Booking.php b/src/Repository/Booking.php index 2fb725d54..a85394379 100644 --- a/src/Repository/Booking.php +++ b/src/Repository/Booking.php @@ -351,8 +351,8 @@ public static function getForCurrentUser( * Returns bookings. This uses the CommonsBooking\Repository\Timeframe::get() method which * is not based on the WP_Query class but will perform its own SQL query. * - * @param array $locations - * @param array $items + * @param array $locations an array of post IDs + * @param array $items an array of post IDs * @param string|null $date Date-String in format YYYY-mm-dd * @param bool $returnAsModel if true, returns booking model, if false return int array (defaults to false) * @param int|null $minTimestamp diff --git a/src/Repository/Location.php b/src/Repository/Location.php index ae3b881c1..3f448c461 100644 --- a/src/Repository/Location.php +++ b/src/Repository/Location.php @@ -13,7 +13,7 @@ class Location extends BookablePost { * * @param bool $bookable * - * @return array + * @return \CommonsBooking\Model\Location[] * @throws Exception */ public static function getByItem( $itemId, bool $bookable = false ): array { diff --git a/src/Repository/PostRepository.php b/src/Repository/PostRepository.php index 16135751a..e8a73b2f7 100644 --- a/src/Repository/PostRepository.php +++ b/src/Repository/PostRepository.php @@ -57,4 +57,6 @@ public static function getPostById( $postId ) { return $post; } } + + abstract public static function get( array $args = array() ): array; } From 1197864c3c1b1170de4c269069ca985687772313 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Thu, 7 May 2026 20:46:27 +0200 Subject: [PATCH 028/148] add doccomments to timeframe model constants --- src/Model/Timeframe.php | 78 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/src/Model/Timeframe.php b/src/Model/Timeframe.php index 0e27f49e5..734bbba34 100644 --- a/src/Model/Timeframe.php +++ b/src/Model/Timeframe.php @@ -28,46 +28,119 @@ class Timeframe extends CustomPost { */ public const ERROR_TYPE = 'timeframeValidationFailed'; + /** + * The error type that occurs, when a timeframe has bookings that have been orphaned. through items changing locations. + * The user is notified about this, so that they can move the bookings using Service::MassOperations. + */ public const ORPHANED_TYPE = 'timeframehasOrphanedBookings'; + /** + * The metafield that stores the timestamp (int) for when the timeframe starts. + */ public const REPETITION_START = 'repetition-start'; + /** + * The metafield that stores the timestamp (int) for when the timeframe ends. + */ public const REPETITION_END = 'repetition-end'; + /** + * The meta field for what kind of selection type is used to select the item. + * Value is either one of self::SELECTION_MANUAL_ID , self::SELECTION_CATEGORY_ID or self::SELECTION_ALL_ID + */ public const META_ITEM_SELECTION_TYPE = 'item-select'; + /** + * The metafield for the item post id associated with the timeframe. + */ public const META_ITEM_ID = 'item-id'; + /** + * The metafield where a serialized array of post IDs (multiple) of items associated with the timeframe is stored + */ public const META_ITEM_ID_LIST = 'item-id-list'; + /** + * The metafield where a serialized array of term_ids that make up the categories from which the items associated with the timeframe are stored. + */ public const META_ITEM_CATEGORY_IDS = 'item-category-ids'; + /** + * The meta field for what kind of selection type is used to select the location. + * Value is either one of self::SELECTION_MANUAL_ID , self::SELECTION_CATEGORY_ID or self::SELECTION_ALL_ID + */ public const META_LOCATION_SELECTION_TYPE = 'location-select'; + /** + * The metafield for the location post id associated with the timeframe. + */ public const META_LOCATION_ID = 'location-id'; + /** + * The metafield where a serialized array of post IDs (multiple) of locations associated with the timeframe is stored + */ public const META_LOCATION_ID_LIST = 'location-id-list'; + /** + * The metafield where a serialized array of term_ids that make up the categories from which the locaations associated with the timeframe are stored. + */ public const META_LOCATION_CATEGORY_IDS = 'location-category-ids'; + /** + * Metafield for what type of repetition the timeframe uses. + * For possible values @see Timeframe::getRepetition() + */ public const META_REPETITION = 'timeframe-repetition'; + /** + * Metafield for how many days in advance the item on that timeframe can be booked. + * When this is limited to for example 30 days, only the next 30 days can be booked. + */ public const META_TIMEFRAME_ADVANCE_BOOKING_DAYS = 'timeframe-advance-booking-days'; + /** + * Metafield for the maximum length in days a booking on this timeframe may have. + */ public const META_MAX_DAYS = 'timeframe-max-days'; + /** + * A possible meta_value for META_ITEM_SELECTION_TYPE and META_LOCATION_SELECTION_TYPE + * This value implies, that posts are individually selected from a list of posts. + */ public const SELECTION_MANUAL_ID = 0; + /** + * A possible meta_value for META_ITEM_SELECTION_TYPE and META_LOCATION_SELECTION_TYPE + * This value implies, that the user selects a category of posts that the timeframe applies to. + */ public const SELECTION_CATEGORY_ID = 1; + /** + * A possible meta_value for META_ITEM_SELECTION_TYPE and META_LOCATION_SELECTION_TYPE + * This value implies, that the timeframe applies to all items / locations of the instance. + */ public const SELECTION_ALL_ID = 2; + /** + * A metafield with an on/off value determining if booking codes shall be created for the timeframe (only bookable timeframes). + */ public const META_CREATE_BOOKING_CODES = 'create-booking-codes'; + /** + * A metafield that defines how many days in advance the user HAS to book an item. This means, that the location often needs some kind of + * booking ahead, and that an item cannot be booked at the same day. Integer value in days. + */ public const META_BOOKING_START_DAY_OFFSET = 'booking-startday-offset'; + /** + * A metafield with an on/off value determining if the booking codes generated in the timeframe shall also be shown to the user. + */ public const META_SHOW_BOOKING_CODES = 'show-booking-codes'; + /** + * A metafield that stores a serialized array of strings with slugs of user roles that are allowed to book this item. When this is empty, + * all user roles may book this item. + */ public const META_ALLOWED_USER_ROLES = 'allowed_user_roles'; /** @@ -75,7 +148,10 @@ class Timeframe extends CustomPost { * Example: 2020-01-01,2020-01-02,2020-01-03 */ public const META_MANUAL_SELECTION = 'timeframe_manual_date'; - const MAX_DAYS_DEFAULT = 3; + /** + * The default value for self::META_MAX_DAYS. + */ + const MAX_DAYS_DEFAULT = 3; /** * null means the data is not fetched yet From 8915700f706cd312d1cd4ca1aa7581ba4e437748 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Thu, 7 May 2026 20:56:49 +0200 Subject: [PATCH 029/148] add getLocation to Item model to retrieve currently stationed location --- src/Model/Item.php | 30 ++++++++++++++++++ src/View/Booking.php | 35 ++++++++++----------- tests/php/Model/ItemTest.php | 59 ++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 19 deletions(-) diff --git a/src/Model/Item.php b/src/Model/Item.php index 25aeae158..37d956be5 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -81,4 +81,34 @@ public function getRestrictions(): array { true ); } + /** + * Will get the location that the item is currently stationed at and bookable. + * Will take into account the current time, the item can have timeframes + * at multiple locations but can only be at one location at a time. + * + * @return ?Location will return null when no Location was found + */ + public function getLocation(): ?Location { + $locations = \CommonsBooking\Repository\Location::getByItem( $this->ID, true ); + + if ( empty( $locations ) ) { + return null; + } + + if ( count( $locations ) === 1 ) { + return reset( $locations ); + } + + $timeframes = []; + foreach ( $locations as $location ) { + $timeframes = array_merge( + $timeframes, + $location->getBookableTimeframesByItem( $this->ID, true ) + ); + } + $closestTimeframe = \CommonsBooking\View\Calendar::getClosestBookableTimeFrameForToday( $timeframes ); + + return $closestTimeframe?->getLocation();// why I used a deprecated method here: https://github.com/wielebenwir/commonsbooking/issues/507#issuecomment-4235848408 + } + } diff --git a/src/View/Booking.php b/src/View/Booking.php index 0c3ded1dc..2bdfa4124 100755 --- a/src/View/Booking.php +++ b/src/View/Booking.php @@ -344,9 +344,15 @@ public static function getLocationForItem_AJAX() { try { $itemModel = new \CommonsBooking\Model\Item( $itemID ); - $location = \CommonsBooking\Repository\Location::getByItem( $itemID, true ); - // pick the first location, no matter what - $location = reset( $location ); + $location = $itemModel->getLocation(); + if ( ! $location ) { + // This won't be displayed anywhere + wp_send_json_error( + array( + 'message' => 'No location found for this item.', + ) + ); + } $timeframe = Timeframe::getBookable( [ $location->ID ], [ $itemID ], @@ -363,22 +369,13 @@ public static function getLocationForItem_AJAX() { ) ); } - if ( $location ) { - wp_send_json( - array( - 'success' => true, - 'locationID' => $location->ID, - 'fullDay' => $timeframe->isFullDay(), - ) - ); - } else { - // This won't be displayed anywhere - wp_send_json_error( - array( - 'message' => 'No location found for this item.', - ) - ); - } + wp_send_json( + array( + 'success' => true, + 'locationID' => $location->ID, + 'fullDay' => $timeframe->isFullDay(), + ) + ); } /** diff --git a/tests/php/Model/ItemTest.php b/tests/php/Model/ItemTest.php index abfa1c997..05d865de8 100644 --- a/tests/php/Model/ItemTest.php +++ b/tests/php/Model/ItemTest.php @@ -55,6 +55,65 @@ public function testGetRestrictions() { } */ + public function testGetLocation() { + $dt = new \DateTime( self::CURRENT_DATE ); + ClockMock::freeze( $dt ); + + // just one item that is currently bookable + $this->assertEquals( $this->locationId, $this->itemModel->getLocation()->ID ); + + // in two weeks, the timeframe is expired, so the item will not be at the location anymore + $dt->modify( '+2 weeks' ); + ClockMock::freeze( $dt ); + $this->assertNull( $this->itemModel->getLocation() ); + + // item that is in location A monday-thursday and in location B friday-sunday. Position should change depending on the day of the week + $locationA = $this->createLocation( 'location a' ); + $locationB = $this->createLocation( 'location b' ); + $movingItem = $this->createItem( 'location changing item' ); + $movingItemModel = new Item( $movingItem ); + $tf1 = new Timeframe( + $this->createTimeframe( + $locationA, + $movingItem, + strtotime( '-1 day', strtotime( \CommonsBooking\Tests\Wordpress\CustomPostTypeTest::CURRENT_DATE ) ), + strtotime( '+14 days', strtotime( \CommonsBooking\Tests\Wordpress\CustomPostTypeTest::CURRENT_DATE ) ), + \CommonsBooking\Wordpress\CustomPostType\Timeframe::BOOKABLE_ID, + '', + 'w', + 0, + '8:00 AM', + '12:00 PM', + 'publish', + [ '1','2','3','4' ] + ) + ); + $tf2 = new Timeframe( + $this->createTimeframe( + $locationB, + $movingItem, + strtotime( '-1 day', strtotime( \CommonsBooking\Tests\Wordpress\CustomPostTypeTest::CURRENT_DATE ) ), + strtotime( '+14 days', strtotime( \CommonsBooking\Tests\Wordpress\CustomPostTypeTest::CURRENT_DATE ) ), + \CommonsBooking\Wordpress\CustomPostType\Timeframe::BOOKABLE_ID, + '', + 'w', + 0, + '8:00 AM', + '12:00 PM', + 'publish', + [ '5','6','7' ] + ) + ); + $this->assertFalse( $tf1->overlaps( $tf2 ) ); + $dt = new \DateTime( self::CURRENT_DATE ); + $dt->modify( 'monday' ); + ClockMock::freeze( $dt ); + $this->assertEquals( $locationA, $movingItemModel->getLocation()->ID ); + $dt->modify( 'friday' ); + ClockMock::freeze( $dt ); + $this->assertEquals( $locationB, $movingItemModel->getLocation()->ID ); + } + protected function setUp(): void { parent::setUp(); $this->restrictionIds[] = $this->createRestriction( From e24c03abd712d763c6ebac8eb0fb33e1421f1861 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Thu, 7 May 2026 21:02:34 +0200 Subject: [PATCH 030/148] GBFS: start day offset now not factored in availability, bc those items would ahave never been shown --- src/API/GBFS/StationStatus.php | 56 +++--------------- src/Model/Calendar.php | 14 ++++- src/Model/Item.php | 33 +++++++++++ .../API/GBFS/StationInformationRouteTest.php | 2 +- tests/php/API/GBFS/StationStatusRouteTest.php | 8 +-- .../API/GBFS/SystemInformationRouteTest.php | 3 - tests/php/Model/ItemTest.php | 57 +++++++++++++++++++ 7 files changed, 117 insertions(+), 56 deletions(-) diff --git a/src/API/GBFS/StationStatus.php b/src/API/GBFS/StationStatus.php index 85221c454..7fcb10593 100644 --- a/src/API/GBFS/StationStatus.php +++ b/src/API/GBFS/StationStatus.php @@ -3,9 +3,6 @@ namespace CommonsBooking\API\GBFS; -use CommonsBooking\Helper\Wordpress; -use CommonsBooking\Model\Calendar; -use CommonsBooking\Model\Day; use CommonsBooking\Model\Location; use CommonsBooking\Repository\Item; use stdClass; @@ -28,16 +25,21 @@ class StationStatus extends BaseRoute { protected $schemaUrl = COMMONSBOOKING_PLUGIN_DIR . 'includes/gbfs-json-schema/station_status.json'; /** - * @param Location $item + * @param Location $location * @param $request * * @return WP_REST_Response * @throws \Exception */ - public function prepare_item_for_response( $item, $request ): WP_REST_Response { + public function prepare_item_for_response( $location, $request ): WP_REST_Response { $preparedItem = new stdClass(); - $preparedItem->station_id = $item->ID . ''; - $preparedItem->num_vehicles_available = $this->getItemCountAtLocation( $item->ID ); + $preparedItem->station_id = strval( $location->ID ); + $preparedItem->num_vehicles_available = count( + array_filter( + Item::getByLocation( $location->ID, true ), + fn( $item ) => $item->isCurrentlyFreeAtLocation( $location->ID ) + ) + ); $preparedItem->is_installed = true; $preparedItem->is_renting = true; $preparedItem->is_returning = true; @@ -45,44 +47,4 @@ public function prepare_item_for_response( $item, $request ): WP_REST_Response { return new WP_REST_Response( $preparedItem ); } - - /** - * Will get the amount of items that are currently in the location - * and marked as "green" (bookable right now by the user) for the current time. - * This purposefully excludes items that have a Holiday Timeframe, are bookable in advance - * or can only be booked through overbooking. - * This is because the GBFS spec only accounts for items available in that instant. - * - * @param int $locationId - * - * @return int - * @throws \Exception - */ - private function getItemCountAtLocation( $locationId ): int { - $items = Item::getByLocation( $locationId, true ); - $nowDT = Wordpress::getUTCDateTimeByTimestamp( current_time( 'timestamp' ) ); - $availableCounter = 0; - foreach ( $items as $item ) { - // we have to make our calendar span at least one day, otherwise we get no results - $itemCalendar = new Calendar( - new Day( date( 'Y-m-d', strtotime( '-1 day' ) ) ), - new Day( date( 'Y-m-d', strtotime( '+1 day' ) ) ), - [ $locationId ], - [ $item->ID ] - ); - $availabilitySlots = $itemCalendar->getAvailabilitySlots(); - // we have to iterate over multiple slots because the calendar will give us more than we asked for - foreach ( $availabilitySlots as $availabilitySlot ) { - // match our exact current time to the slot - $startDT = new \DateTime( $availabilitySlot->start ); - $endDT = new \DateTime( $availabilitySlot->end ); - if ( $nowDT >= $startDT && $nowDT <= $endDT ) { - ++$availableCounter; - // break out of the loop, we only need one match of availability per item - break; - } - } - } - return $availableCounter; - } } diff --git a/src/Model/Calendar.php b/src/Model/Calendar.php index 806b52feb..713fa8505 100644 --- a/src/Model/Calendar.php +++ b/src/Model/Calendar.php @@ -45,6 +45,14 @@ class Calendar { */ protected array $timeframes; + /** + * When this is enabled, @see Timeframe::META_BOOKING_START_DAY_OFFSET is ignored. + * This is used for the API routes, where we want to show the actual availability of the items, regardless of the booking start day offset. + * + * @var bool + */ + protected bool $ignoreStartDayOffset = false; + /** * Calendar constructor. * @@ -149,7 +157,7 @@ public function getAvailabilitySlots(): array { } // Skip timeframes that are not bookable today - if ( $timeframe->getFirstBookableDay() > $day->getDate() ) { + if ( ! $this->ignoreStartDayOffset && $timeframe->getFirstBookableDay() > $day->getDate() ) { continue; } @@ -185,4 +193,8 @@ public function getAvailabilitySlots(): array { } return $slots; } + + public function setIgnoreStartDayOffset( bool $ignoreStartDayOffset ): void { + $this->ignoreStartDayOffset = $ignoreStartDayOffset; + } } diff --git a/src/Model/Item.php b/src/Model/Item.php index 37d956be5..672184a2b 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -111,4 +111,37 @@ public function getLocation(): ?Location { return $closestTimeframe?->getLocation();// why I used a deprecated method here: https://github.com/wielebenwir/commonsbooking/issues/507#issuecomment-4235848408 } + /** + * Determines whether this item is currently free at a given location. + * Free is the opposite of rented. Checks against live availability slots, so it excludes items with Holiday + * Timeframes or overbooking-only availability, although they are technically not rented during these periods. + * + * This method will include items that may only be booked in advance (\CommonsBooking\Model\Timeframe::META_TIMEFRAME_ADVANCE_BOOKING_DAYS), + * because they are technically available at this location. Just not for pickup right now. + * + * @param int $locationId + * + * @return bool true if the item is free right now, false otherwise + * @throws \Exception + */ + public function isCurrentlyFreeAtLocation( int $locationId ): bool { + $nowDT = Wordpress::getUTCDateTimeByTimestamp( current_time( 'timestamp' ) ); + $itemCalendar = new Calendar( + new Day( date( 'Y-m-d', strtotime( '-1 day' ) ) ), + new Day( date( 'Y-m-d', strtotime( '+1 day' ) ) ), + [ $locationId ], + [ $this->ID ] + ); + $itemCalendar->setIgnoreStartDayOffset( true ); + + foreach ( $itemCalendar->getAvailabilitySlots() as $availabilitySlot ) { + $startDT = new \DateTime( $availabilitySlot->start ); + $endDT = new \DateTime( $availabilitySlot->end ); + if ( $nowDT >= $startDT && $nowDT <= $endDT ) { + return true; + } + } + + return false; + } } diff --git a/tests/php/API/GBFS/StationInformationRouteTest.php b/tests/php/API/GBFS/StationInformationRouteTest.php index dfd211d8c..465af31fd 100644 --- a/tests/php/API/GBFS/StationInformationRouteTest.php +++ b/tests/php/API/GBFS/StationInformationRouteTest.php @@ -53,7 +53,7 @@ public function setUp(): void { $this->locationId = $this->createLocation( 'Test Location', 'publish' ); $this->itemId = $this->createItem( 'TestItem', 'publish' ); - $this->timeframe = $this->createTimeframe( + $this->createTimeframe( $this->locationId, $this->itemId, strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), diff --git a/tests/php/API/GBFS/StationStatusRouteTest.php b/tests/php/API/GBFS/StationStatusRouteTest.php index d3dfad0ee..681d17e89 100644 --- a/tests/php/API/GBFS/StationStatusRouteTest.php +++ b/tests/php/API/GBFS/StationStatusRouteTest.php @@ -84,7 +84,7 @@ public function testStationStatus_withBookingOffset() { 2 ); - // with offset → unavailable + // with offset → still counted as available because it is not booked $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); $response = rest_do_request( $request ); $data = $response->get_data()->data; @@ -97,9 +97,9 @@ function ( $station ) use ( $otherLocationId ) { } ) ); - $this->assertEquals( 0, $relevantStation->num_vehicles_available ); + $this->assertEquals( 1, $relevantStation->num_vehicles_available ); - // remove offset → available + // remove offset → still available update_post_meta( $timeframeID, \CommonsBooking\Model\Timeframe::META_BOOKING_START_DAY_OFFSET, 0 ); $response = rest_do_request( $request ); @@ -123,7 +123,7 @@ public function setUp(): void { $this->locationId = $this->createLocation( 'Testlocation', 'publish' ); $this->itemId = $this->createItem( 'TestItem', 'publish' ); - $this->timeframe = $this->createTimeframe( + $this->createTimeframe( $this->locationId, $this->itemId, strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), diff --git a/tests/php/API/GBFS/SystemInformationRouteTest.php b/tests/php/API/GBFS/SystemInformationRouteTest.php index 0988126c7..40e96b2b3 100644 --- a/tests/php/API/GBFS/SystemInformationRouteTest.php +++ b/tests/php/API/GBFS/SystemInformationRouteTest.php @@ -4,9 +4,6 @@ use CommonsBooking\Tests\API\CB_REST_Route_UnitTestCase; -/** - * TODO: add result unit test - */ class SystemInformationRouteTest extends CB_REST_Route_UnitTestCase { protected $ENDPOINT = '/commonsbooking/v1/system_information.json'; diff --git a/tests/php/Model/ItemTest.php b/tests/php/Model/ItemTest.php index 05d865de8..579fd0133 100644 --- a/tests/php/Model/ItemTest.php +++ b/tests/php/Model/ItemTest.php @@ -114,6 +114,63 @@ public function testGetLocation() { $this->assertEquals( $locationB, $movingItemModel->getLocation()->ID ); } + public function testIsCurrentlyFreeAtLocation() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + + // Item has a bookable timeframe including today, should be free + $this->assertTrue( $this->itemModel->isCurrentlyFreeAtLocation( $this->locationId ) ); + + // A confirmed booking starting today means the item is now rented + $this->createConfirmedBookingStartingToday(); + $this->assertFalse( $this->itemModel->isCurrentlyFreeAtLocation( $this->locationId ) ); + + // In two weeks, the timeframe is expired, should no longer be free + $dt = new \DateTime( self::CURRENT_DATE ); + $dt->modify( '+2 weeks' ); + ClockMock::freeze( $dt ); + $this->assertFalse( $this->itemModel->isCurrentlyFreeAtLocation( $this->locationId ) ); + + // Wrong location should not be free + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + $otherLocationId = $this->createLocation( 'other location' ); + $this->assertFalse( $this->itemModel->isCurrentlyFreeAtLocation( $otherLocationId ) ); + } + + public function testIsCurrentlyFreeAtLocation_withBookingOffset() { + $otherLocationId = $this->createLocation( 'Other Location' ); + $otherItemId = $this->createItem( 'Other Item' ); + $otherItemModel = new Item( $otherItemId ); + + $timeframeId = $this->createTimeframe( + $otherLocationId, + $otherItemId, + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ), + \CommonsBooking\Wordpress\CustomPostType\Timeframe::BOOKABLE_ID, + 'on', + 'd', + 0, + '8:00 AM', + '12:00 PM', + 'publish', + [], + '', + CustomPostTypeTest::USER_ID, + 3, // booking start day offset + 30, + 2 + ); + + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + + // With offset → item is still free, it's just not possible to pick it up right now + $this->assertTrue( $otherItemModel->isCurrentlyFreeAtLocation( $otherLocationId ) ); + + // Remove offset → still free, no change in rental status + update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_BOOKING_START_DAY_OFFSET, 0 ); + $this->assertTrue( $otherItemModel->isCurrentlyFreeAtLocation( $otherLocationId ) ); + } + protected function setUp(): void { parent::setUp(); $this->restrictionIds[] = $this->createRestriction( From 410f97cfd57deecf926ad64277bc64904c0aee78 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Thu, 7 May 2026 21:03:53 +0200 Subject: [PATCH 031/148] tests: add additional unit test to assert empty calendar state --- tests/php/Model/CalendarTest.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/php/Model/CalendarTest.php b/tests/php/Model/CalendarTest.php index 65481071b..ae414af6a 100644 --- a/tests/php/Model/CalendarTest.php +++ b/tests/php/Model/CalendarTest.php @@ -92,6 +92,22 @@ public function testGetAvailabilitySlots() { ], ]; $this->assertEquals( $expectedSlotObject, $availabilitySlots ); + + // book the other day too, assert an empty + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( $tomorrow ), + $tomorrowEnd + ); + // recreate the calendar object to get the updated availability + $this->calendar = new Calendar( + new Day( $today, [ $this->locationId ], [ $this->itemId ] ), + new Day( $tomorrow, [ $this->locationId ], [ $this->itemId ] ), + [ $this->locationId ], + [ $this->itemId ] + ); + $this->assertEmpty( $this->calendar->getAvailabilitySlots() ); } public function testGetAvailabilitySlotsWithHourlyTimeframe() { From 55b1f3b029d80a24b505fc24bfbc3d93aa29323e Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Thu, 7 May 2026 21:05:00 +0200 Subject: [PATCH 032/148] GBFS: change string conversion to always use strval --- src/API/GBFS/StationInformation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/API/GBFS/StationInformation.php b/src/API/GBFS/StationInformation.php index 807cffaee..e3ea84ccc 100644 --- a/src/API/GBFS/StationInformation.php +++ b/src/API/GBFS/StationInformation.php @@ -35,7 +35,7 @@ class StationInformation extends BaseRoute { */ public function prepare_item_for_response( $item, $request ): WP_REST_Response { $preparedItem = new stdClass(); - $preparedItem->station_id = $item->ID . ''; + $preparedItem->station_id = strval( $item->ID ); $preparedItem->name = [ (object) [ 'text' => $item->post_title, From 173d7c22b054d4aa2e257362c12fef9ccbcd0a2e Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Thu, 7 May 2026 21:18:38 +0200 Subject: [PATCH 033/148] GBFS: add vehicle_status route --- includes/gbfs-json-schema/vehicle_status.json | 153 ++++++++++++++++++ src/API/GBFS/Discovery.php | 1 + src/API/GBFS/VehicleStatus.php | 56 +++++++ src/Model/Item.php | 66 ++++++++ src/Plugin.php | 4 + src/Repository/Item.php | 62 +++++++ tests/php/API/GBFS/VehicleStatusRouteTest.php | 75 +++++++++ tests/php/Model/ItemTest.php | 64 ++++++++ tests/php/Repository/ItemTest.php | 26 ++- 9 files changed, 503 insertions(+), 4 deletions(-) create mode 100644 includes/gbfs-json-schema/vehicle_status.json create mode 100644 src/API/GBFS/VehicleStatus.php create mode 100644 tests/php/API/GBFS/VehicleStatusRouteTest.php diff --git a/includes/gbfs-json-schema/vehicle_status.json b/includes/gbfs-json-schema/vehicle_status.json new file mode 100644 index 000000000..6cefa91d1 --- /dev/null +++ b/includes/gbfs-json-schema/vehicle_status.json @@ -0,0 +1,153 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "$id": + "https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC2/vehicle_status.json", + "description": + "Describes the vehicles that are available for rent (as of v3.0, formerly free_bike_status).", + "type": "object", + "properties": { + "last_updated": { + "description": + "Last time the data in the feed was updated in RFC3339 format.", + "type": "string", + "format": "date-time" + }, + "ttl": { + "description": + "Number of seconds before the data in the feed will be updated again (0 if the data should always be refreshed).", + "type": "integer", + "minimum": 0 + }, + "version": { + "description": + "GBFS version number to which the feed conforms, according to the versioning framework (added in v1.1).", + "type": "string", + "const": "3.1-RC2" + }, + "data": { + "description": + "Array that contains one object per vehicle as defined below.", + "type": "object", + "properties": { + "vehicles": { + "type": "array", + "items": { + "type": "object", + "properties": { + "vehicle_id": { + "description": "Rotating (as of v2.0) identifier of a vehicle.", + "type": "string" + }, + "lat": { + "description": "The latitude of the vehicle.", + "type": "number", + "minimum": -90, + "maximum": 90 + }, + "lon": { + "description": "The longitude of the vehicle.", + "type": "number", + "minimum": -180, + "maximum": 180 + }, + "is_reserved": { + "description": "Is the vehicle currently reserved?", + "type": "boolean" + }, + "is_disabled": { + "description": "Is the vehicle currently disabled (broken)?", + "type": "boolean" + }, + "rental_uris": { + "description": "Contains rental uris for Android, iOS, and web in the android, ios, and web fields (added in v1.1).", + "type": "object", + "properties": { + "android": { + "description": "URI that can be passed to an Android app with an intent (added in v1.1).", + "type": "string", + "format": "uri" + }, + "ios": { + "description": "URI that can be used on iOS to launch the rental app for this vehicle (added in v1.1).", + "type": "string", + "format": "uri" + }, + "web": { + "description": "URL that can be used by a web browser to show more information about renting this vehicle (added in v1.1).", + "type": "string", + "format": "uri" + } + } + }, + "vehicle_type_id": { + "description": "The vehicle_type_id of this vehicle (added in v2.1-RC).", + "type": "string" + }, + "last_reported": { + "description": "The last time this vehicle reported its status to the operator's backend in RFC3339 format (added in v2.1-RC).", + "type": "string", + "format": "date-time" + }, + "current_range_meters": { + "description": "The furthest distance in meters that the vehicle can travel without recharging or refueling with the vehicle's current charge or fuel (added in v2.1-RC).", + "type": "number", + "minimum": 0 + }, + "current_fuel_percent": { + "description": "This value represents the current percentage, expressed from 0 to 1, of fuel or battery power remaining in the vehicle. Added in v2.3-RC.", + "type": "number", + "minimum": 0, + "maximum": 1 + }, + "station_id": { + "description": "Identifier referencing the station_id if the vehicle is currently at a station (added in v2.1-RC2).", + "type": "string" + }, + "home_station_id": { + "description": "The station_id of the station this vehicle must be returned to (added in v2.3-RC).", + "type": "string" + }, + "pricing_plan_id": { + "description": "The plan_id of the pricing plan this vehicle is eligible for (added in v2.2).", + "type": "string" + }, + "vehicle_equipment": { + "description": "List of vehicle equipment provided by the operator in addition to the accessories already provided in the vehicle. Added in v2.3.", + "type": "array", + "items": { + "enum": ["child_seat_a", "child_seat_b", "child_seat_c", "winter_tires", "snow_chains"] + } + }, + "available_until": { + "description": "The date and time when any rental of the vehicle must be completed. Added in v2.3.", + "type": "string", + "pattern": "^([0-9]{4})-([0-9]{2})-([0-9]{2})T([0-9]{2}):([0-9]{2}):([0-9]{2})(([+-]([0-9]{2}):([0-9]{2}))|Z)$" + } + }, + "anyOf": [ + { + "required": ["lat", "lon"], + "errorMessage": "Both 'lat' and 'lon' are required." + }, + { + "required": ["station_id"], + "properties": { + "lat": { + "not": {} + }, + "lon": { + "not": {} + } + }, + "errorMessage": "'station_id' is required if 'lat' and 'lon' are not present." + } + ], + "required": ["vehicle_id", "is_reserved", "is_disabled"] + } + } + }, + "required": ["vehicles"] + } + }, + "required": ["last_updated", "ttl", "version", "data"] +} diff --git a/src/API/GBFS/Discovery.php b/src/API/GBFS/Discovery.php index 5bdad3964..b8a9a540a 100644 --- a/src/API/GBFS/Discovery.php +++ b/src/API/GBFS/Discovery.php @@ -49,6 +49,7 @@ public function get_items( $request ): WP_REST_Response { 'system_information', 'station_information', 'station_status', + 'vehicle_status', ] ); $feeds = array_map( fn( $feed ) => $this->get_feed( $feed ), $raw_feeds ); diff --git a/src/API/GBFS/VehicleStatus.php b/src/API/GBFS/VehicleStatus.php new file mode 100644 index 000000000..5682f8a30 --- /dev/null +++ b/src/API/GBFS/VehicleStatus.php @@ -0,0 +1,56 @@ +vehicle_id = strval( $item->getCloakedId() ); + $preparedItem->station_id = strval( $item->getLocation()?->ID ); + $preparedItem->is_reserved = ! $item->isCurrentlyFreeAtLocation( intval( $preparedItem->station_id ) ); + $preparedItem->is_disabled = $item->getLocation() === null; + $preparedItem->rental_uris = (object) [ + 'web' => $item->getCloakedURL(), + ]; + // $preparedItem->available_until //TODO The date and time when any rental of the vehicle must be completed. The vehicle must be returned and made available for the next user by this time. If this field is empty, it indicates that the vehicle is available indefinitely. This field SHOULD be published by carsharing or other mobility systems where vehicles can be booked in advance for future travel. + + return new WP_REST_Response( $preparedItem ); + } + + protected static function getListName(): string { + return 'vehicles'; + } + + + protected static function getRepository(): PostRepository { + // we iterate over posts with cb_item post type + return new Item(); + } +} diff --git a/src/Model/Item.php b/src/Model/Item.php index 672184a2b..7abf17c82 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -4,6 +4,7 @@ namespace CommonsBooking\Model; use CommonsBooking\Helper\Helper; +use CommonsBooking\Helper\Wordpress; use CommonsBooking\Repository\Timeframe; use Exception; @@ -81,6 +82,71 @@ public function getRestrictions(): array { true ); } + + /** + * Will get a rotating ID by which the vehicle can be identified. + * The ID rotates after every trip and can be used to publish a vehicle ID to the GBFS API. + * + * The GBFS spec demands, that a vehicle ID must be rotated after each trip so that the users cannot be profiled. + * This needs to be deterministic and reversible. + * + * The ID should be reversible, so that we can get a deep link to the item that you found in the feed. + * + * Inspired by: https://tier.engineering/How-we-anonymize-user-trips-on-public-APIs + * Difference: We don't care about anonymity as much, because we don't offer A -> B trips. + * + * This function is probably not secure, wp_hash uses md5 encryption. + * + * @return string - a rotating ID for a vehicle + */ + public function getCloakedId(): string { + $closestBooking = $this->getClosestBooking(); + $secondHash = $closestBooking->post_name ?? $this->post_name; // If there is a booking, hash that. Otherwise, get the post name of the item as second hash item + + return wp_hash( $this->ID . $secondHash ); + } + + /** + * Gets the permalink for an item as a cloaked URL to be published in the API. + * + * @return string + */ + public function getCloakedURL(): string { + return add_query_arg( + array( + \CommonsBooking\Repository\Item::QUERY_VEHICLE_ID => $this->getCloakedId(), + \CommonsBooking\Repository\Item::URL_SLUG => true, + ), + get_site_url() . '/' + ); + } + + /** + * Gets the closest Booking for a given Item. + * + * @return ?Booking the booking that is either past or currently active closest to the current time, null if no booking is present + */ + public function getClosestBooking(): ?Booking { + + $location = $this->getLocation(); + if ( $location === null ) { + return null; + } + + $allBookings = \CommonsBooking\Repository\Booking::get( + [ $location->ID ], + [ $this->ID ], + null, + true, + null, + [ 'confirmed' ] + ); + + $closestBooking = \CommonsBooking\View\Calendar::getClosestBookableTimeFrameForToday( $allBookings ); + + return ( $closestBooking instanceof Booking ) ? $closestBooking : null; // This also checks if the value is null + } + /** * Will get the location that the item is currently stationed at and bookable. * Will take into account the current time, the item can have timeframes diff --git a/src/Plugin.php b/src/Plugin.php index b7e143506..7eec57731 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -831,6 +831,9 @@ function () { // iCal rewrite iCalendar::initRewrite(); + + // permalink resolution rewrite + \CommonsBooking\Repository\Item::initRewrite(); } /** @@ -918,6 +921,7 @@ function () { new \CommonsBooking\API\GBFS\Discovery(), new \CommonsBooking\API\GBFS\StationInformation(), new \CommonsBooking\API\GBFS\StationStatus(), + new \CommonsBooking\API\GBFS\VehicleStatus(), new \CommonsBooking\API\GBFS\SystemInformation(), ]; diff --git a/src/Repository/Item.php b/src/Repository/Item.php index ada54a228..9629ac961 100644 --- a/src/Repository/Item.php +++ b/src/Repository/Item.php @@ -5,6 +5,8 @@ use Exception; class Item extends BookablePost { + public const URL_SLUG = COMMONSBOOKING_PLUGIN_SLUG . '_get_vehicle'; + public const QUERY_VEHICLE_ID = COMMONSBOOKING_PLUGIN_SLUG . '_vehicle_cloaked_id'; /** * Returns array with items at location based on bookable timeframes. @@ -20,6 +22,50 @@ public static function getByLocation( $locationId, bool $bookable = false ): arr return self::getByRelatedPost( $locationId, 'location', 'item', $bookable ); } + /** + * Allows resolving cloaked vehicle IDs published by the GBFS API back to the corresponding items + * + * @return void + */ + public static function initRewrite() { + add_action( + 'wp_loaded', + function () { + add_rewrite_rule( self::URL_SLUG, 'index.php?' . self::URL_SLUG . '=1', 'top' ); + } + ); + + add_filter( + 'query_vars', + function ( $query_vars ) { + $query_vars[] = self::URL_SLUG; + return $query_vars; + } + ); + + add_action( + 'parse_request', + function ( &$wp ) { + + if ( + ! array_key_exists( self::URL_SLUG, $wp->query_vars ) || + ! isset( $_GET[ self::QUERY_VEHICLE_ID ] ) || + empty( $_GET[ self::QUERY_VEHICLE_ID ] ) + ) { + return; + } + $cloakedId = sanitize_text_field( wp_unslash( $_GET[ self::QUERY_VEHICLE_ID ] ) ); + $item = Item::getByCloakedId( $cloakedId ); + if ( $item === null ) { + die( 'invalid vehicle id' ); + } + $url = get_permalink( $item->ID ); + wp_redirect( $url ); + exit; + } + ); + } + /** * @return string */ @@ -27,6 +73,22 @@ protected static function getPostType(): string { return \CommonsBooking\Wordpress\CustomPostType\Item::getPostType(); } + /** + * Gets an individual item from a cloaked ID. The GBFS API uses this to provide + * deep-links with rotating vehicle IDs. + * + * @param string $cloakedId + * @return \CommonsBooking\Model\Item|null + */ + public static function getByCloakedId( string $cloakedId ): ?\CommonsBooking\Model\Item { + foreach ( self::get() as $item ) { + if ( $item->getCloakedId() == $cloakedId ) { + return $item; + } + } + return null; + } + /** * This is the model class that belongs to the post type. * With the model class, you are able to perform additional functions on the post type. diff --git a/tests/php/API/GBFS/VehicleStatusRouteTest.php b/tests/php/API/GBFS/VehicleStatusRouteTest.php new file mode 100644 index 000000000..8b7550439 --- /dev/null +++ b/tests/php/API/GBFS/VehicleStatusRouteTest.php @@ -0,0 +1,75 @@ +ENDPOINT ); + $response = rest_do_request( $request ); + + $this->assertSame( 200, $response->get_status() ); + + $data = $response->get_data()->data; + + $this->assertFalse( $data->vehicles[0]->is_reserved ); + + $this->createConfirmedBookingStartingToday(); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertTrue( $data->vehicles[0]->is_reserved ); + } + + public function testIsDisabled() { + // base case, not disabled + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertFalse( $data->vehicles[0]->is_disabled ); + + // timeframe expired: is disabled + $future = $this->end->modify( '+1 day' ); + ClockMock::freeze( $future ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertTrue( $data->vehicles[0]->is_disabled ); + } + + public function setUp(): void { + parent::setUp(); + + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + + $this->locationId = $this->createLocation( 'Testlocation', 'publish', [] ); + $this->itemId = $this->createItem( 'TestItem', 'publish' ); + + $mocked = new \DateTimeImmutable( self::CURRENT_DATE ); + $this->start = $mocked->modify( '-1 days' ); + $this->end = $mocked->modify( '+1 days' ); + + $this->timeframe = $this->createTimeframe( + $this->locationId, + $this->itemId, + $this->start->getTimestamp(), + $this->end->getTimestamp() + ); + } + + public function tearDown(): void { + ClockMock::reset(); + parent::tearDown(); + } +} diff --git a/tests/php/Model/ItemTest.php b/tests/php/Model/ItemTest.php index 579fd0133..5eef2b6f6 100644 --- a/tests/php/Model/ItemTest.php +++ b/tests/php/Model/ItemTest.php @@ -6,6 +6,7 @@ use CommonsBooking\Model\Restriction; use CommonsBooking\Model\Timeframe; use CommonsBooking\Tests\Wordpress\CustomPostTypeTest; +use SlopeIt\ClockMock\ClockMock; class ItemTest extends CustomPostTypeTest { @@ -114,6 +115,69 @@ public function testGetLocation() { $this->assertEquals( $locationB, $movingItemModel->getLocation()->ID ); } + public function testGetCloakedID() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + $cloakedID = $this->itemModel->getCloakedId(); + $this->assertIsString( $cloakedID ); + // create a booking, assert that it has changed + $this->createConfirmedBookingEndingToday(); + $cloakedIDWithBooking = $this->itemModel->getCloakedId(); + $this->assertNotEquals( $cloakedID, $cloakedIDWithBooking ); + $booking = $this->createConfirmedBookingStartingToday(); + $cloakedIDwithTwoBookings = $this->itemModel->getCloakedId(); + $this->assertNotEquals( $cloakedIDWithBooking, $cloakedIDwithTwoBookings ); + + // delete second booking, ID should revert to previous one + wp_delete_post( $booking, true ); + $this->assertEquals( $cloakedIDWithBooking, $this->itemModel->getCloakedId() ); + } + + public function testGetClosestBooking() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + // no booking present + $this->assertNull( $this->itemModel->getClosestBooking() ); + + // one past booking + $bookingEndingToday = $this->createConfirmedBookingEndingToday(); + $closestBooking = $this->itemModel->getClosestBooking(); + $this->assertEquals( $bookingEndingToday, $closestBooking->ID ); + + // newer booking in front of that + $bookingStartingToday = $this->createConfirmedBookingStartingToday(); + $closestBooking = $this->itemModel->getClosestBooking(); + $this->assertEquals( $bookingStartingToday, $closestBooking->ID ); + + // booking in future (should not affect) + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '+3 days' ), + strtotime( '+4 days' ) + ); + $this->assertEquals( $bookingStartingToday, $this->itemModel->getClosestBooking()->ID ); + } + + // Test case where last booking is way in the past but other booking is in the nearer future. Should still return booking in the past + public function testGetClosestBooking_notIncludingFutureBookings() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + // one past booking + $pastBooking = $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '-7 days' ), + strtotime( '-5 days' ) + ); + // one future booking + $bookingStartingTomorrow = $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '+1 day' ), + strtotime( '+2 days' ) + ); + $closestBooking = $this->itemModel->getClosestBooking(); + $this->assertEquals( $pastBooking, $closestBooking->ID ); + } + public function testIsCurrentlyFreeAtLocation() { ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); diff --git a/tests/php/Repository/ItemTest.php b/tests/php/Repository/ItemTest.php index 64baef6f6..641671183 100644 --- a/tests/php/Repository/ItemTest.php +++ b/tests/php/Repository/ItemTest.php @@ -4,21 +4,39 @@ use CommonsBooking\Repository\Item; use CommonsBooking\Tests\Wordpress\CustomPostTypeTest; +use SlopeIt\ClockMock\ClockMock; class ItemTest extends CustomPostTypeTest { protected function setUp(): void { parent::setUp(); - - // Create timeframe with location and item, so that we can search vor it + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + // Create timeframe with location and item, so that we can search for it $this->createTimeframe( $this->locationId, $this->itemId, - strtotime( 'midnight' ), - strtotime( '+90 days' ) + strtotime( 'midnight', strtotime( self::CURRENT_DATE ) ), + strtotime( '+90 days', strtotime( self::CURRENT_DATE ) ) ); } + public function testGetByCloakedId(): void { + $itemModel = new \CommonsBooking\Model\Item( $this->itemId ); + + // basic test, without any booking + $cloakedId = $itemModel->getCloakedId(); + $this->assertEquals( $this->itemId, Item::getByCloakedId( $cloakedId )->ID ); + + // with booking + $this->createConfirmedBookingEndingToday(); + $bookingCloakedId = $itemModel->getCloakedId(); + $this->assertNotEquals( $bookingCloakedId, $cloakedId ); + $this->assertEquals( $this->itemId, Item::getByCloakedId( $bookingCloakedId )->ID ); + + // test for invalid cloaked id + $this->assertNull( Item::getByCloakedId( 'invalid-cloaked-id' ) ); + } + public function testGetByLocation(): void { $this->assertEquals( [ $this->itemId ], From 42cceed57125939e4360fd31944a5d3e2ef568bb Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Thu, 7 May 2026 21:20:49 +0200 Subject: [PATCH 034/148] GBFS: add vehicle_availability route --- .../vehicle_availability.json | 91 +++++++++++++++ src/API/GBFS/Discovery.php | 1 + src/API/GBFS/VehicleAvailability.php | 83 ++++++++++++++ src/Plugin.php | 1 + .../API/GBFS/VehicleAvailabilityRouteTest.php | 104 ++++++++++++++++++ 5 files changed, 280 insertions(+) create mode 100644 includes/gbfs-json-schema/vehicle_availability.json create mode 100644 src/API/GBFS/VehicleAvailability.php create mode 100644 tests/php/API/GBFS/VehicleAvailabilityRouteTest.php diff --git a/includes/gbfs-json-schema/vehicle_availability.json b/includes/gbfs-json-schema/vehicle_availability.json new file mode 100644 index 000000000..db426d3dd --- /dev/null +++ b/includes/gbfs-json-schema/vehicle_availability.json @@ -0,0 +1,91 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://github.com/MobilityData/gbfs-json-schema/blob/master/v3.1-RC2/vehicle_availability.json", + "description": "Describes the vehicle availabilities of the system.", + "type": "object", + "properties": { + "last_updated": { + "description": "Last time the data in the feed was updated in RFC3339 format.", + "type": "string", + "format": "date-time" + }, + "ttl": { + "description": "Number of seconds before the data in the feed will be updated again (0 if the data should always be refreshed).", + "type": "integer", + "minimum": 0 + }, + "version": { + "description": "GBFS version number to which the feed conforms, according to the versioning framework (added in v1.1).", + "type": "string", + "const": "3.1-RC2" + }, + "data": { + "type": "object", + "properties": { + "vehicles": { + "type": "array", + "description": "Contains one object per vehicle.", + "items": { + "type": "object", + "properties": { + "vehicle_id": { + "type": "string", + "description": "Identifier of a vehicle" + }, + "vehicle_type_id": { + "type": "string", + "description": "Unique identifier of a vehicle type as defined in vehicle_types.json" + }, + "station_id": { + "type": "string", + "description": " The id of the station where this vehicle is located when available" + }, + "pricing_plan_id": { + "type": "string", + "description": "The plan_id of the pricing plan this vehicle is eligible for" + }, + "vehicle_equipment": { + "type": "array", + "description": "List of vehicle equipment provided by the operator", + "items": { + "type": "string" + } + }, + "availabilities": { + "type": "array", + "description": "Array of time slots during which the specified vehicle is available.", + "items": { + "type": "object", + "properties": { + "from": { + "type": "string", + "description": "Start date and time of available time slot.", + "format": "date-time" + }, + "until": { + "type": "string", + "description": "End date and time of available time slot.", + "format": "date-time" + } + }, + "required": ["from"], + "additionalProperties": false + } + } + }, + "required": [ + "vehicle_id", + "station_id", + "availabilities" + ], + "additionalProperties": false + } + } + }, + "required": ["vehicles"], + "additionalProperties": false + } + }, + "required": ["last_updated", "ttl", "version", "data"], + "additionalProperties": false +} diff --git a/src/API/GBFS/Discovery.php b/src/API/GBFS/Discovery.php index b8a9a540a..a7677189d 100644 --- a/src/API/GBFS/Discovery.php +++ b/src/API/GBFS/Discovery.php @@ -49,6 +49,7 @@ public function get_items( $request ): WP_REST_Response { 'system_information', 'station_information', 'station_status', + 'vehicle_availability', 'vehicle_status', ] ); diff --git a/src/API/GBFS/VehicleAvailability.php b/src/API/GBFS/VehicleAvailability.php new file mode 100644 index 000000000..00717f3f8 --- /dev/null +++ b/src/API/GBFS/VehicleAvailability.php @@ -0,0 +1,83 @@ +vehicle_id = strval( $item->getCloakedId() ); + $preparedItem->station_id = strval( $item->getLocation()?->ID ); // This is what you could consider the home location. Regardless if the item is there atm or not. + $preparedItem->availabilities = self::getAvailabilities( $item ); + + return new WP_REST_Response( $preparedItem ); + } + + private static function getAvailabilities( $item ): array { + $availabilities = AvailabilityRoute::getItemData( $item->ID ); + + if ( empty( $availabilities ) ) { + return []; + } + + $firstAvailability = array_shift( $availabilities ); + $slots = [ + (object) [ + 'from' => $firstAvailability->start, + 'until' => $firstAvailability->end, + ], + ]; + + foreach ( $availabilities as $availability ) { + $gapSeconds = strtotime( $availability->start ) - strtotime( end( $slots )->until ); + + if ( $gapSeconds < 59 ) { + end( $slots )->until = $availability->end; + } else { + $slots[] = (object) [ + 'from' => $availability->start, + 'until' => $availability->end, + ]; + } + } + + return $slots; + } + + protected static function getListName(): string { + return 'vehicles'; + } + + + protected static function getRepository(): PostRepository { + // we iterate over posts with cb_item post type + return new Item(); + } +} diff --git a/src/Plugin.php b/src/Plugin.php index 7eec57731..cb96a80f8 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -921,6 +921,7 @@ function () { new \CommonsBooking\API\GBFS\Discovery(), new \CommonsBooking\API\GBFS\StationInformation(), new \CommonsBooking\API\GBFS\StationStatus(), + new \CommonsBooking\API\GBFS\VehicleAvailability(), new \CommonsBooking\API\GBFS\VehicleStatus(), new \CommonsBooking\API\GBFS\SystemInformation(), diff --git a/tests/php/API/GBFS/VehicleAvailabilityRouteTest.php b/tests/php/API/GBFS/VehicleAvailabilityRouteTest.php new file mode 100644 index 000000000..2a2c81801 --- /dev/null +++ b/tests/php/API/GBFS/VehicleAvailabilityRouteTest.php @@ -0,0 +1,104 @@ +ENDPOINT ); + $response = rest_do_request( $request ); + + $this->assertSame( 200, $response->get_status() ); + + $data = $response->get_data()->data; + $this->assertNotEmpty( $data->vehicles ); + $this->assertCount( 1, $data->vehicles ); + $availabilities = $data->vehicles[0]->availabilities; + $this->assertCount( 1, $availabilities ); + + $startDT = new \DateTime( $availabilities[0]->from ); + $today = new \DateTime( self::CURRENT_DATE ); + + $this->assertEqualsWithDelta( $today->getTimestamp(), $startDT->getTimestamp(), 1.0 ); + } + + public function testHourlyAvailability() { + delete_post_meta( $this->timeframe, 'full-day', 'on' ); + update_post_meta( $this->timeframe, 'grid', 1 ); // hourly grid + update_post_meta( $this->timeframe, 'start-time', '08:00 AM' ); + update_post_meta( $this->timeframe, 'end-time', '01:00 PM' ); + + $startDT = new \DateTime(); + $startDT->modify( '08:00 AM' ); + $endDT = new \DateTime(); + $endDT->modify( '01:00 PM' ); + $endDT->modify( '-1 second' ); // timeframes always have one second cut + + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + + $data = $response->get_data()->data; + $this->assertNotEmpty( $data->vehicles ); + $this->assertCount( 1, $data->vehicles ); + $availabilities = $data->vehicles[0]->availabilities; + $this->assertCount( 2, $availabilities ); // today and tomorrow + $this->assertEquals( $startDT->format( 'c' ), $availabilities[0]->from ); + $this->assertEquals( $endDT->format( 'c' ), $availabilities[0]->until ); + } + + public function testVehicleIDChanges() { + // test, that the vehicle ID rotates after each trip + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + + $data = $response->get_data()->data; + $id = $data->vehicles[0]->vehicle_id; + + // add a trip + $this->createConfirmedBookingStartingToday( $this->locationId, $this->itemId ); + + // after the trip, the vehicle ID should have changed + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + + $this->assertNotEquals( $id, $data->vehicles[0]->vehicle_id ); + } + + public function setUp(): void { + parent::setUp(); + + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + + $this->locationId = $this->createLocation( 'Testlocation', 'publish', [] ); + $this->itemId = $this->createItem( 'TestItem', 'publish' ); + + $mocked = new \DateTimeImmutable( self::CURRENT_DATE ); + $this->start = $mocked->modify( '-1 days' ); + $this->end = $mocked->modify( '+1 days' ); + + $this->timeframe = $this->createTimeframe( + $this->locationId, + $this->itemId, + $this->start->getTimestamp(), + $this->end->getTimestamp() + ); + } + + public function tearDown(): void { + ClockMock::reset(); + parent::tearDown(); + } +} From 14bc0c2a607724f9b54fd6167f3da17a0231ba5a Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Thu, 7 May 2026 23:45:37 +0200 Subject: [PATCH 035/148] amend! GBFS: add vehicle_status route GBFS: add vehicle_status route --- src/Model/Item.php | 27 +++++++- .../API/GBFS/VehicleAvailabilityRouteTest.php | 9 ++- tests/php/Model/ItemTest.php | 64 +++++++++++++++---- tests/php/Repository/ItemTest.php | 9 ++- 4 files changed, 89 insertions(+), 20 deletions(-) diff --git a/src/Model/Item.php b/src/Model/Item.php index 7abf17c82..06af2e34b 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -124,7 +124,7 @@ public function getCloakedURL(): string { /** * Gets the closest Booking for a given Item. * - * @return ?Booking the booking that is either past or currently active closest to the current time, null if no booking is present + * @return ?Booking the booking that is past and closest to the current time, null if no booking is present */ public function getClosestBooking(): ?Booking { @@ -142,9 +142,30 @@ public function getClosestBooking(): ?Booking { [ 'confirmed' ] ); - $closestBooking = \CommonsBooking\View\Calendar::getClosestBookableTimeFrameForToday( $allBookings ); + $allBookings = array_filter( $allBookings, fn( $b ) => $b->isPast() ); - return ( $closestBooking instanceof Booking ) ? $closestBooking : null; // This also checks if the value is null + if ( empty( $allBookings ) ) { + return null; + } + + usort( + $allBookings, + function ( $a, $b ) { + $aStartDate = $a->getStartDate(); + $bStartDate = $b->getStartDate(); + + if ( $aStartDate == $bStartDate ) { + $aStartTimeDT = $a->getStartTimeDateTime(); + $bStartTimeDT = $b->getStartTimeDateTime(); + + return $aStartTimeDT <=> $bStartTimeDT; + } + + return $aStartDate <=> $bStartDate; + } + ); + + return array_pop( $allBookings ); } /** diff --git a/tests/php/API/GBFS/VehicleAvailabilityRouteTest.php b/tests/php/API/GBFS/VehicleAvailabilityRouteTest.php index 2a2c81801..f160bcdc7 100644 --- a/tests/php/API/GBFS/VehicleAvailabilityRouteTest.php +++ b/tests/php/API/GBFS/VehicleAvailabilityRouteTest.php @@ -65,8 +65,13 @@ public function testVehicleIDChanges() { $data = $response->get_data()->data; $id = $data->vehicles[0]->vehicle_id; - // add a trip - $this->createConfirmedBookingStartingToday( $this->locationId, $this->itemId ); + // add a trip in the past + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '-2 days', strtotime( self::CURRENT_DATE ) ), + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ) + ); // after the trip, the vehicle ID should have changed $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); diff --git a/tests/php/Model/ItemTest.php b/tests/php/Model/ItemTest.php index 5eef2b6f6..6a07cfc70 100644 --- a/tests/php/Model/ItemTest.php +++ b/tests/php/Model/ItemTest.php @@ -120,16 +120,19 @@ public function testGetCloakedID() { $cloakedID = $this->itemModel->getCloakedId(); $this->assertIsString( $cloakedID ); // create a booking, assert that it has changed - $this->createConfirmedBookingEndingToday(); + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '-2 days', strtotime( self::CURRENT_DATE ) ), + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ) + ); $cloakedIDWithBooking = $this->itemModel->getCloakedId(); $this->assertNotEquals( $cloakedID, $cloakedIDWithBooking ); + + // this booking is not in the past, trip has not ended. Therefore it should not affect the ID $booking = $this->createConfirmedBookingStartingToday(); $cloakedIDwithTwoBookings = $this->itemModel->getCloakedId(); - $this->assertNotEquals( $cloakedIDWithBooking, $cloakedIDwithTwoBookings ); - - // delete second booking, ID should revert to previous one - wp_delete_post( $booking, true ); - $this->assertEquals( $cloakedIDWithBooking, $this->itemModel->getCloakedId() ); + $this->assertEquals( $cloakedIDWithBooking, $cloakedIDwithTwoBookings ); } public function testGetClosestBooking() { @@ -138,14 +141,24 @@ public function testGetClosestBooking() { $this->assertNull( $this->itemModel->getClosestBooking() ); // one past booking - $bookingEndingToday = $this->createConfirmedBookingEndingToday(); - $closestBooking = $this->itemModel->getClosestBooking(); - $this->assertEquals( $bookingEndingToday, $closestBooking->ID ); + $bookingInPast = $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '-4 days', strtotime( self::CURRENT_DATE ) ), + strtotime( '-3 days', strtotime( self::CURRENT_DATE ) ) + ); + $closestBooking = $this->itemModel->getClosestBooking(); + $this->assertEquals( $bookingInPast, $closestBooking->ID ); // newer booking in front of that - $bookingStartingToday = $this->createConfirmedBookingStartingToday(); - $closestBooking = $this->itemModel->getClosestBooking(); - $this->assertEquals( $bookingStartingToday, $closestBooking->ID ); + $newerBooking = $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '-2 days', strtotime( self::CURRENT_DATE ) ), + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ) + ); + $closestBooking = $this->itemModel->getClosestBooking(); + $this->assertEquals( $newerBooking, $closestBooking->ID ); // booking in future (should not affect) $this->createBooking( @@ -154,7 +167,7 @@ public function testGetClosestBooking() { strtotime( '+3 days' ), strtotime( '+4 days' ) ); - $this->assertEquals( $bookingStartingToday, $this->itemModel->getClosestBooking()->ID ); + $this->assertEquals( $newerBooking, $this->itemModel->getClosestBooking()->ID ); } // Test case where last booking is way in the past but other booking is in the nearer future. Should still return booking in the past @@ -178,6 +191,31 @@ public function testGetClosestBooking_notIncludingFutureBookings() { $this->assertEquals( $pastBooking, $closestBooking->ID ); } + public function testGetClosestBooking_picksMostRecentPastBooking() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '-14 days' ), + strtotime( '-12 days' ) + ); + $recentPastBooking = $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '-3 days' ), + strtotime( '-1 day' ) + ); + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '+1 day' ), + strtotime( '+2 days' ) + ); + + $closestBooking = $this->itemModel->getClosestBooking(); + $this->assertEquals( $recentPastBooking, $closestBooking->ID ); + } + public function testIsCurrentlyFreeAtLocation() { ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); diff --git a/tests/php/Repository/ItemTest.php b/tests/php/Repository/ItemTest.php index 641671183..d559fbe95 100644 --- a/tests/php/Repository/ItemTest.php +++ b/tests/php/Repository/ItemTest.php @@ -27,8 +27,13 @@ public function testGetByCloakedId(): void { $cloakedId = $itemModel->getCloakedId(); $this->assertEquals( $this->itemId, Item::getByCloakedId( $cloakedId )->ID ); - // with booking - $this->createConfirmedBookingEndingToday(); + // with booking in past + $this->createBooking( + $this->locationId, + $this->itemId, + strtotime( '-2 days', strtotime( self::CURRENT_DATE ) ), + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ) + ); $bookingCloakedId = $itemModel->getCloakedId(); $this->assertNotEquals( $bookingCloakedId, $cloakedId ); $this->assertEquals( $this->itemId, Item::getByCloakedId( $bookingCloakedId )->ID ); From 2e62aa7b2093bb1e7928fc1b126b3fd6e9f178c4 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Fri, 8 May 2026 09:06:53 +0200 Subject: [PATCH 036/148] GBFS: always skip item when there is no location available --- src/API/GBFS/VehicleAvailability.php | 7 ++++++- src/API/GBFS/VehicleStatus.php | 11 ++++++++--- tests/php/API/GBFS/VehicleStatusRouteTest.php | 10 ++++++++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/API/GBFS/VehicleAvailability.php b/src/API/GBFS/VehicleAvailability.php index 00717f3f8..31bdf3760 100644 --- a/src/API/GBFS/VehicleAvailability.php +++ b/src/API/GBFS/VehicleAvailability.php @@ -32,9 +32,14 @@ class VehicleAvailability extends BaseRoute { * @throws \Exception */ public function prepare_item_for_response( $item, $request ): WP_REST_Response { + $location = $item->getLocation(); + if ( ! $location ) { + throw new \Exception( 'No location for item. (ID: ' . $item->ID . ')' ); + } + $preparedItem = new stdClass(); $preparedItem->vehicle_id = strval( $item->getCloakedId() ); - $preparedItem->station_id = strval( $item->getLocation()?->ID ); // This is what you could consider the home location. Regardless if the item is there atm or not. + $preparedItem->station_id = strval( $location->ID ); // This is what you could consider the home location. Regardless if the item is there atm or not. $preparedItem->availabilities = self::getAvailabilities( $item ); return new WP_REST_Response( $preparedItem ); diff --git a/src/API/GBFS/VehicleStatus.php b/src/API/GBFS/VehicleStatus.php index 5682f8a30..84a854c89 100644 --- a/src/API/GBFS/VehicleStatus.php +++ b/src/API/GBFS/VehicleStatus.php @@ -31,15 +31,20 @@ class VehicleStatus extends BaseRoute { * @throws \Exception */ public function prepare_item_for_response( $item, $request ): WP_REST_Response { + $location = $item->getLocation(); + if ( ! $location ) { + throw new \Exception( 'No location for item. (ID: ' . $item->ID . ')' ); + } + $preparedItem = new stdClass(); $preparedItem->vehicle_id = strval( $item->getCloakedId() ); - $preparedItem->station_id = strval( $item->getLocation()?->ID ); + $preparedItem->station_id = strval( $location->ID ); $preparedItem->is_reserved = ! $item->isCurrentlyFreeAtLocation( intval( $preparedItem->station_id ) ); - $preparedItem->is_disabled = $item->getLocation() === null; + $preparedItem->is_disabled = false; // This never happens, when the item is disabled it does not have a location and is therefore skipped $preparedItem->rental_uris = (object) [ 'web' => $item->getCloakedURL(), ]; - // $preparedItem->available_until //TODO The date and time when any rental of the vehicle must be completed. The vehicle must be returned and made available for the next user by this time. If this field is empty, it indicates that the vehicle is available indefinitely. This field SHOULD be published by carsharing or other mobility systems where vehicles can be booked in advance for future travel. + // $preparedItem->available_until //TODO: The date and time when any rental of the vehicle must be completed. The vehicle must be returned and made available for the next user by this time. If this field is empty, it indicates that the vehicle is available indefinitely. This field SHOULD be published by carsharing or other mobility systems where vehicles can be booked in advance for future travel. return new WP_REST_Response( $preparedItem ); } diff --git a/tests/php/API/GBFS/VehicleStatusRouteTest.php b/tests/php/API/GBFS/VehicleStatusRouteTest.php index 8b7550439..69c7cd9be 100644 --- a/tests/php/API/GBFS/VehicleStatusRouteTest.php +++ b/tests/php/API/GBFS/VehicleStatusRouteTest.php @@ -30,6 +30,12 @@ public function testIsReserved() { $this->assertTrue( $data->vehicles[0]->is_reserved ); } + /** + * This does not test is_disabled for when there is no timeframe. + * This is, because there is no way for us to get a location for an item + * when there is no active timeframe. + * @return void + */ public function testIsDisabled() { // base case, not disabled $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); @@ -38,14 +44,14 @@ public function testIsDisabled() { $data = $response->get_data()->data; $this->assertFalse( $data->vehicles[0]->is_disabled ); - // timeframe expired: is disabled + // timeframe expired: item vanishes from feed $future = $this->end->modify( '+1 day' ); ClockMock::freeze( $future ); $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); $response = rest_do_request( $request ); $this->assertSame( 200, $response->get_status() ); $data = $response->get_data()->data; - $this->assertTrue( $data->vehicles[0]->is_disabled ); + $this->assertEmpty( $data->vehicles ); } public function setUp(): void { From 70de1bae5083eeb5881685c203c4870d936d2c96 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Fri, 8 May 2026 09:20:19 +0200 Subject: [PATCH 037/148] fix doccomment --- src/Model/Item.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Model/Item.php b/src/Model/Item.php index 06af2e34b..e893781f2 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -95,7 +95,7 @@ public function getRestrictions(): array { * Inspired by: https://tier.engineering/How-we-anonymize-user-trips-on-public-APIs * Difference: We don't care about anonymity as much, because we don't offer A -> B trips. * - * This function is probably not secure, wp_hash uses md5 encryption. + * This function uses wp_hash to get a hashed identifier, this uses md5 hashing internally. * * @return string - a rotating ID for a vehicle */ From f380aad453ed6427f583297e68652bbd611e3d2b Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Fri, 8 May 2026 09:41:47 +0200 Subject: [PATCH 038/148] tests: add test for GBFS availability with offset calculation --- .../API/GBFS/VehicleAvailabilityRouteTest.php | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/tests/php/API/GBFS/VehicleAvailabilityRouteTest.php b/tests/php/API/GBFS/VehicleAvailabilityRouteTest.php index f160bcdc7..070178d60 100644 --- a/tests/php/API/GBFS/VehicleAvailabilityRouteTest.php +++ b/tests/php/API/GBFS/VehicleAvailabilityRouteTest.php @@ -4,6 +4,7 @@ use CommonsBooking\Model\Timeframe; use CommonsBooking\Tests\API\CB_REST_Route_UnitTestCase; +use CommonsBooking\Tests\Wordpress\CustomPostTypeTest; use SlopeIt\ClockMock\ClockMock; class VehicleAvailabilityRouteTest extends CB_REST_Route_UnitTestCase { @@ -31,6 +32,60 @@ public function testDailyAvailability() { $this->assertEqualsWithDelta( $today->getTimestamp(), $startDT->getTimestamp(), 1.0 ); } + public function testAvailabilityWithOffset() { + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + + // delete other timeframe so it doesn't mess with our tests + wp_delete_post( $this->timeframe, true ); + $otherLocationId = $this->createLocation( 'Other Location', ); + $otherItemId = $this->createItem( 'Other Item', ); + + $timeframeID = $this->createTimeframe( + $otherLocationId, + $otherItemId, + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ), + \CommonsBooking\Wordpress\CustomPostType\Timeframe::BOOKABLE_ID, + 'on', + 'd', + 0, + '8:00 AM', + '12:00 PM', + 'publish', + [], + '', + CustomPostTypeTest::USER_ID, + 3, + 30, + 2 + ); + + // with offset → not available right now + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + + $availabilities = $data->vehicles[0]->availabilities; + + $startDT = new \DateTime( $availabilities[0]->from ); + $today = new \DateTime( self::CURRENT_DATE ); + + $this->assertNotEqualsWithDelta( $today->getTimestamp(), $startDT->getTimestamp(), 1.0 ); + + // remove offset → now available today + update_post_meta( $timeframeID, \CommonsBooking\Model\Timeframe::META_BOOKING_START_DAY_OFFSET, 0 ); + + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + $availabilities = $data->vehicles[0]->availabilities; + $this->assertCount( 1, $availabilities ); + + $startDT = new \DateTime( $availabilities[0]->from ); + $today = new \DateTime( self::CURRENT_DATE ); + + $this->assertEqualsWithDelta( $today->getTimestamp(), $startDT->getTimestamp(), 1.0 ); + } + public function testHourlyAvailability() { delete_post_meta( $this->timeframe, 'full-day', 'on' ); update_post_meta( $this->timeframe, 'grid', 1 ); // hourly grid From 359dc5785d16bc91a51b7b760e8474c1dbe15bdd Mon Sep 17 00:00:00 2001 From: hansmorb Date: Fri, 8 May 2026 08:06:37 +0000 Subject: [PATCH 039/148] Ran wp i18n make-pot --- languages/commonsbooking-de_DE.po | 46 ++++++++++++++--------------- languages/commonsbooking.pot | 48 +++++++++++++++---------------- 2 files changed, 47 insertions(+), 47 deletions(-) diff --git a/languages/commonsbooking-de_DE.po b/languages/commonsbooking-de_DE.po index 0be42d0b2..2b0ae1afd 100644 --- a/languages/commonsbooking-de_DE.po +++ b/languages/commonsbooking-de_DE.po @@ -1184,51 +1184,51 @@ msgstr "Bitte kontaktiere die Kontaktpersonen vor Ort direkt, wenn du Fragen zur msgid "Not set" msgstr "Nicht gesetzt" -#: src/Model/Timeframe.php:255 +#: src/Model/Timeframe.php:331 msgid "Available here" msgstr "Hier verfügbar" #. translators: %s = date in WordPress defined format #: src/Model/Booking.php:437 -#: src/Model/Timeframe.php:260 +#: src/Model/Timeframe.php:336 #, php-format msgid "on %s" msgstr "am %s" #. translators: %s = date in WordPress defined format -#: src/Model/Timeframe.php:265 +#: src/Model/Timeframe.php:341 #, php-format msgid "from %s" msgstr "von %s" -#: src/Model/Timeframe.php:269 +#: src/Model/Timeframe.php:345 msgid "permanently" msgstr "dauerhaft" #. translators: %1 = startdate, %2 = enddate in WordPress defined format #. translators: %1$s = startdate, second %2$s = enddate in WordPress defined format #: src/Model/Booking.php:440 -#: src/Model/Timeframe.php:275 +#: src/Model/Timeframe.php:351 #, php-format msgid "from %1$s until %2$s" msgstr "von %1$s bis %2$s" #. translators: %s = enddate in WordPress defined format -#: src/Model/Timeframe.php:282 +#: src/Model/Timeframe.php:358 #, php-format msgid "until %s" msgstr "bis %s" -#: src/Model/Timeframe.php:610 +#: src/Model/Timeframe.php:686 msgid "A pickup time but no return time has been set. Please set the return time." msgstr "Eine Abholzeit, aber keine Rückgabezeit wurde festgelegt. Lege bitte eine Rückgabezeit fest." -#: src/Model/Timeframe.php:620 +#: src/Model/Timeframe.php:696 msgid "End date is before start date. Please set a valid end date." msgstr "Enddatum liegt vor dem Startdatum. Bitte setze ein gültiges Enddatum." #. translators: %1$s = timeframe-ID, %2$s is timeframe post_title -#: src/Model/Timeframe.php:655 +#: src/Model/Timeframe.php:731 #, php-format msgid "Item is already bookable at another location within the same date range. See other timeframe ID: %1$s: %2$s" msgstr "Artikel ist bereits an einem anderen Ort innerhalb desselben Datumsbereichs buchbar. Siehe andere Zeitrahmen ID: %1$s: %2$s" @@ -3025,7 +3025,7 @@ msgstr "Es ist nicht möglich, diesen Zeitrahmen im Frontend abzurufen. Bitte be msgid "Cancelled" msgstr "Storniert" -#: src/Model/Timeframe.php:630 +#: src/Model/Timeframe.php:706 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." @@ -3110,25 +3110,25 @@ msgid "If selected, days that are overbooked will be counted towards the maximum msgstr "Ist diese Option aktiviert, werden überbuchte Tage auf die maximale Anzahl buchbarer Tage angerechnet. Wenn diese Option deaktiviert ist, dann werden überbuchte Tage nicht zusätzlich gezählt und ermöglichen Buchungszeiträume die länger sind als die im Zeitrahmen konfigurierte maximale Anzahl an gebuchten Tagen." #. translators: first %s = timeframe-ID, second %s is timeframe post_title -#: src/Model/Timeframe.php:691 +#: src/Model/Timeframe.php:767 #, php-format msgid "See overlapping timeframe ID: %1$s %2$s" msgstr "Sich überschneidende Zeitrahmen ID: %1$s %2$s" -#: src/Model/Timeframe.php:790 +#: src/Model/Timeframe.php:866 msgid "Overlapping bookable timeframes are only allowed to have the same grid." msgstr "Sich überschneidende buchbare Zeiträume müssen das gleiche Raster haben." -#: src/Model/Timeframe.php:820 +#: src/Model/Timeframe.php:896 msgid "Overlapping bookable timeframes are not allowed to have the same weekdays." msgstr "Mehrere buchbare Zeiträume überschneiden sich in den definierten Wochentagen." -#: src/Model/Timeframe.php:832 +#: src/Model/Timeframe.php:908 msgid "Overlapping bookable timeframes are not allowed to have the same dates." msgstr "Mehrere buchbare Zeiträume überschneiden sich in dem definierten Datumsbereich." -#: src/Model/Timeframe.php:839 -#: src/Model/Timeframe.php:846 +#: src/Model/Timeframe.php:915 +#: src/Model/Timeframe.php:922 msgid "The other timeframe is overlapping with your weekly configuration." msgstr "Der andere Zeitrahmen überschneidet sich mit einer wöchentlichen Konfiguration." @@ -3168,7 +3168,7 @@ msgstr "Feiertage importieren" msgid "Select the year and state to import holidays for (as of now only German holidays are supported)" msgstr "Wählen Sie das Jahr und das Bundesland, für das Sie Feiertage importieren möchten (derzeit werden Feiertage in Deutschland unterstützt)" -#: src/Model/Timeframe.php:806 +#: src/Model/Timeframe.php:882 msgid "Daily repeated time periods are not allowed to overlap." msgstr "Täglich wiederholende Zeiträume dürfen sich nicht überschneiden." @@ -3867,27 +3867,27 @@ msgstr "Bitte passe das Start- oder Enddatum an." msgid "Affected Bookings: %s" msgstr "Betroffene Buchungen: %s" -#: src/Model/Timeframe.php:555 +#: src/Model/Timeframe.php:631 msgid "Could not get item or location. Please set a valid item and location." msgstr "Artikel oder Standort konnte nicht gefunden werden. Bitte wähle einen gültigen Artikel oder Standort." -#: src/Model/Timeframe.php:564 +#: src/Model/Timeframe.php:640 msgid "Item or location is missing. Please set item and location." msgstr "Artikel oder Standort fehlen. Bitte Artikel und Standort festlegen." -#: src/Model/Timeframe.php:577 +#: src/Model/Timeframe.php:653 msgid "No dates selected. Please select at least one date." msgstr "Kein Datum ausgewählt. Bitte mindestens ein Datum auswählen." -#: src/Model/Timeframe.php:587 +#: src/Model/Timeframe.php:663 msgid "The same date was selected multiple times. Please select each date only once." msgstr "Das gleiche Datum wurde mehrere Male ausgewählt. Bitte ein Datum nur einmal auswählen." -#: src/Model/Timeframe.php:596 +#: src/Model/Timeframe.php:672 msgid "Startdate is missing. Please enter a start date to publish this timeframe." msgstr "Das Startdatum fehlt. Ein Startdatum muss eingegeben werden, damit der Zeitrahmen veröffentlicht werden kann." -#: src/View/Booking.php:581 +#: src/View/Booking.php:578 #: src/Wordpress/CustomPostType/Booking.php:864 msgid "Submit booking" msgstr "Buchung abschicken" diff --git a/languages/commonsbooking.pot b/languages/commonsbooking.pot index 1feb6de32..435c35fdc 100644 --- a/languages/commonsbooking.pot +++ b/languages/commonsbooking.pot @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2026-04-09T19:23:59+00:00\n" +"POT-Creation-Date: 2026-05-08T08:06:33+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.12.0\n" "X-Domain: commonsbooking\n" @@ -1476,7 +1476,7 @@ msgstr "" #. translators: %s = date in WordPress defined format #: src/Model/Booking.php:437 -#: src/Model/Timeframe.php:260 +#: src/Model/Timeframe.php:336 #, php-format msgid "on %s" msgstr "" @@ -1484,7 +1484,7 @@ msgstr "" #. translators: %1 = startdate, %2 = enddate in WordPress defined format #. translators: %1$s = startdate, second %2$s = enddate in WordPress defined format #: src/Model/Booking.php:440 -#: src/Model/Timeframe.php:275 +#: src/Model/Timeframe.php:351 #, php-format msgid "from %1$s until %2$s" msgstr "" @@ -1564,88 +1564,88 @@ msgstr "" msgid "Not set" msgstr "" -#: src/Model/Timeframe.php:255 +#: src/Model/Timeframe.php:331 msgid "Available here" msgstr "" #. translators: %s = date in WordPress defined format -#: src/Model/Timeframe.php:265 +#: src/Model/Timeframe.php:341 #, php-format msgid "from %s" msgstr "" -#: src/Model/Timeframe.php:269 +#: src/Model/Timeframe.php:345 msgid "permanently" msgstr "" #. translators: %s = enddate in WordPress defined format -#: src/Model/Timeframe.php:282 +#: src/Model/Timeframe.php:358 #, php-format msgid "until %s" msgstr "" -#: src/Model/Timeframe.php:555 +#: src/Model/Timeframe.php:631 msgid "Could not get item or location. Please set a valid item and location." msgstr "" -#: src/Model/Timeframe.php:564 +#: src/Model/Timeframe.php:640 msgid "Item or location is missing. Please set item and location." msgstr "" -#: src/Model/Timeframe.php:577 +#: src/Model/Timeframe.php:653 msgid "No dates selected. Please select at least one date." msgstr "" -#: src/Model/Timeframe.php:587 +#: src/Model/Timeframe.php:663 msgid "The same date was selected multiple times. Please select each date only once." msgstr "" -#: src/Model/Timeframe.php:596 +#: src/Model/Timeframe.php:672 msgid "Startdate is missing. Please enter a start date to publish this timeframe." msgstr "" -#: src/Model/Timeframe.php:610 +#: src/Model/Timeframe.php:686 msgid "A pickup time but no return time has been set. Please set the return time." msgstr "" -#: src/Model/Timeframe.php:620 +#: src/Model/Timeframe.php:696 msgid "End date is before start date. Please set a valid end date." msgstr "" -#: src/Model/Timeframe.php:630 +#: src/Model/Timeframe.php:706 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 "" #. translators: %1$s = timeframe-ID, %2$s is timeframe post_title -#: src/Model/Timeframe.php:655 +#: src/Model/Timeframe.php:731 #, php-format msgid "Item is already bookable at another location within the same date range. See other timeframe ID: %1$s: %2$s" msgstr "" #. translators: first %s = timeframe-ID, second %s is timeframe post_title -#: src/Model/Timeframe.php:691 +#: src/Model/Timeframe.php:767 #, php-format msgid "See overlapping timeframe ID: %1$s %2$s" msgstr "" -#: src/Model/Timeframe.php:790 +#: src/Model/Timeframe.php:866 msgid "Overlapping bookable timeframes are only allowed to have the same grid." msgstr "" -#: src/Model/Timeframe.php:806 +#: src/Model/Timeframe.php:882 msgid "Daily repeated time periods are not allowed to overlap." msgstr "" -#: src/Model/Timeframe.php:820 +#: src/Model/Timeframe.php:896 msgid "Overlapping bookable timeframes are not allowed to have the same weekdays." msgstr "" -#: src/Model/Timeframe.php:832 +#: src/Model/Timeframe.php:908 msgid "Overlapping bookable timeframes are not allowed to have the same dates." msgstr "" -#: src/Model/Timeframe.php:839 -#: src/Model/Timeframe.php:846 +#: src/Model/Timeframe.php:915 +#: src/Model/Timeframe.php:922 msgid "The other timeframe is overlapping with your weekly configuration." msgstr "" @@ -2041,7 +2041,7 @@ msgstr "" msgid "Code" msgstr "" -#: src/View/Booking.php:581 +#: src/View/Booking.php:578 #: src/Wordpress/CustomPostType/Booking.php:864 msgid "Submit booking" msgstr "" From 63ab28839e44593d50a31112b0d980a9966b6aca Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Fri, 8 May 2026 10:46:20 +0200 Subject: [PATCH 040/148] GBFS: #2155 dynamic opening hours --- src/API/GBFS/SystemInformation.php | 13 +++++++++- .../API/GBFS/SystemInformationRouteTest.php | 26 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/API/GBFS/SystemInformation.php b/src/API/GBFS/SystemInformation.php index d40a67a61..c392bd68c 100644 --- a/src/API/GBFS/SystemInformation.php +++ b/src/API/GBFS/SystemInformation.php @@ -3,6 +3,8 @@ namespace CommonsBooking\API\GBFS; +use CommonsBooking\CB\CB; +use CommonsBooking\Repository\Timeframe; use stdClass; use WP_REST_Response; @@ -36,7 +38,7 @@ public function get_items( $request ): WP_REST_Response { 'language' => get_bloginfo( 'language' ), ], ]; - $response->data->opening_hours = '24/7'; // TODO: Close, when no items are available + $response->data->opening_hours = $this->isOpen() ? '24/7' : '24/7 closed'; $response->data->system_id = sha1( site_url() ); $response->data->feed_contact_email = get_bloginfo( 'admin_email' ); $response->data->languages = [ get_bloginfo( 'language' ) ]; @@ -47,4 +49,13 @@ public function get_items( $request ): WP_REST_Response { return $this->respond_with_validation( $response ); } + + private function isOpen(): bool { + $timeframes = Timeframe::getBookable( + [], + [], + date( CB::getInternalDateFormat(), current_time( 'timestamp' ) ), + ); + return count( $timeframes ) > 0; + } } diff --git a/tests/php/API/GBFS/SystemInformationRouteTest.php b/tests/php/API/GBFS/SystemInformationRouteTest.php index 40e96b2b3..bd8c4fb12 100644 --- a/tests/php/API/GBFS/SystemInformationRouteTest.php +++ b/tests/php/API/GBFS/SystemInformationRouteTest.php @@ -3,6 +3,7 @@ namespace CommonsBooking\Tests\API\GBFS; use CommonsBooking\Tests\API\CB_REST_Route_UnitTestCase; +use SlopeIt\ClockMock\ClockMock; class SystemInformationRouteTest extends CB_REST_Route_UnitTestCase { @@ -24,6 +25,31 @@ public function testRoute() { parent::testRoute(); } + public function testOpeningHours() { + // no timeframe setup, meaning no items to book -> closed + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + $this->assertEquals( '24/7 closed', $data->opening_hours ); + + // with timeframe, is open + $this->createBookableTimeFrameIncludingCurrentDay(); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + $this->assertEquals( '24/7', $data->opening_hours ); + + // outside of the timeframe, closed again + $inAWeek = new \DateTime( self::CURRENT_DATE ); + $inAWeek->modify( '+1 week' ); + ClockMock::freeze( $inAWeek ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + $this->assertEquals( '24/7 closed', $data->opening_hours ); + } + public function setUp(): void { parent::setUp(); } From 81ecea0c64cbc72e96bc882fb6622b75e920af92 Mon Sep 17 00:00:00 2001 From: Stefan Bomsdorf Date: Sun, 10 May 2026 20:12:54 +0200 Subject: [PATCH 041/148] Addresses review feedback --- docs/de/documentation/faq/index.md | 18 ++++++++---------- docs/en/documentation/faq/index.md | 18 ++++++++---------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/docs/de/documentation/faq/index.md b/docs/de/documentation/faq/index.md index e356491f8..01cc4b9c5 100644 --- a/docs/de/documentation/faq/index.md +++ b/docs/de/documentation/faq/index.md @@ -1,4 +1,4 @@ -# Häufige Fragen (FAQ) +# Häufige Fragen (FAQ) {#faq} + + + + diff --git a/docs/.vitepress/theme/index.js b/docs/.vitepress/theme/index.js index fd81d720f..293df5935 100644 --- a/docs/.vitepress/theme/index.js +++ b/docs/.vitepress/theme/index.js @@ -1,25 +1,28 @@ // .vitepress/theme/index.js +import { h, onMounted } from 'vue' import DefaultTheme from 'vitepress/theme' import './custom.css' -import { onMounted } from 'vue'; -import mediumZoom from 'medium-zoom'; -import { useData } from 'vitepress'; +import mediumZoom from 'medium-zoom' +import { useData } from 'vitepress' +import AnnouncementBanner from '../components/AnnouncementBanner.vue' export default { - ...DefaultTheme, - setup() { - const { page } = useData(); - - onMounted(() => { - const LOCALE_STORAGE_KEY = 'cb-doc-locale'; - const path = window.location.pathname; - const locale = path.startsWith('/en/') ? '/en/' : path.startsWith('/de/') ? '/de/' : '/de/'; - - // Persist the currently viewed locale so root can reuse the choice later - localStorage.setItem(LOCALE_STORAGE_KEY, locale); - - // Keep zoom working across locales - mediumZoom('[data-zoomable]', { background: 'var(--vp-c-bg)' }); - }); - }, + ...DefaultTheme, + Layout() { + return h(DefaultTheme.Layout, null, { + 'home-hero-before': () => h(AnnouncementBanner), + }) + }, + setup() { + const { page } = useData(); + onMounted(() => { + const LOCALE_STORAGE_KEY = 'cb-doc-locale'; + const path = window.location.pathname; + const locale = path.startsWith('/en/') ? '/en/' : path.startsWith('/de/') ? '/de/' : '/de/'; + // Persist the currently viewed locale so root can reuse the choice later + localStorage.setItem(LOCALE_STORAGE_KEY, locale); + // Keep zoom working across locales + mediumZoom('[data-zoomable]', { background: 'var(--vp-c-bg)' }); + }); + }, }; diff --git a/docs/de/documentation/setup/migration-from-cb1.md b/docs/de/documentation/setup/migration-from-cb1.md index b35fc55b9..6610466cc 100644 --- a/docs/de/documentation/setup/migration-from-cb1.md +++ b/docs/de/documentation/setup/migration-from-cb1.md @@ -1,5 +1,9 @@ # Migration von Version 0.9.x +:::danger ACHTUNG +Mit CommonsBooking 2.12 (Veröffentlichung Anfang 2027) wird die Migration von CommonsBooking 0.9.X auf die neuste Version eingestellt. +Alle Nutzenden von CommonsBooking 0.9.X sind dazu angehalten **zeitnah zu migrieren**, bei Fragen unterstützen wir gerne und helfen euch auch gerne bei der Migration. +::: Die Migration von Version CB 0.9.x zu CB 2.x.x könnt ihr per Knopfdruck erledigen. Die Migration importiert folgende Daten: diff --git a/docs/en/documentation/setup/migration-from-cb1.md b/docs/en/documentation/setup/migration-from-cb1.md index 89a92dba3..04c390412 100644 --- a/docs/en/documentation/setup/migration-from-cb1.md +++ b/docs/en/documentation/setup/migration-from-cb1.md @@ -1,5 +1,10 @@ # Migration from version 0.9.x +:::danger danger +With CommonsBooking 2.12 (releasing early 2027), migration support from CommonsBooking 0.9.X to the latest version will end. +All users of CommonsBooking 0.9.X are urged to **migrate as soon as possible**. We are happy to help with any questions and will support you in migration. +::: + You can migrate from CB 0.9.x to CB 2.x.x with a single click. The migration imports the following data: * Items diff --git a/src/CB/CB1UserFields.php b/src/CB/CB1UserFields.php index 41f6e4782..995488cbc 100644 --- a/src/CB/CB1UserFields.php +++ b/src/CB/CB1UserFields.php @@ -8,6 +8,9 @@ use CommonsBooking\Settings\Settings; +/** + * @deprecated since 2.11, to be removed in 2.12 + */ class CB1UserFields { /** @@ -226,7 +229,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 2.10 deprecated (cb_object_to_array is unspecified), removal in 2.12 * @since 0.6 */ public function set_basic_user_vars( $user_id ) { @@ -248,6 +251,7 @@ public function set_basic_user_vars( $user_id ) { /** * Add addiotinal key/value pairs to the user_vars array * + * @deprecated since 2.11, removal in 2.12 * @since 0.5.3 */ public function add_user_vars( $key, $value ) { diff --git a/src/Helper/Wordpress.php b/src/Helper/Wordpress.php index 43256ccde..22d44f19e 100644 --- a/src/Helper/Wordpress.php +++ b/src/Helper/Wordpress.php @@ -320,6 +320,14 @@ public static function getUTCDateTime( $datetime = 'now' ): DateTime { return $dto; } + /** + * UNUSED + * + * @deprecated since 2.11, to be removed in 2.12 + * @param $timestamp + * @return DateTime + * @throws \DateInvalidTimeZoneException + */ public static function getLocalDateTime( $timestamp ): DateTime { $dto = new DateTime(); $dto->setTimestamp( diff --git a/src/Map/MapFilter.php b/src/Map/MapFilter.php index 7c3f5e5a4..cb2a839e2 100644 --- a/src/Map/MapFilter.php +++ b/src/Map/MapFilter.php @@ -2,8 +2,20 @@ namespace CommonsBooking\Map; +/** + * Class MapFilter + * + * @deprecated since 2.11, to be removed in 2.12 + */ class MapFilter { + /** + * @deprecated since 2.11, to be removed in 2.12 + * + * @param $item_terms + * @param $category_groups + * @return bool + */ protected static function check_item_terms_against_categories( $item_terms, $category_groups ): bool { $valid_groups_count = 0; diff --git a/src/Migration/Migration.php b/src/Migration/Migration.php index fef012036..613d9e27d 100644 --- a/src/Migration/Migration.php +++ b/src/Migration/Migration.php @@ -16,6 +16,9 @@ use WP_Query; /** + * + * @deprecated since 2.11, will be removed in 2.12 + * * The logic for handling the migration from CB1 to CB2. * The CB1 fields are fetched from the @see \CommonsBooking\Repository\CB1 repository and migrated using the * respective migration functions in this class. diff --git a/src/Model/Item.php b/src/Model/Item.php index e893781f2..4957ad387 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -71,6 +71,7 @@ public function getAdmins() { * * This function is not used anywhere yet. * + * @deprecated since 2.11, removal in 2.12. * @return array * @throws Exception */ diff --git a/src/Model/Location.php b/src/Model/Location.php index bc178aaf3..7a1139c93 100644 --- a/src/Model/Location.php +++ b/src/Model/Location.php @@ -258,6 +258,7 @@ public function getAdmins() { /** * Will get the currently applicable restrictions for the location. * + * @deprecated since 2.11, removal in 2.12 * @return Restriction[] * @throws \Exception */ diff --git a/src/Model/Restriction.php b/src/Model/Restriction.php index 80bd7cfbd..e6b8560a6 100644 --- a/src/Model/Restriction.php +++ b/src/Model/Restriction.php @@ -171,8 +171,9 @@ public function isActive(): bool { /** * Returns true if restriction ist active. - * TODO this function seems unused in restriction context. Check if it can be removed @markus-mw + * Unused in restriction context * + * @deprecated since 2.11, removal in 2.12 * @return bool */ public function isLocked(): bool { @@ -238,6 +239,9 @@ public function getEndDateDateTime(): DateTime { /** * Returns item name for the item that is restricted. * + * Unused: accessed through {{item:post_title}} template tag over Item Model, not this method + * + * @deprecated since 2.11, removal in 2.12 * @return string */ public function getItemName(): string { @@ -262,6 +266,9 @@ public function getItemId() { /** * Returns location name for the location that the restricted item is in. * + * Unused, can be accessed through {{location:post_title}} template tag, not needed here + * + * @deprecated since 2.11, removal in 2.12. * @return string */ public function getLocationName(): string { diff --git a/src/Repository/CB1.php b/src/Repository/CB1.php index 0b519ada2..024e4afe7 100644 --- a/src/Repository/CB1.php +++ b/src/Repository/CB1.php @@ -9,6 +9,8 @@ * This class contains methods to query the database for old CB1 data. * CB1 is CommonsBooking up to version 0.9.4.18 (https://wordpress.org/plugins/commons-booking/) * This class is mainly used to migrate over the old data to CB2. + * + * @deprecated since 2.11 , removal in 2.12 */ class CB1 { @@ -234,10 +236,10 @@ public static function getCB2PostIdByCB1Id( $id ): ?int { $table_postmeta = $wpdb->prefix . 'postmeta'; $sql = $wpdb->prepare( - "SELECT meta_value as cb1_id, post_id as cb2_id + "SELECT meta_value as cb1_id, post_id as cb2_id FROM $table_postmeta WHERE - meta_key = '_cb_cb1_post_post_ID' AND + meta_key = '_cb_cb1_post_post_ID' AND meta_value = %s; ", $id @@ -266,10 +268,10 @@ public static function getCB1Taxonomies() { return $wpdb->get_results( " SELECT - tr.*, + tr.*, tt.taxonomy, t.slug as term - FROM $table_term_relationships tr + FROM $table_term_relationships tr LEFT JOIN $table_term_taxonomy tt ON tr.term_taxonomy_id = tt.term_id LEFT JOIN $table_terms t ON From c82c580e8fd266cde5447d04dd1b417b88bdaa16 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Mon, 15 Jun 2026 16:04:10 +0200 Subject: [PATCH 091/148] #1509 enable multi-select for all blocking timeframe --- assets/admin/js/src/timeframe.js | 8 ++++---- src/Wordpress/CustomPostType/Timeframe.php | 9 +++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/assets/admin/js/src/timeframe.js b/assets/admin/js/src/timeframe.js index 632aa565d..88561efa0 100644 --- a/assets/admin/js/src/timeframe.js +++ b/assets/admin/js/src/timeframe.js @@ -170,7 +170,7 @@ * Currently only for holidays, holidays used to only have one assignable single selection. */ const migrateSingleSelection = () => { - if (typeInput.val() != HOLIDAYS_ID) { + if (typeInput.val() != HOLIDAYS_ID || typeInput.val() != REPAIR_ID) { return; } // get single selection @@ -222,7 +222,7 @@ } //we migrate the single selection to the multiselect (new holiday timeframes do not have a single selection anymore) - if (selectedType == HOLIDAYS_ID) { + if (selectedType == HOLIDAYS_ID || selectedType == REPAIR_ID) { itemSelectionInput.show(); locationSelectionInput.show(); migrateSingleSelection(); @@ -244,7 +244,7 @@ const handleLocationSelection = function () { const selectedType = $('option:selected', typeInput).val(); //disable the mass selection for all timeframes except holidays - if (selectedType == HOLIDAYS_ID) { + if (selectedType == HOLIDAYS_ID || selectedType == REPAIR_ID) { singleLocationSelection.hide(); //handle different selection types const selectedOption = $('option:selected', locationSelectionInput).val(); @@ -275,7 +275,7 @@ const handleItemSelection = function () { const selectedType = $('option:selected', typeInput).val(); //disable the mass selection for all timeframes except holidays (for now) - if (selectedType == HOLIDAYS_ID) { + if (selectedType == HOLIDAYS_ID || selectedType == REPAIR_ID) { singleItemSelection.hide(); //handle different selection types const selectedOption = $('option:selected', itemSelectionInput).val(); diff --git a/src/Wordpress/CustomPostType/Timeframe.php b/src/Wordpress/CustomPostType/Timeframe.php index d20f8571f..b6bc88ac4 100644 --- a/src/Wordpress/CustomPostType/Timeframe.php +++ b/src/Wordpress/CustomPostType/Timeframe.php @@ -1115,7 +1115,7 @@ public static function removeIrrelevantPostmeta( \CommonsBooking\Model\Timeframe \CommonsBooking\Model\Timeframe::META_SHOW_BOOKING_CODES, ]; // remove multi-select postmeta if not relevant (#507) - $onlyRelevantForHolidays = [ + $onlyRelevantForHolidaysOrRepair = [ \CommonsBooking\Model\Timeframe::META_ITEM_ID_LIST, \CommonsBooking\Model\Timeframe::META_LOCATION_ID_LIST, \CommonsBooking\Model\Timeframe::META_ITEM_CATEGORY_IDS, @@ -1124,14 +1124,15 @@ public static function removeIrrelevantPostmeta( \CommonsBooking\Model\Timeframe \CommonsBooking\Model\Timeframe::META_LOCATION_SELECTION_TYPE, ]; - if ( $timeframe->getType() != self::BOOKABLE_ID ) { + $type = $timeframe->getType(); + if ( $type !== self::BOOKABLE_ID ) { foreach ( $onlyRelevantForBookable as $metaKey ) { delete_post_meta( $timeframe->ID, $metaKey ); } } - if ( $timeframe->getType() != self::HOLIDAYS_ID ) { - foreach ( $onlyRelevantForHolidays as $metaKey ) { + if ( ! ( $type === self::HOLIDAYS_ID || $type === self::REPAIR_ID ) ) { + foreach ( $onlyRelevantForHolidaysOrRepair as $metaKey ) { delete_post_meta( $timeframe->ID, $metaKey ); } // reset to manual selection From 91dd8f9122b9dd4931a52174571c95c316f63b99 Mon Sep 17 00:00:00 2001 From: hansmorb Date: Mon, 15 Jun 2026 14:16:31 +0000 Subject: [PATCH 092/148] Ran wp i18n make-pot --- languages/commonsbooking-de_DE.po | 44 ++++++++++++++--------------- languages/commonsbooking.pot | 46 +++++++++++++++---------------- 2 files changed, 45 insertions(+), 45 deletions(-) diff --git a/languages/commonsbooking-de_DE.po b/languages/commonsbooking-de_DE.po index 7ccfc1675..7a0db97a9 100644 --- a/languages/commonsbooking-de_DE.po +++ b/languages/commonsbooking-de_DE.po @@ -1563,7 +1563,7 @@ msgstr "Buchungen" #: src/Wordpress/CustomPostType/Item.php:118 #: src/Wordpress/CustomPostType/Location.php:140 #: src/Wordpress/CustomPostType/Restriction.php:307 -#: src/Wordpress/CustomPostType/Timeframe.php:1152 +#: src/Wordpress/CustomPostType/Timeframe.php:1153 msgid "Add new" msgstr "Neu hinzufügen" @@ -1589,7 +1589,7 @@ msgstr "Buchungen anzeigen" msgid "Search bookings" msgstr "Buchungen suchen" -#: src/Wordpress/CustomPostType/Timeframe.php:1159 +#: src/Wordpress/CustomPostType/Timeframe.php:1160 msgid "Timeframes not found" msgstr "Zeitrahmen wurden nicht gefunden" @@ -1606,12 +1606,12 @@ msgid "All bookings" msgstr "Alle Buchungen" #: src/Wordpress/CustomPostType/Booking.php:536 -#: src/Wordpress/CustomPostType/Timeframe.php:1163 +#: src/Wordpress/CustomPostType/Timeframe.php:1164 msgid "Timeframe archive" msgstr "Zeitrahmenarchiv" #: src/Wordpress/CustomPostType/Booking.php:537 -#: src/Wordpress/CustomPostType/Timeframe.php:1164 +#: src/Wordpress/CustomPostType/Timeframe.php:1165 msgid "Timeframe attributes" msgstr "Zeitrahmenattribute" @@ -1624,7 +1624,7 @@ msgid "Added to booking" msgstr "Zur Buchung hinzugefügt" #: src/Wordpress/CustomPostType/Booking.php:540 -#: src/Wordpress/CustomPostType/Timeframe.php:1167 +#: src/Wordpress/CustomPostType/Timeframe.php:1168 msgid "Timeframe image" msgstr "Zeitrahmenbild" @@ -1641,8 +1641,8 @@ msgid "use as booking image" msgstr "als Buchungsbild verwenden" #: src/Wordpress/CustomPostType/Booking.php:544 -#: src/Wordpress/CustomPostType/Timeframe.php:1150 -#: src/Wordpress/CustomPostType/Timeframe.php:1171 +#: src/Wordpress/CustomPostType/Timeframe.php:1151 +#: src/Wordpress/CustomPostType/Timeframe.php:1172 #: templates/dashboard-index.php:37 msgid "Timeframes" msgstr "Zeitrahmen" @@ -2185,7 +2185,7 @@ msgid "Blocked (not overbookable)" msgstr "Geblockt (nicht überbuchbar)" #: src/Wordpress/CustomPostType/Timeframe.php:420 -#: src/Wordpress/CustomPostType/Timeframe.php:1151 +#: src/Wordpress/CustomPostType/Timeframe.php:1152 msgid "Timeframe" msgstr "Zeitrahmen" @@ -2364,56 +2364,56 @@ msgstr "Monatlich" msgid "Yearly" msgstr "Jährlich" -#: src/Wordpress/CustomPostType/Timeframe.php:1153 -#: src/Wordpress/CustomPostType/Timeframe.php:1155 +#: src/Wordpress/CustomPostType/Timeframe.php:1154 +#: src/Wordpress/CustomPostType/Timeframe.php:1156 msgid "Add new timeframe" msgstr "Hinzufügen eines neuen Zeitrahmens" -#: src/Wordpress/CustomPostType/Timeframe.php:1154 +#: src/Wordpress/CustomPostType/Timeframe.php:1155 msgid "Edit timeframe" msgstr "Zeitrahmen bearbeiten" -#: src/Wordpress/CustomPostType/Timeframe.php:1156 +#: src/Wordpress/CustomPostType/Timeframe.php:1157 msgid "Show timeframe" msgstr "Zeitrahmen anzeigen" -#: src/Wordpress/CustomPostType/Timeframe.php:1157 +#: src/Wordpress/CustomPostType/Timeframe.php:1158 msgid "Show timeframes" msgstr "Zeitrahmen anzeigen" -#: src/Wordpress/CustomPostType/Timeframe.php:1158 +#: src/Wordpress/CustomPostType/Timeframe.php:1159 msgid "Search timeframes" msgstr "Zeitrahmen suchen" -#: src/Wordpress/CustomPostType/Timeframe.php:1160 +#: src/Wordpress/CustomPostType/Timeframe.php:1161 msgid "No timeframes found in trash" msgstr "Keine Zeitrahmen im Papierkorb gefunden" -#: src/Wordpress/CustomPostType/Timeframe.php:1161 +#: src/Wordpress/CustomPostType/Timeframe.php:1162 msgid "Parent timeframes:" msgstr "Übergeordnete Zeitrahmen:" -#: src/Wordpress/CustomPostType/Timeframe.php:1162 +#: src/Wordpress/CustomPostType/Timeframe.php:1163 msgid "All timeframes" msgstr "Alle Zeitrahmen" -#: src/Wordpress/CustomPostType/Timeframe.php:1165 +#: src/Wordpress/CustomPostType/Timeframe.php:1166 msgid "Add to timeframe" msgstr "Zum Zeitrahmen hinzufügen" -#: src/Wordpress/CustomPostType/Timeframe.php:1166 +#: src/Wordpress/CustomPostType/Timeframe.php:1167 msgid "Added to timeframe" msgstr "Zum Zeitrahmen hinzugefügt" -#: src/Wordpress/CustomPostType/Timeframe.php:1168 +#: src/Wordpress/CustomPostType/Timeframe.php:1169 msgid "set timeframe image" msgstr "Festlegen des Zeitrahmenbilds" -#: src/Wordpress/CustomPostType/Timeframe.php:1169 +#: src/Wordpress/CustomPostType/Timeframe.php:1170 msgid "remove timeframe image" msgstr "Zeitrahmenbild entfernen" -#: src/Wordpress/CustomPostType/Timeframe.php:1170 +#: src/Wordpress/CustomPostType/Timeframe.php:1171 msgid "use as timeframe image" msgstr "Verwendung als Zeitrahmenbild" diff --git a/languages/commonsbooking.pot b/languages/commonsbooking.pot index a7a327936..c61c10689 100644 --- a/languages/commonsbooking.pot +++ b/languages/commonsbooking.pot @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2026-06-03T16:34:23+00:00\n" +"POT-Creation-Date: 2026-06-15T14:16:27+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.12.0\n" "X-Domain: commonsbooking\n" @@ -2421,7 +2421,7 @@ msgstr "" #: src/Wordpress/CustomPostType/Item.php:118 #: src/Wordpress/CustomPostType/Location.php:140 #: src/Wordpress/CustomPostType/Restriction.php:307 -#: src/Wordpress/CustomPostType/Timeframe.php:1152 +#: src/Wordpress/CustomPostType/Timeframe.php:1153 msgid "Add new" msgstr "" @@ -2464,12 +2464,12 @@ msgid "All bookings" msgstr "" #: src/Wordpress/CustomPostType/Booking.php:536 -#: src/Wordpress/CustomPostType/Timeframe.php:1163 +#: src/Wordpress/CustomPostType/Timeframe.php:1164 msgid "Timeframe archive" msgstr "" #: src/Wordpress/CustomPostType/Booking.php:537 -#: src/Wordpress/CustomPostType/Timeframe.php:1164 +#: src/Wordpress/CustomPostType/Timeframe.php:1165 msgid "Timeframe attributes" msgstr "" @@ -2482,7 +2482,7 @@ msgid "Added to booking" msgstr "" #: src/Wordpress/CustomPostType/Booking.php:540 -#: src/Wordpress/CustomPostType/Timeframe.php:1167 +#: src/Wordpress/CustomPostType/Timeframe.php:1168 msgid "Timeframe image" msgstr "" @@ -2499,8 +2499,8 @@ msgid "use as booking image" msgstr "" #: src/Wordpress/CustomPostType/Booking.php:544 -#: src/Wordpress/CustomPostType/Timeframe.php:1150 -#: src/Wordpress/CustomPostType/Timeframe.php:1171 +#: src/Wordpress/CustomPostType/Timeframe.php:1151 +#: src/Wordpress/CustomPostType/Timeframe.php:1172 #: templates/dashboard-index.php:37 msgid "Timeframes" msgstr "" @@ -3651,7 +3651,7 @@ msgid "Select Dates:" msgstr "" #: src/Wordpress/CustomPostType/Timeframe.php:420 -#: src/Wordpress/CustomPostType/Timeframe.php:1151 +#: src/Wordpress/CustomPostType/Timeframe.php:1152 msgid "Timeframe" msgstr "" @@ -3936,60 +3936,60 @@ msgstr "" msgid "Orphaned bookings found, can migrate. Click here to migrate " msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1153 -#: src/Wordpress/CustomPostType/Timeframe.php:1155 +#: src/Wordpress/CustomPostType/Timeframe.php:1154 +#: src/Wordpress/CustomPostType/Timeframe.php:1156 msgid "Add new timeframe" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1154 +#: src/Wordpress/CustomPostType/Timeframe.php:1155 msgid "Edit timeframe" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1156 +#: src/Wordpress/CustomPostType/Timeframe.php:1157 msgid "Show timeframe" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1157 +#: src/Wordpress/CustomPostType/Timeframe.php:1158 msgid "Show timeframes" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1158 +#: src/Wordpress/CustomPostType/Timeframe.php:1159 msgid "Search timeframes" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1159 +#: src/Wordpress/CustomPostType/Timeframe.php:1160 msgid "Timeframes not found" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1160 +#: src/Wordpress/CustomPostType/Timeframe.php:1161 msgid "No timeframes found in trash" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1161 +#: src/Wordpress/CustomPostType/Timeframe.php:1162 msgid "Parent timeframes:" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1162 +#: src/Wordpress/CustomPostType/Timeframe.php:1163 msgid "All timeframes" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1165 +#: src/Wordpress/CustomPostType/Timeframe.php:1166 msgid "Add to timeframe" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1166 +#: src/Wordpress/CustomPostType/Timeframe.php:1167 msgid "Added to timeframe" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1168 +#: src/Wordpress/CustomPostType/Timeframe.php:1169 msgid "set timeframe image" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1169 +#: src/Wordpress/CustomPostType/Timeframe.php:1170 msgid "remove timeframe image" msgstr "" -#: src/Wordpress/CustomPostType/Timeframe.php:1170 +#: src/Wordpress/CustomPostType/Timeframe.php:1171 msgid "use as timeframe image" msgstr "" From b92872d81e7c81c5220939e2fa6df21090b8b0b2 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Mon, 15 Jun 2026 16:24:11 +0200 Subject: [PATCH 093/148] Prevent reopening existing bookings as unconfirmed Add guard to prevent setting existing bookings to unconfirmed. --- src/Wordpress/CustomPostType/Booking.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Wordpress/CustomPostType/Booking.php b/src/Wordpress/CustomPostType/Booking.php index 3895b9d0c..9b68907d5 100644 --- a/src/Wordpress/CustomPostType/Booking.php +++ b/src/Wordpress/CustomPostType/Booking.php @@ -298,6 +298,12 @@ public static function handleBookingRequest( return $booking->ID; } + // Frontend requests should never reopen an existing booking as unconfirmed by ID. + // Treat this as an invalid request instead of mutating the current booking state. + if ( $post_status === 'unconfirmed' && $post_ID !== null ) { + throw new BookingDeniedException( __( 'Invalid booking request. Please try again from the calendar.', 'commonsbooking' ) ); + } + $existingBookings = \CommonsBooking\Repository\Booking::getExistingBookings( $itemId, From 0f0e42a48726a2450f4b2f9c8f195e577b2d84be Mon Sep 17 00:00:00 2001 From: hansmorb Date: Wed, 17 Jun 2026 11:57:47 +0000 Subject: [PATCH 094/148] Ran wp i18n make-pot --- languages/commonsbooking-de_DE.po | 144 +++++++++++++++-------------- languages/commonsbooking.pot | 146 +++++++++++++++--------------- 2 files changed, 149 insertions(+), 141 deletions(-) diff --git a/languages/commonsbooking-de_DE.po b/languages/commonsbooking-de_DE.po index 7a0db97a9..997a4e4d9 100644 --- a/languages/commonsbooking-de_DE.po +++ b/languages/commonsbooking-de_DE.po @@ -1275,14 +1275,14 @@ msgid "Directory %s could not be written to." msgstr "Der Ordner %s ist nicht beschreibbar." #: src/View/Admin/Filter.php:58 -#: src/Wordpress/CustomPostType/Booking.php:779 +#: src/Wordpress/CustomPostType/Booking.php:792 #: src/Wordpress/CustomPostType/Restriction.php:451 #: src/Wordpress/CustomPostType/Timeframe.php:678 msgid "Start date" msgstr "Startdatum" #: src/View/Admin/Filter.php:62 -#: src/Wordpress/CustomPostType/Booking.php:796 +#: src/Wordpress/CustomPostType/Booking.php:809 #: src/Wordpress/CustomPostType/Restriction.php:461 #: src/Wordpress/CustomPostType/Timeframe.php:702 msgid "End date" @@ -1307,7 +1307,7 @@ msgstr "Nicht verfügbar" #: src/View/Booking.php:196 #: src/View/MassOperations.php:38 -#: src/Wordpress/CustomPostType/Booking.php:446 +#: src/Wordpress/CustomPostType/Booking.php:459 #: src/Wordpress/CustomPostType/Timeframe.php:97 #: templates/shortcode-bookings.php:74 msgid "User" @@ -1315,7 +1315,7 @@ msgstr "Nutzende*r" #: src/View/Booking.php:200 #: src/View/MassOperations.php:42 -#: src/Wordpress/CustomPostType/Booking.php:973 +#: src/Wordpress/CustomPostType/Booking.php:986 #: src/Wordpress/CustomPostType/Restriction.php:477 msgid "Status" msgstr "Status" @@ -1333,9 +1333,9 @@ msgid "Booking codes list" msgstr "Liste der Buchungscodes" #: src/View/Calendar.php:237 -#: src/Wordpress/CustomPostType/Booking.php:447 -#: src/Wordpress/CustomPostType/Booking.php:761 -#: src/Wordpress/CustomPostType/Booking.php:989 +#: src/Wordpress/CustomPostType/Booking.php:460 +#: src/Wordpress/CustomPostType/Booking.php:774 +#: src/Wordpress/CustomPostType/Booking.php:1002 #: src/Wordpress/CustomPostType/Item.php:117 #: src/Wordpress/CustomPostType/Restriction.php:48 #: src/Wordpress/CustomPostType/Restriction.php:438 @@ -1349,9 +1349,9 @@ msgid "No items found." msgstr "Keine Artikel gefunden." #: src/View/Calendar.php:238 -#: src/Wordpress/CustomPostType/Booking.php:448 -#: src/Wordpress/CustomPostType/Booking.php:767 -#: src/Wordpress/CustomPostType/Booking.php:985 +#: src/Wordpress/CustomPostType/Booking.php:461 +#: src/Wordpress/CustomPostType/Booking.php:780 +#: src/Wordpress/CustomPostType/Booking.php:998 #: src/Wordpress/CustomPostType/Location.php:139 #: src/Wordpress/CustomPostType/Restriction.php:49 #: src/Wordpress/CustomPostType/Restriction.php:431 @@ -1503,63 +1503,63 @@ msgstr "Standort existiert nicht. (%s)" msgid "Start- and/or end-date is missing." msgstr "Das Start- und/oder Enddatum fehlt." -#: src/Wordpress/CustomPostType/Booking.php:307 +#: src/Wordpress/CustomPostType/Booking.php:320 msgid "Booking canceled." msgstr "Buchung storniert." #: src/Wordpress/CustomPostType/Booking.php:291 -#: src/Wordpress/CustomPostType/Booking.php:323 +#: src/Wordpress/CustomPostType/Booking.php:336 msgid "There is already a booking in this time-range. This notice may also appear if there is an unconfirmed booking in the requested period. Unconfirmed bookings are deleted after about 10 minutes. Please try again in a few minutes." msgstr "Es gibt bereits eine Buchung in diesem Zeitraum. Dieser Hinweis kann auch erscheinen, wenn es eine unbestätigte Buchung in dem gewünschten Zeitraum gibt. Unbestätigte Buchungen werden nach etwa 10 Minuten gelöscht. Bitte versuche es in ein paar Minuten erneut." -#: src/Wordpress/CustomPostType/Booking.php:331 -#: src/Wordpress/CustomPostType/Booking.php:524 -#: src/Wordpress/CustomPostType/Booking.php:712 +#: src/Wordpress/CustomPostType/Booking.php:344 +#: src/Wordpress/CustomPostType/Booking.php:537 +#: src/Wordpress/CustomPostType/Booking.php:725 #: src/Wordpress/CustomPostType/Timeframe.php:132 msgid "Booking" msgstr "Buchung" -#: src/Wordpress/CustomPostType/Booking.php:375 +#: src/Wordpress/CustomPostType/Booking.php:388 msgid "There was an error while saving the booking. Please try again. Thrown error:" msgstr "Es gab einen Fehler während der Buchung. Geworfener Fehler:" -#: src/Wordpress/CustomPostType/Booking.php:392 +#: src/Wordpress/CustomPostType/Booking.php:405 msgid "There was an error while saving the booking. Please try again. Resulting WP_ERROR: " msgstr "Es gab einen Fehler während der Buchung. WP_ERROR: " -#: src/Wordpress/CustomPostType/Booking.php:449 +#: src/Wordpress/CustomPostType/Booking.php:462 msgid "Bookingdate" msgstr "Buchungsdatum" -#: src/Wordpress/CustomPostType/Booking.php:450 +#: src/Wordpress/CustomPostType/Booking.php:463 #: src/Wordpress/CustomPostType/Restriction.php:50 #: src/Wordpress/CustomPostType/Timeframe.php:101 #: src/Wordpress/CustomPostType/Timeframe.php:758 msgid "Start Date" msgstr "Startdatum" -#: src/Wordpress/CustomPostType/Booking.php:451 +#: src/Wordpress/CustomPostType/Booking.php:464 #: src/Wordpress/CustomPostType/Restriction.php:51 #: src/Wordpress/CustomPostType/Timeframe.php:102 msgid "End Date" msgstr "Enddatum" -#: src/Wordpress/CustomPostType/Booking.php:452 +#: src/Wordpress/CustomPostType/Booking.php:465 msgid "Booking Status" msgstr "Buchungsstatus" -#: src/Wordpress/CustomPostType/Booking.php:453 -#: src/Wordpress/CustomPostType/Booking.php:981 +#: src/Wordpress/CustomPostType/Booking.php:466 +#: src/Wordpress/CustomPostType/Booking.php:994 #: src/Wordpress/CustomPostType/Timeframe.php:448 msgid "Comment" msgstr "Kommentar" -#: src/Wordpress/CustomPostType/Booking.php:523 +#: src/Wordpress/CustomPostType/Booking.php:536 #: templates/dashboard-index.php:45 msgid "Bookings" msgstr "Buchungen" -#: src/Wordpress/CustomPostType/Booking.php:525 +#: src/Wordpress/CustomPostType/Booking.php:538 #: src/Wordpress/CustomPostType/Item.php:118 #: src/Wordpress/CustomPostType/Location.php:140 #: src/Wordpress/CustomPostType/Restriction.php:307 @@ -1567,25 +1567,25 @@ msgstr "Buchungen" msgid "Add new" msgstr "Neu hinzufügen" -#: src/Wordpress/CustomPostType/Booking.php:526 -#: src/Wordpress/CustomPostType/Booking.php:528 +#: src/Wordpress/CustomPostType/Booking.php:539 +#: src/Wordpress/CustomPostType/Booking.php:541 msgid "Add new booking" msgstr "Neue Buchung hinzufügen" -#: src/Wordpress/CustomPostType/Booking.php:527 -#: src/Wordpress/CustomPostType/Booking.php:743 +#: src/Wordpress/CustomPostType/Booking.php:540 +#: src/Wordpress/CustomPostType/Booking.php:756 msgid "Edit booking" msgstr "Buchung bearbeiten" -#: src/Wordpress/CustomPostType/Booking.php:529 +#: src/Wordpress/CustomPostType/Booking.php:542 msgid "Show booking" msgstr "Buchung anzeigen" -#: src/Wordpress/CustomPostType/Booking.php:530 +#: src/Wordpress/CustomPostType/Booking.php:543 msgid "Show bookings" msgstr "Buchungen anzeigen" -#: src/Wordpress/CustomPostType/Booking.php:531 +#: src/Wordpress/CustomPostType/Booking.php:544 msgid "Search bookings" msgstr "Buchungen suchen" @@ -1593,99 +1593,99 @@ msgstr "Buchungen suchen" msgid "Timeframes not found" msgstr "Zeitrahmen wurden nicht gefunden" -#: src/Wordpress/CustomPostType/Booking.php:533 +#: src/Wordpress/CustomPostType/Booking.php:546 msgid "No bookings found in trash" msgstr "Keine Buchungen im Papierkorb gefunden" -#: src/Wordpress/CustomPostType/Booking.php:534 +#: src/Wordpress/CustomPostType/Booking.php:547 msgid "Parent bookings:" msgstr "Übergeordnete Buchungen:" -#: src/Wordpress/CustomPostType/Booking.php:535 +#: src/Wordpress/CustomPostType/Booking.php:548 msgid "All bookings" msgstr "Alle Buchungen" -#: src/Wordpress/CustomPostType/Booking.php:536 +#: src/Wordpress/CustomPostType/Booking.php:549 #: src/Wordpress/CustomPostType/Timeframe.php:1164 msgid "Timeframe archive" msgstr "Zeitrahmenarchiv" -#: src/Wordpress/CustomPostType/Booking.php:537 +#: src/Wordpress/CustomPostType/Booking.php:550 #: src/Wordpress/CustomPostType/Timeframe.php:1165 msgid "Timeframe attributes" msgstr "Zeitrahmenattribute" -#: src/Wordpress/CustomPostType/Booking.php:538 +#: src/Wordpress/CustomPostType/Booking.php:551 msgid "Add to booking" msgstr "Der Buchung hinzufügen" -#: src/Wordpress/CustomPostType/Booking.php:539 +#: src/Wordpress/CustomPostType/Booking.php:552 msgid "Added to booking" msgstr "Zur Buchung hinzugefügt" -#: src/Wordpress/CustomPostType/Booking.php:540 +#: src/Wordpress/CustomPostType/Booking.php:553 #: src/Wordpress/CustomPostType/Timeframe.php:1168 msgid "Timeframe image" msgstr "Zeitrahmenbild" -#: src/Wordpress/CustomPostType/Booking.php:541 +#: src/Wordpress/CustomPostType/Booking.php:554 msgid "set booking image" msgstr "Buchungsbild festlegen" -#: src/Wordpress/CustomPostType/Booking.php:542 +#: src/Wordpress/CustomPostType/Booking.php:555 msgid "remove booking image" msgstr "Buchungsbild entfernen" -#: src/Wordpress/CustomPostType/Booking.php:543 +#: src/Wordpress/CustomPostType/Booking.php:556 msgid "use as booking image" msgstr "als Buchungsbild verwenden" -#: src/Wordpress/CustomPostType/Booking.php:544 +#: src/Wordpress/CustomPostType/Booking.php:557 #: src/Wordpress/CustomPostType/Timeframe.php:1151 #: src/Wordpress/CustomPostType/Timeframe.php:1172 #: templates/dashboard-index.php:37 msgid "Timeframes" msgstr "Zeitrahmen" -#: src/Wordpress/CustomPostType/Booking.php:852 +#: src/Wordpress/CustomPostType/Booking.php:865 msgid "External comment" msgstr "Öffentlicher Kommentar" -#: src/Wordpress/CustomPostType/Booking.php:853 +#: src/Wordpress/CustomPostType/Booking.php:866 msgid "This comment can be seen by users in booking details. It can be set by users during the booking confirmation process if comments are enabled in settings." msgstr "Dieser Kommentar ist intern für Zeitrahmen wie buchbar, Reparatur, Urlaub. Wenn es sich um eine Buchung handelt, kann dieser Kommentar von den Benutzenden während des Buchungsbestätigungsprozesses eingegeben werden." -#: src/Wordpress/CustomPostType/Booking.php:858 +#: src/Wordpress/CustomPostType/Booking.php:871 #: templates/booking-single.php:131 msgid "Internal comment" msgstr "Interner Kommentar" -#: src/Wordpress/CustomPostType/Booking.php:859 +#: src/Wordpress/CustomPostType/Booking.php:872 msgid "This internal comment can only be seen in the backend by privileged users like admins or cb-managers" msgstr "Dieser interne Kommentar kann im Backend nur von autorisierten Nutzenden wie Admins oder CB-Managern gesehen werden" -#: src/Wordpress/CustomPostType/Booking.php:780 +#: src/Wordpress/CustomPostType/Booking.php:793 msgid "Set the start date. You must set the time to 00:00 if you want to book the full day " msgstr "Lege das Startdatum fest. Setze die Uhrzeit auf 00:00, wenn du den ganzen Tag buchen willst " -#: src/Wordpress/CustomPostType/Booking.php:797 +#: src/Wordpress/CustomPostType/Booking.php:810 msgid "Set the end date. You must set time to 23:59 if you want to book the full day" msgstr "Lege das Enddatum fest. Setze die Zeit auf 23:59 Uhr, wenn du den ganzen Tag buchen willst" -#: src/Wordpress/CustomPostType/Booking.php:813 +#: src/Wordpress/CustomPostType/Booking.php:826 #: templates/booking-single.php:59 msgid "Booking Code" msgstr "Buchungscode" -#: src/Wordpress/CustomPostType/Booking.php:819 +#: src/Wordpress/CustomPostType/Booking.php:832 msgid "Booking User" msgstr "Buchende Person" -#: src/Wordpress/CustomPostType/Booking.php:834 +#: src/Wordpress/CustomPostType/Booking.php:847 msgid "Admin Booking User" msgstr "Admin Booking Konto" -#: src/Wordpress/CustomPostType/Booking.php:845 +#: src/Wordpress/CustomPostType/Booking.php:858 msgid "This is the admin user who created or modified this booking." msgstr "Dies ist der/die Admin-Nutzende, der diese Buchung erstellt oder geändert hat." @@ -3031,35 +3031,35 @@ msgstr "Die Start- und Endzeit des Zeitrahmens dürfen nicht gleich sein. Wenn d #: src/Plugin.php:720 #: src/Plugin.php:735 -#: src/Wordpress/CustomPostType/Booking.php:936 +#: src/Wordpress/CustomPostType/Booking.php:949 msgid "CommonsBooking Bookings" msgstr "CommonsBooking Buchungen" -#: src/Wordpress/CustomPostType/Booking.php:532 +#: src/Wordpress/CustomPostType/Booking.php:545 msgid "Bookings not found" msgstr "Keine Buchungen gefunden" -#: src/Wordpress/CustomPostType/Booking.php:961 +#: src/Wordpress/CustomPostType/Booking.php:974 msgid "Booking start" msgstr "Buchungsbeginn" -#: src/Wordpress/CustomPostType/Booking.php:965 +#: src/Wordpress/CustomPostType/Booking.php:978 msgid "Booking end" msgstr "Buchungsende" -#: src/Wordpress/CustomPostType/Booking.php:969 +#: src/Wordpress/CustomPostType/Booking.php:982 msgid "Time of booking" msgstr "Buchungszeit" -#: src/Wordpress/CustomPostType/Booking.php:977 +#: src/Wordpress/CustomPostType/Booking.php:990 msgid "Booking code" msgstr "Buchungscode" -#: src/Wordpress/CustomPostType/Booking.php:993 +#: src/Wordpress/CustomPostType/Booking.php:1006 msgid "Time of cancellation" msgstr "Storniert am" -#: src/Wordpress/CustomPostType/Booking.php:997 +#: src/Wordpress/CustomPostType/Booking.php:1010 msgid "Admin booking by" msgstr "Adminbuchung von" @@ -3888,23 +3888,23 @@ msgid "Startdate is missing. Please enter a start date to publish this timeframe msgstr "Das Startdatum fehlt. Ein Startdatum muss eingegeben werden, damit der Zeitrahmen veröffentlicht werden kann." #: src/View/Booking.php:578 -#: src/Wordpress/CustomPostType/Booking.php:864 +#: src/Wordpress/CustomPostType/Booking.php:877 msgid "Submit booking" msgstr "Buchung abschicken" -#: src/Wordpress/CustomPostType/Booking.php:773 +#: src/Wordpress/CustomPostType/Booking.php:786 msgid "Book full day" msgstr "Ganztägig buchen" -#: src/Wordpress/CustomPostType/Booking.php:776 +#: src/Wordpress/CustomPostType/Booking.php:789 msgid "The booking should apply to the entire day(s)" msgstr "Die Buchung soll auf den gesamten Tag / die gesamten Tage angewendet werden" -#: src/Wordpress/CustomPostType/Booking.php:816 +#: src/Wordpress/CustomPostType/Booking.php:829 msgid "Valid booking code will be automatically retrieved for bookings that apply to the full day." msgstr "Ein gültiger Buchungscode wird automatisch für Buchungen, die sich auf den ganzen Tag beziehen, generiert." -#: src/Wordpress/CustomPostType/Booking.php:825 +#: src/Wordpress/CustomPostType/Booking.php:838 msgid "" "Here you must select the user for whom the booking is made.
\n" " If the booking was made by a user via frontend booking process, the user will be shown in this field.\n" @@ -3914,7 +3914,7 @@ msgstr "" " 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:865 +#: src/Wordpress/CustomPostType/Booking.php:878 msgid "This will create the specified booking and send out the booking confirmation email." msgstr "Dadurch wird die angegebene Buchung erstellt und die Buchungsbestätigung per E-Mail verschickt." @@ -4450,7 +4450,7 @@ msgstr "" msgid "When this box is checked, the item will not appear in any of the API shares." msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:745 +#: src/Wordpress/CustomPostType/Booking.php:758 msgid "" "

Notice

In this view, you as an admin can create or modify existing bookings. Please use it with caution.
\n" "\t\t\t\t

    \n" @@ -4462,7 +4462,7 @@ msgid "" "\t\t\t\t" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:888 +#: src/Wordpress/CustomPostType/Booking.php:901 #, php-format msgid "" "Bookings should be created via frontend booking calendar.
    \n" @@ -4472,3 +4472,7 @@ msgid "" "\t\tTo search and filter bookings please integrate the frontend booking list via shortcode.\n" "\t\tSee here %1$sHow to display the booking list%2$s" msgstr "" + +#: src/Wordpress/CustomPostType/Booking.php:304 +msgid "Invalid booking request. Please try again from the calendar." +msgstr "" diff --git a/languages/commonsbooking.pot b/languages/commonsbooking.pot index c61c10689..9c9d46698 100644 --- a/languages/commonsbooking.pot +++ b/languages/commonsbooking.pot @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2026-06-15T14:16:27+00:00\n" +"POT-Creation-Date: 2026-06-17T11:57:44+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.12.0\n" "X-Domain: commonsbooking\n" @@ -1666,7 +1666,7 @@ msgstr "" #: src/Plugin.php:720 #: src/Plugin.php:735 -#: src/Wordpress/CustomPostType/Booking.php:936 +#: src/Wordpress/CustomPostType/Booking.php:949 msgid "CommonsBooking Bookings" msgstr "" @@ -1992,14 +1992,14 @@ msgid "" msgstr "" #: src/View/Admin/Filter.php:58 -#: src/Wordpress/CustomPostType/Booking.php:779 +#: src/Wordpress/CustomPostType/Booking.php:792 #: src/Wordpress/CustomPostType/Restriction.php:451 #: src/Wordpress/CustomPostType/Timeframe.php:678 msgid "Start date" msgstr "" #: src/View/Admin/Filter.php:62 -#: src/Wordpress/CustomPostType/Booking.php:796 +#: src/Wordpress/CustomPostType/Booking.php:809 #: src/Wordpress/CustomPostType/Restriction.php:461 #: src/Wordpress/CustomPostType/Timeframe.php:702 msgid "End date" @@ -2024,7 +2024,7 @@ msgstr "" #: src/View/Booking.php:196 #: src/View/MassOperations.php:38 -#: src/Wordpress/CustomPostType/Booking.php:446 +#: src/Wordpress/CustomPostType/Booking.php:459 #: src/Wordpress/CustomPostType/Timeframe.php:97 #: templates/shortcode-bookings.php:74 msgid "User" @@ -2032,7 +2032,7 @@ msgstr "" #: src/View/Booking.php:200 #: src/View/MassOperations.php:42 -#: src/Wordpress/CustomPostType/Booking.php:973 +#: src/Wordpress/CustomPostType/Booking.php:986 #: src/Wordpress/CustomPostType/Restriction.php:477 msgid "Status" msgstr "" @@ -2042,7 +2042,7 @@ msgid "Code" msgstr "" #: src/View/Booking.php:578 -#: src/Wordpress/CustomPostType/Booking.php:864 +#: src/Wordpress/CustomPostType/Booking.php:877 msgid "Submit booking" msgstr "" @@ -2148,9 +2148,9 @@ msgid "No items found." msgstr "" #: src/View/Calendar.php:237 -#: src/Wordpress/CustomPostType/Booking.php:447 -#: src/Wordpress/CustomPostType/Booking.php:761 -#: src/Wordpress/CustomPostType/Booking.php:989 +#: src/Wordpress/CustomPostType/Booking.php:460 +#: src/Wordpress/CustomPostType/Booking.php:774 +#: src/Wordpress/CustomPostType/Booking.php:1002 #: src/Wordpress/CustomPostType/Item.php:117 #: src/Wordpress/CustomPostType/Restriction.php:48 #: src/Wordpress/CustomPostType/Restriction.php:438 @@ -2160,9 +2160,9 @@ msgid "Item" msgstr "" #: src/View/Calendar.php:238 -#: src/Wordpress/CustomPostType/Booking.php:448 -#: src/Wordpress/CustomPostType/Booking.php:767 -#: src/Wordpress/CustomPostType/Booking.php:985 +#: src/Wordpress/CustomPostType/Booking.php:461 +#: src/Wordpress/CustomPostType/Booking.php:780 +#: src/Wordpress/CustomPostType/Booking.php:998 #: src/Wordpress/CustomPostType/Location.php:139 #: src/Wordpress/CustomPostType/Restriction.php:49 #: src/Wordpress/CustomPostType/Restriction.php:431 @@ -2362,62 +2362,66 @@ msgid "Your reservation has expired, please try to book again" msgstr "" #: src/Wordpress/CustomPostType/Booking.php:291 -#: src/Wordpress/CustomPostType/Booking.php:323 +#: src/Wordpress/CustomPostType/Booking.php:336 msgid "There is already a booking in this time-range. This notice may also appear if there is an unconfirmed booking in the requested period. Unconfirmed bookings are deleted after about 10 minutes. Please try again in a few minutes." msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:307 +#: src/Wordpress/CustomPostType/Booking.php:304 +msgid "Invalid booking request. Please try again from the calendar." +msgstr "" + +#: src/Wordpress/CustomPostType/Booking.php:320 msgid "Booking canceled." msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:331 -#: src/Wordpress/CustomPostType/Booking.php:524 -#: src/Wordpress/CustomPostType/Booking.php:712 +#: src/Wordpress/CustomPostType/Booking.php:344 +#: src/Wordpress/CustomPostType/Booking.php:537 +#: src/Wordpress/CustomPostType/Booking.php:725 #: src/Wordpress/CustomPostType/Timeframe.php:132 msgid "Booking" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:375 +#: src/Wordpress/CustomPostType/Booking.php:388 msgid "There was an error while saving the booking. Please try again. Thrown error:" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:392 +#: src/Wordpress/CustomPostType/Booking.php:405 msgid "There was an error while saving the booking. Please try again. Resulting WP_ERROR: " msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:449 +#: src/Wordpress/CustomPostType/Booking.php:462 msgid "Bookingdate" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:450 +#: src/Wordpress/CustomPostType/Booking.php:463 #: src/Wordpress/CustomPostType/Restriction.php:50 #: src/Wordpress/CustomPostType/Timeframe.php:101 #: src/Wordpress/CustomPostType/Timeframe.php:758 msgid "Start Date" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:451 +#: src/Wordpress/CustomPostType/Booking.php:464 #: src/Wordpress/CustomPostType/Restriction.php:51 #: src/Wordpress/CustomPostType/Timeframe.php:102 msgid "End Date" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:452 +#: src/Wordpress/CustomPostType/Booking.php:465 msgid "Booking Status" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:453 -#: src/Wordpress/CustomPostType/Booking.php:981 +#: src/Wordpress/CustomPostType/Booking.php:466 +#: src/Wordpress/CustomPostType/Booking.php:994 #: src/Wordpress/CustomPostType/Timeframe.php:448 msgid "Comment" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:523 +#: src/Wordpress/CustomPostType/Booking.php:536 #: templates/dashboard-index.php:45 msgid "Bookings" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:525 +#: src/Wordpress/CustomPostType/Booking.php:538 #: src/Wordpress/CustomPostType/Item.php:118 #: src/Wordpress/CustomPostType/Location.php:140 #: src/Wordpress/CustomPostType/Restriction.php:307 @@ -2425,87 +2429,87 @@ msgstr "" msgid "Add new" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:526 -#: src/Wordpress/CustomPostType/Booking.php:528 +#: src/Wordpress/CustomPostType/Booking.php:539 +#: src/Wordpress/CustomPostType/Booking.php:541 msgid "Add new booking" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:527 -#: src/Wordpress/CustomPostType/Booking.php:743 +#: src/Wordpress/CustomPostType/Booking.php:540 +#: src/Wordpress/CustomPostType/Booking.php:756 msgid "Edit booking" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:529 +#: src/Wordpress/CustomPostType/Booking.php:542 msgid "Show booking" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:530 +#: src/Wordpress/CustomPostType/Booking.php:543 msgid "Show bookings" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:531 +#: src/Wordpress/CustomPostType/Booking.php:544 msgid "Search bookings" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:532 +#: src/Wordpress/CustomPostType/Booking.php:545 msgid "Bookings not found" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:533 +#: src/Wordpress/CustomPostType/Booking.php:546 msgid "No bookings found in trash" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:534 +#: src/Wordpress/CustomPostType/Booking.php:547 msgid "Parent bookings:" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:535 +#: src/Wordpress/CustomPostType/Booking.php:548 msgid "All bookings" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:536 +#: src/Wordpress/CustomPostType/Booking.php:549 #: src/Wordpress/CustomPostType/Timeframe.php:1164 msgid "Timeframe archive" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:537 +#: src/Wordpress/CustomPostType/Booking.php:550 #: src/Wordpress/CustomPostType/Timeframe.php:1165 msgid "Timeframe attributes" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:538 +#: src/Wordpress/CustomPostType/Booking.php:551 msgid "Add to booking" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:539 +#: src/Wordpress/CustomPostType/Booking.php:552 msgid "Added to booking" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:540 +#: src/Wordpress/CustomPostType/Booking.php:553 #: src/Wordpress/CustomPostType/Timeframe.php:1168 msgid "Timeframe image" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:541 +#: src/Wordpress/CustomPostType/Booking.php:554 msgid "set booking image" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:542 +#: src/Wordpress/CustomPostType/Booking.php:555 msgid "remove booking image" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:543 +#: src/Wordpress/CustomPostType/Booking.php:556 msgid "use as booking image" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:544 +#: src/Wordpress/CustomPostType/Booking.php:557 #: src/Wordpress/CustomPostType/Timeframe.php:1151 #: src/Wordpress/CustomPostType/Timeframe.php:1172 #: templates/dashboard-index.php:37 msgid "Timeframes" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:745 +#: src/Wordpress/CustomPostType/Booking.php:758 msgid "" "

    Notice

    In this view, you as an admin can create or modify existing bookings. Please use it with caution.
    \n" "\t\t\t\t

      \n" @@ -2517,72 +2521,72 @@ msgid "" "\t\t\t\t" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:773 +#: src/Wordpress/CustomPostType/Booking.php:786 msgid "Book full day" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:776 +#: src/Wordpress/CustomPostType/Booking.php:789 msgid "The booking should apply to the entire day(s)" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:780 +#: src/Wordpress/CustomPostType/Booking.php:793 msgid "Set the start date. You must set the time to 00:00 if you want to book the full day " msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:797 +#: src/Wordpress/CustomPostType/Booking.php:810 msgid "Set the end date. You must set time to 23:59 if you want to book the full day" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:813 +#: src/Wordpress/CustomPostType/Booking.php:826 #: templates/booking-single.php:59 msgid "Booking Code" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:816 +#: src/Wordpress/CustomPostType/Booking.php:829 msgid "Valid booking code will be automatically retrieved for bookings that apply to the full day." msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:819 +#: src/Wordpress/CustomPostType/Booking.php:832 msgid "Booking User" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:825 +#: src/Wordpress/CustomPostType/Booking.php:838 msgid "" "Here you must select the user for whom the booking is made.
      \n" " 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 "" -#: src/Wordpress/CustomPostType/Booking.php:834 +#: src/Wordpress/CustomPostType/Booking.php:847 msgid "Admin Booking User" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:845 +#: src/Wordpress/CustomPostType/Booking.php:858 msgid "This is the admin user who created or modified this booking." msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:852 +#: src/Wordpress/CustomPostType/Booking.php:865 msgid "External comment" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:853 +#: src/Wordpress/CustomPostType/Booking.php:866 msgid "This comment can be seen by users in booking details. It can be set by users during the booking confirmation process if comments are enabled in settings." msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:858 +#: src/Wordpress/CustomPostType/Booking.php:871 #: templates/booking-single.php:131 msgid "Internal comment" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:859 +#: src/Wordpress/CustomPostType/Booking.php:872 msgid "This internal comment can only be seen in the backend by privileged users like admins or cb-managers" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:865 +#: src/Wordpress/CustomPostType/Booking.php:878 msgid "This will create the specified booking and send out the booking confirmation email." msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:888 +#: src/Wordpress/CustomPostType/Booking.php:901 #, php-format msgid "" "Bookings should be created via frontend booking calendar.
      \n" @@ -2593,27 +2597,27 @@ msgid "" "\t\tSee here %1$sHow to display the booking list%2$s" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:961 +#: src/Wordpress/CustomPostType/Booking.php:974 msgid "Booking start" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:965 +#: src/Wordpress/CustomPostType/Booking.php:978 msgid "Booking end" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:969 +#: src/Wordpress/CustomPostType/Booking.php:982 msgid "Time of booking" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:977 +#: src/Wordpress/CustomPostType/Booking.php:990 msgid "Booking code" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:993 +#: src/Wordpress/CustomPostType/Booking.php:1006 msgid "Time of cancellation" msgstr "" -#: src/Wordpress/CustomPostType/Booking.php:997 +#: src/Wordpress/CustomPostType/Booking.php:1010 msgid "Admin booking by" msgstr "" From 6720439943993ce091351753a78e4ac38ee73b8b Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Wed, 17 Jun 2026 15:27:21 +0200 Subject: [PATCH 095/148] fix booking denied string --- src/Wordpress/CustomPostType/Booking.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Wordpress/CustomPostType/Booking.php b/src/Wordpress/CustomPostType/Booking.php index 9b68907d5..c04cc194c 100644 --- a/src/Wordpress/CustomPostType/Booking.php +++ b/src/Wordpress/CustomPostType/Booking.php @@ -301,7 +301,7 @@ public static function handleBookingRequest( // Frontend requests should never reopen an existing booking as unconfirmed by ID. // Treat this as an invalid request instead of mutating the current booking state. if ( $post_status === 'unconfirmed' && $post_ID !== null ) { - throw new BookingDeniedException( __( 'Invalid booking request. Please try again from the calendar.', 'commonsbooking' ) ); + throw new BookingDeniedException( __( 'Invalid booking request. Please try again.', 'commonsbooking' ) ); } $existingBookings = From 5d53bffa1d30a506548018bfaf2e4ce614615940 Mon Sep 17 00:00:00 2001 From: hansmorb Date: Wed, 17 Jun 2026 13:27:51 +0000 Subject: [PATCH 096/148] Ran wp i18n make-pot --- languages/commonsbooking-de_DE.po | 2 +- languages/commonsbooking.pot | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/languages/commonsbooking-de_DE.po b/languages/commonsbooking-de_DE.po index 997a4e4d9..cfad8aae1 100644 --- a/languages/commonsbooking-de_DE.po +++ b/languages/commonsbooking-de_DE.po @@ -4474,5 +4474,5 @@ msgid "" msgstr "" #: src/Wordpress/CustomPostType/Booking.php:304 -msgid "Invalid booking request. Please try again from the calendar." +msgid "Invalid booking request. Please try again." msgstr "" diff --git a/languages/commonsbooking.pot b/languages/commonsbooking.pot index 9c9d46698..06258bcfc 100644 --- a/languages/commonsbooking.pot +++ b/languages/commonsbooking.pot @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2026-06-17T11:57:44+00:00\n" +"POT-Creation-Date: 2026-06-17T13:27:47+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.12.0\n" "X-Domain: commonsbooking\n" @@ -2367,7 +2367,7 @@ msgid "There is already a booking in this time-range. This notice may also appea msgstr "" #: src/Wordpress/CustomPostType/Booking.php:304 -msgid "Invalid booking request. Please try again from the calendar." +msgid "Invalid booking request. Please try again." msgstr "" #: src/Wordpress/CustomPostType/Booking.php:320 From 10507fb38bc850e81ac4c21dbbef474e76ed3842 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Wed, 17 Jun 2026 15:49:16 +0200 Subject: [PATCH 097/148] added strings for 2.11 --- languages/commonsbooking-de_DE.mo | Bin 133742 -> 134829 bytes languages/commonsbooking-de_DE.po | 302 ++++++++++++------------------ 2 files changed, 118 insertions(+), 184 deletions(-) diff --git a/languages/commonsbooking-de_DE.mo b/languages/commonsbooking-de_DE.mo index c79a46cd8bb2b2b168172777cd11fcdb14e207dc..fae1c549bbc23193284683a60a5d015ddeb4ca29 100644 GIT binary patch delta 22269 zcmciKcXSoi!uRo+&`W^OJBQvw2}MH>O+b3@gyf`<1}RAOND~360Yed_3J59)5~M3A zqSB;XP!LdxO1Du|c)q{0H}`tidj5LXdY@T$^Vx0o?Ac}JoCDrF3v<4^Jg4uwf>{?i z9DA}jPHFtBjN|;B)p0H~QLf{h=;}B_UB@|zdq~&oPQW{uz&V~Cj&qLmoZgPJ45Ry) zcCz$!oMNOsSQwwf;@BCBViaaLj?bA$qy!m7`Z-Q1tb=NO(H<~aN4_&TrS{7${dXzG(5z{z#-w^(k(^*K)EIL9eZ zg}(8QQx3;sWn6-la6eYSt2hdCBrqyC7Q?V(A^~S31LB;+9C!h9;Z@9ocQ7YD#@v`C z$#I5oeJ39g-FX74!VJud3$QxAh1u~4=EoCQ94})5e1tkb_egW$Dp-hgFsgnSs=Xdq z0Ec1_jzpg-OeRtg7hpbIhwAZmRQUlcfG1FMdBvvxKut{!hD8k)LA6sAH3FeF9fmr; zw>1iN-bl(bU`%~gX+*rs0+`=hM0j3@F>>8fK(PD z)b0c@P!H9;EA{Zg>g?a(!nW5zWmC)X*J5HFye# z;&s#=wVPnJVK{08Vo>#`VNqO&nyO8xIsOng-~p_Pu@lXW&c`Ek@Bp^;5t&IR4pZU8 zD`xH&PcnD19E*^@5%=PL)B|baWabf9qt<|Tia9RcqgQX6QEo_8O zuq`&6#`yOmGJcv_6sNHQ=|8PyUo{Q3LN(X{E8-B;+L(;mrgKo+cLQp~PGWJqfx01Q zI?sKVyT@!KV_!3CC+RhYUU#ydj8>S5t??0F#%43vt5|lX>G^JKPx=>ZhoQ5Kldvu6 z&rx%q?{(9`5}1Q@Wvq;~F(>xKmN>{qL_@zEbti{0FJ3`)><(&*o}dOH}p7&yngwteA5R+AAr*UarjtVQ}hR>HFL%-gXw zszYAPj%hZ30@f$J0{ugeok-un0T?ph-0>W11~wsorAhmo3%1}IYN+nuBm4vRN>?yyQm!I=lV{F&1j8k zxUUK@*5;2z?bq3;3$C;7Ky~mi4#hL5Ic}I?wp|<49eXhvM`CF_hkfyP^r=Uk7n>pK zh3fGTn~p}EFba#~98?F^V^-XW#c(fb&78pxFkp#!)P9KN*mgOWaxPX|#_qyQwv^8Q zb2;N*iioqq3{7baC0P+Qw?i-hU&gaI3HxEcx6I<)itmv=i+ym~O7m8`fa^#%UqvVJ zDh6`l<*f8@(wo*WDj2xd$IF69%3AY)@Nm{3Dvp1fk6n0fJqwZYF&oXDC%t2)<`vYP z%|ngAmQChK_&I8XZlDJrVht?8MU>wL^`z{L=P<@cL_^W)T{D;MP;=kQrXx`oNJg#V znW#Blhok@nh^y`sw>-P4wSl8cxQt1R^a;1BNK5-Z#55^ z78po{a8yG{7=&X`+h(RsuRyJxEvP&C%6bV4kp2Z#KMN~T>0+qGTn)=$Tg<2ZAK{NM z#Hb5T!h$##gK#x^a64+K&!Fz?8fr-IVLp6}8tPozOny1k)Ky32w?ftHi{&v2gSfu) z8WHtyDQ3YxnvVFc!o_ zRL3Tvo;NE{9bC7Q@z!w z$AK8Si-nDEU{S2G+q^|vp+;oTZpJ^D$T%`Wa3d;x5jA&t_n0BBgw;tmK;6+0EQO=6 z5Y9&3@ha3B`oN|SU}@4PQETQ7s{9dZ1akQJV5cF;kGfz{9E8F6JkG-B@Ke;tJi!Lo zV4vwoENZPxz`8gCwQYA{0v^D^7`)$naA}PlNzbxr-&rE6Q1*bigAh~?+t_pu)E!5l zR_$oi1s7Y_p>E&<)JS}UYVRnj!{4LUSn-d|C!l6nm2?C$;yz~k7=0q6Z77m zj3r2i9W+BY2sPwmu`Dh^b#yz{#!syGP|uCBhs=YlDr!-Npz@ocZlE3d_kT|!<;WP0 znu5uwic7IHu0dV!0BUG2+45^xgY+G&g(W^U7ix!^>u#tK8HjqKCZR@VJgVdKu!4`s z3R~f0)KDKqop>3wYJWoy=K0L5+FGdmj@T5#Q4gvWsI{{Nb)mq+=1wc1>eoRYxlTLG zjd3ZwDD=ghwvXmiBed2bv^ItF#Y^QbAgjoRnREy2f=Ndif4%+ok<{-TV)$mSK{e!3roU-{>P$P58ri-01YoY?`ytYUOeNHzb9myDg zT9xZiceWYTv5!zaJ#Wi@M0Mb<&3}Lz!R%+v+~!B!c|+`hEl?x001M+5>!*I1|8Iy? zq~I=g$3p)y``n94$6;;Ui}mm(Mq-(BJTq`IYRax*92Py#=R4)&Ks<*!ufaFQD6B<# zF}CFT&Zk5YG5fcsr)gM~bUN0@-Ka%*2bW`k3+7JW!&gb4#(g;OqUmtS@BCkQop{uu z{SCD^gD#mbv%RoC>HFyO66ti=tk$jAg7j0|f-SD_H45)xIzY>wEH_UIjFXATB*HJ^f;79W= zcz`dktulWyPdw+Q`99DLnGL7#E%TDOg_}tS-8L88XU%iReBSSegDKyK)3NkjAMbD? zYwz+n#G?0jx8p0Qo?k*Ou8{lYdC(NK+FPL(Q+L#2i?ZpF7({xSO=qC$Z$?eU9@OeT zZ_BUxh-lS6!hz`gVon%jjkiv~92CEfS#cq1ik4sx?D(sBM=Zy7r1zofXZy`eMIaU+ z-3JR|G?qi(I3nuVQtYZB#(ku7{9!Ki8LIqCRL_6JJoqbWQ9Z?081}&2z*HPS`Z9)K zlZR$;C!uceJNyzuANkh+zyCfqLpTsM)LztxB%;G){BlaP`SQgj6MiNmS`UK};e!eCxz?G=o5t7aI|77zCHXvOnyX*fA=>^Qg z^__V{isPGD7C*$wcpBT_W9))0a=8AE&Ot4@TbLLBz($xQr|VxEq1aXRQ4g-U7>avs z`XSaOT_u<6_%y_QiB!a)SRSXK7S%e`g&(3i)IPWCe;_4bFzJ;xeH_)1fIO~$s`4WP z>6Ap}mqAT!4QmMIBi%F)fB#Z}NGCEh$BDQI$Kug-^XQ9Q&Sh! za0gUJqfy%^*_Ka3U1$ZWqw7%H^aCu6nW&C`g{|>4s^i6d1zi6pnGn>FbV5Ba24E>1 zfkp6D)E&Nw>c9r;Hq?V_A8x{GL1rpXquP0h8sVG;&DyGoN_Rxvs4szt7Sm`{!>^!v zJPQlqN>oGJu__)yjo2-l-?xytvuIRC0AFXzx>i>XR?IlZ^De$01syb@hHb;$M zq|Kj*8i@ty(-5vDq9NRc8v2vi6fdIgq+}^`p_&*>dN}IWvH3U->y>exgXC{6YsyFR z)7aZt_>_!S$ZyB~cn1ipcDu?kkHVji8HQR&Gz z6*rlpv4{CAt!*UpdS`)t4h^XQ!)DvkpYD&)93Xf48C=_NcP~X}S)xdDndE-$HzhU!t zSdXLH{}J^-3utYg7iEzf_BmCEXf=kS=JG|<2ncNt~y?K9^#4@Bupr+(C z)JtYF>cZPlcl@a>KaCo(hgN-L){W#u)hlAHgz7*D`m~B$6RC!=sJGezjKg)P27)@6 zDJhE@`dZi$+oJCLRaA#opxWDly3@0$HQ{tL?RZezw>D}jdv#?0wcy+ zi?^{JmhHs0#BQiNnTuK@D=-&sw&@+HNAe*IL+3@);nt}7gYY5SdW6l7=;AX^z6o8- zXSsCL9p6Bm@EhuZ6wuXNxGL&N*$5M`GwM!uqo(dGR=_K$8_L?vSPa$C8mM{=@Dps| zBhr9KKzH+qZH&Ls!$f=qBYN^t3a|Du`}{_4)4|)Q*X(2b8H@FC{U5gj`tt0jek0Uc z=+w{blAfr=*$>r$NK}V>Nkp_5#-fIH25OEMqwaJo2IJ?b5qW@G{n`4PxvzvuH$^Sh zfvD{|7B%;?Q5}63)uAs?FQ>1O=Yh|;K}18CWq|pxSr(&7CtxC;K{eE7pxI85Se5iD z)c!w$>hLkFg*Q+`UwDvt;8evLq+4ToOvKta4@+wQ?<2C2Av=%y1T$rb`PltB>P}8# zf4qi6u*Fc<@lbyS?jXH?nCt(xJ38Dv^Y>#%@^cJ#{l5YAz)qxBqK5t!YK=X>99-YY z8ez6gUep}b#}}|U*2L+kN9Z=xHam)%vP-B(>Rr?b<%x9tU$JVUIxrnIrC+1Yzk(W> zKdt$^?0?;1c_Mm*HpF4r3BSe7cnV*OGOKz}w0V;G@Hz5#S${=!s8)=*!=|XIXpb#0 z71e?5*cXps99D^C|7*w>#G0XBhV4kNMJ<+_Hvd=aUs#@@&o;t!c2iz8&UIeHA5hyg zKHfZ-=A#zn*Qh(bj~eo<38te#*76DLe{F+$WN7G{poX|T>dDq0^~fECV{i=WPVb{e z%uO^yTnv?81$BNS)P-L_JrM_@+M9&x$P(0b-}VvFg}0zCv8J)7z} zvvJR8GejN7m_^qYb>VT?1*c&ZJdFYPCuZZkC#bcMb)5NRG#hV{K7h%%dA#fYouJ$V z*EvHv16|gilQ5B0N&`tRoA2%KvnI%P!g&6k!%uJ#<;x~fj`gOv&R2M7DvJ&0ziRIM z>*;2Qf50B(KSC|S7iXA9d>m>`tVFGeZ5W~pohPEX3!G_&tODksf#)Upt!9}gTnAJG z!%>SY4YmKLqqgxHo1clAq9Zo_FVqzMgj#DkUU!}GSO|TZ^SMM+unmjje$=8nhpq80 z>cSz+j~*!PP#x=yTFry84jmqW+9gZpnEhU8uG!YLu_5`5P}hmK`D5lX{%Uv<8M@#? ztcIJgI-W+&^%Ja$mFJml)*1EO7>s&%M4?7t5~{sLsF%(LoBq_6pF`ciEt~)6Jmy-f zHs5@6LOJxm%~1P!AZjS%P2$W(W zse@I0L^StpP!06Q+8B%4uNkNgzKhv#AL>pIp|;sMY>Agp9rUD|_G+U>A`CUMy-|xU z9{t-IHNw87M9L94WW9>oW?2`Sq3>xOhq}{Ms5?7|>c~;lzP^Hb1b@R;xy4#|ikiw> z8D{YnS!~V=L9MZ7$RhSReTZmiVo-N96?K7Grh>Bw^`2jkFW_d>i2aV8F!vJEU>^)4 zorD_N4^Sg{9JO}-#$H%?sq6oFejKjTMn6GBi)i#RbI0?oJFyA*m#{gOdegks2A~$@ zbktgS59{D(s5|?^mgiq?F5Cz;1w&9%l4jGdsa*U2Eh1VJhf#BV3bp92qUP!sRKt&P zG!|N6UaK>$U*PlP=YGrB1~o!2qt-+^hTuxnbxz|nyo~<+AGOl;|4qkC>`K7})X>&i z#<~Dm24^q^DvOUdAu6{aUkT3avAXs}5@0c1A7IcvMH{pyqx(YKo4dI`kCPp`35~ z%wj9{wi&AOs38hQ^)wXqgzSjA(?nDQGf>-S0oK4hsO@sGqH?y18Td3Y&Lh$4pT`FM0NB8>cYRH zo@{~dnz;@^bz~qu=0OyXvq(q3?>dL@SL}s5w`fY)e}P-gomNA7OaxwwtrfEaC>J=f`+FLx*`4jZ1 zV*ZcJ9C=WSsXpq2VW{ntf|{a5){Qus^j_?PEq9q4$Uv?B{njr~bAJZ4$Zy#E2dEJW z*vZ1ou$B2y?o8-aqO(@uUYHGv%Kni;=(o zIc~n!_r*k6JgJG~Z~ZeC;~d$$x+|xWIR(%*!i=JywJCPOOMO zoHdW?9Oqo;BkI>fP32AOul?WhyzBp$4ogwnD$h6iV89m*oQ^fWb)A=S8zy7@3+DN- z4z*abUo?v^2=%%xVXcBH4?#Wao1=DHZ`5vz!hG8QNaYPbid60??PlC5$(@+P>W(0*22@M zN3DB>A!8`3;C9mEzc(GN`-7?11ocvi!94gf>d86NdIFKEZIT`HSoSSN5~_H8B7n#e6|jCCIx zV=xElm8dna!Fm)^NdJObOi__A)Sdls(sFGTkr+y zf@e^x{32Gxd$zpzpXRe)MLbXbT^xo-{xXZV#^2`rP}KQhSPpxm)=V1K!^x=KvK_N) z|L-NDm&PF+hNmzY8$2)FQ7(rRe(9~2>SHCzf430`LYD~Kg~8mH56`5u#QFD@if#BuS0cgCu(R9<2Za| z^HZ}1_@{IVYMahNt)(ScANOSq@cBP*+$Te;x?DC>F%0#Z?S{JJKB%FLLfx4UYvK&l zNPLJI@>8e>(a$#RWH;v(Lp^%y;zDeNQ}AqdpSkdW9HxPZsBN~;rnjIja2Rz5*HEwF zU$HV4%o*VS%=a9s1L3G`HwN3_Oq)KA>ev<3$UVTqnA?}j%w0Lu_NjqgF$QCCC$_)} zxsAh7^;TOi;}g?Fsd0;{k<<#1|7D`YW>k%aZ6q&{3W64vnlPl(u7=ON8A$N$)UmvkLM z6UxSsr`7)_>3HHFp^ldb5yaDJ>wDad433kD`3X%4FZ%c+n2P#Osd-8HkGF{H=tbpO z#ChvF9^&`On}YSpiy|!d*D`yynlBYFun0RY~b`T$?oB-P3 z{`o>dL3e~3Ef;dJs(lQ*BwAI@wdn{A;gY#?5Z3a=4(F#3-b#C60G_`K-^Q>Te7 zt4e$salOwc+j`nTONh6_T9i$+IE$8VYS5xX=^XD)3>> z_;o@hPI`9Cv+>@XT+%kc*7yHQx$d^C2>D0J%SHM#)KQaof{jlxSx#l@`N-Fz*Rdjt zS%3b-CMxS?)SL$M0VB@OS*5Lh`hd}%M;=i$U96> zr@IjJ33nDjA7@IFKM9wsQQ|tDBi@-fUlE;1)JJc<^-5Du$2a-}_JD#u=_gwi@^vS+ zmY|~tRjUw&kPB_K>ba=t~71(+TT2QO679H6eUUdM@dI`Ez-u;V|+ilAmJF z(~GtcX%Fd&m`?f=!eqj?w7;9Yym}Pc#xeV;1F236lsqA_zOE+m>{H+eQ`58eanZpWr^W6@R1RPFq1Ijv-uEgrlRa z^E>Xdapfo2`cGAdFof_KdG+Y&~D~WAX~vbbkyaZ>VkP zHg(epI_ewzzq7Wbj*hd011jhGPAQxDA@R4#>_>Vm;U?*~NG~O%5!X?M{1-_NB7V|d z{3T2#J&pYL@CoXui^;Z*(wX{$ydm~_4Jj)UL54nL=O>|WY&r_3-)~#YSIwUKtF;)X z-J`UpZGH{$-o%TNKZE$kgc$06N8Uo>cd#MqXh*z|y=*LXl8N`XX_a3g?*r=aCCeEG zZ|Wu0k_tTubqF2E%tfJ&FA2d^-blWVH^`q!ya;*Ku^VO(I-6qupT((DfV>5^jYhmZ`Hn#?+CFq zv@p^(t5cd&^LuP;TZ$#V#-2S7d#chujaQj~SD=Qc*ZTsXVP zU#bec(43{5l+|8nDDl=*c;0p@@wCVRKucb_m2E<3({90Iy z^h)wSrq$&(e=K>G$y-2pLR`l@LT>78qs|grFT>c}`GiVS3H*-aOd`BX<#MQFnr%Sw zlEly8Dawx7{AuZ{Iu!DKMe1jAf2DLJ;Z@S3X#NNCW|RJiaF6%^@)lC|4sjjbNnarT z7V&ooXKkyOiN8twu}wF_aO&2l?tbEXDc4bnyfQqiLOKTd`VenP*?Q`{fG?XWP7C5m zgwceGlx-&PbB+J_jl6#zdu{qpGE=D2i!hqdfe=dBhlC8uj^K;foY02rZqLGpn?6+1 zF&H5pQL({eNbv5nJya;uncGqTXXl?-GBVyt<@kqz82>o%tg`JECGS4xR(Z{*kX}E6yH4cy@eEd;s+- z*mIu8VT8&yt$G^?RY@?Frd6{C_pCUs6U8E>gG%|HeZ9Xn-tdXZora3;F&< z$t_Zs@eJW*LSJge(&QFAPpD0(pn8M~_EIg$)6t&11>|)lUfAY&@Ue}Lr(DNW(q9o; z+5BbXy&vFTGJGK<@e&2AZRK4w*n^UYAw?0H`j-$)3fUIm?Kj}XeY5wcM>nRZ>`BZZv6v>j^OuS$Mv>ZTFirtAfMFo`4c6%uQybe?z#f=h)HxRl@}KAZ3Z z@n=U@>Ru)ECU388JjVL0P8H745l+ZK2(@YDO{8uZ;g0~j=0}scJ-vI^LJi-eS{luE zqWCJgS&7fLm)@y!?eUAvyM{HkE$MnQd)~05q`26`Xir2^q&MS4Be!&hr;?l9le>3{ zH`&uRAv`ud)H8m38mUnIG1RN9i4(US>oYxDw%oZm(nonKZ+m4>>9X6FkK0#t+t~Tu zEO{cmo~Y!c1W&7O9k!iYSgBZr;r24g-cf1Zl+<8Pw|H-Oir15xJk}E)9Uhw)yyn+U zEqp1S)EKYFJKCF=>WTEGL?p+KOpQ%SBsVq$u)u0C*0+gwU&xW7LU;ql(Y$Z(p>7@fr}>kD?CHT|Fdr^cqnbK?I+&l@l>|4%)y zy6yJQnSmY64Kpyqlg4O#B4WG|ao)&U{xOP8^(L6H*YJjq9O(^D_QWQ7!V|}OlA`=o zm}XB(On9<4B|Yb(n%lm5_+IYJRaxBUgE9*iadTx0Y*f2mV^6(?p$(p^S+{;>wUTZL z*L^-Stdv_ehZ~qNtb$u5UtsRAw1}9r#ORd&UWqjWbGK!VV&kB2Ky2Uc8S943{>ywn65)l)g=INA}G%_k< zN>z7$27et_RHX^of}7Tfk5%nL>01V7qjOt1Cr{HlDXGb6g68+<&lcO{0;~x072hm>kc4 z-&ieAT7pN-wehAhdMONF^0THhHgs}5zTOGX(wsal%@Y+HpXyCc^rX?L$h72$m=q?& zn^?;e7oM2-&(l*Qh?BL>M*9a$W0#o_=gul! z{n=flgeOKNvz3EAVX>*|LUN)vjgh0i|3-o{Z%=o(bn>yld01$mdBDUZdt-;Q>OAx{ z+0)6+AiYmbKDaj8>lw|%=id`j%YT}gkVrN~cwA~4Q%85By$RmQI=D6_KGi=~so^XyGiR-mQ)A;8G@g!eW?N_`wQAe3&Z5JIGgEAt Z;LHI(xIOY_UcBpWE1Y>bYrvdr{{x&`1zP|B delta 21162 zcmY-01$R3e1HD$<8gSNy62vI;@-Ofo0q0|HYbJmcBUkA9ge;Jj*}bj=W(2Wk~q$$ zYRYw-6)hd7hwC^iaX)Fdwd0h*gE)|Lp5t}W-9K`i`BV#iL76Yl3Ye_#k5@7mRI z&f(`h=_DPG33Hr3saK{S^+^}zSD78Q)@hOdoC9%ZI8Tj2W>8dR3t%kxbYF(_sv% z$74|C(=Y=rMa|_Fn?8n`nk%RVe?qnM64jC9442aBF#`r!%c0JzKbZN~owczAolt9G z0A|JUs3Bcs%a@@>W-DrF_oEs*fo1Uu>duqLm>bE3TGYi*`3LJZ?yg~)O; zir@{@(E73R)RA1M5vhRcP<_;eJ7WdxgXM7%2IF}wgzr%2<&QIWUKX{c>Y?U79P415 zmq<<`yHP#8h%8>`8S2hnpf2dfo5h(LwTOzNhPXUxM5?3eH%48!gU#=YS{t#L7iVBb z+=8L#JxoLm1Pw6_ltSdwY4VJ4h|S_^AY9Zf{-mMf@{dWjm+bVJPzZt4f%X7+b} z%tHRf5#~Yk0Nap$kGkR3BXu3-zdI4lO(bgQW}_Nhi9K*9=EN)?n{8MMH3Ah;_1j`L z?1h@D;ix$thwE@U7RE}Sm>cbZ-_pV9*uYDqBb_)&g=M47-1i-0?j!=Ul0Os=;55_& zsp(k9If~J!HBfGxIjI}isE+Ei8oP0_YgG_ z?`=Bcc(aWPp&G1;T2xI?^}^jaZOiH@aM6-5kOl0VF zC-G#|!3kIoPvTunJ;`yF;1g8OCr#!df`>5#Q%o_o#0I42q2~S;rp8}TH}C=r;#*9C zfm4|#EaoMmp^re_$y`i>TTva`kD8)0s6}`WTj6`u>TfyC%;{&S?KKb6;95+HJ25RD zM9uvfY>PMXI(kb@cbrv3Qp_-OyAgv)AHo9o1OqYSOw*xqn2dBiRDKgIi;?IXdTdI1 z7qT-Qcb470)^S*k{HZ4Gb-u9$7g0m?J-)`D@DSdb&Aj501oI@zJjXn8OJP3p`(Q>K zkEwAUX24a}9jK8wj+&Ztm>F+iGVTATL|T*a64PVITr*_tQRzO`IP_fzb%A-PDO+pP zM^Hn52{p%eP#63aHDWJN7k-0kH{CqaT;It{L=Bfk71UP&wnOdH{-_I%w$4J$=_>4j z+fZ|xVZPaJ`A`?Gjs37G=Efb^0WY9BRAd43uc0YLL_My8O4mi5&HMop%~al8%J{1%f0I!a-=pTV$}(QT z*a@#L7+tplzitWGP;ek8W@B5vUQEve7&NKSzzwQS{(tn|_Iz zNGIiL*D*V41b#W)6P z&cF<$SE1_fu<4ViMSLCe;GdWdGk<9eLf`wp3=uV03o~LH^k5&Ie`m_F=E<`l9Jy44y5-Z|ho4*d#&@NPm zj-xJo1$BpyP*2X}JI(G$kGkXXsPZ;g1_#;lm8dB>f!@MI9ud)@%NW#jqUd zPWu@Dl0>GFp}E_S8saNh6z`+%DBXUu_yRFA=^CgzZjD;Jy=*!fbCVu}S~JT~^p6Em$7!qdJn~pjj)ySekSd)V3Xf12G!2;B9P( zFR%$#J7m(IqRP*qZoqqwhjTPT8YoQT>6rNvAnxhP)`|CEWnk(LPuLW2`Gs z51@0X2iY~$qP%DGpQ3KyFVy1mKW-LvCJf;EPFW&qpb6^2ZBZADMh)!@TRs`pzdrG?X(j8?HtV?!!EI%jUnq z>ZCKCFuS7#b|u{tb)f^OJH3Qz=ML(Ee_=Aranjt72Q~MF(D(kYL_|YV2Q?C{P#x-o z+6@Cy4S#|HQ5QOZh4C)xj#GT&n`0*%_9HzNb^c4#Vov%k;~z~V`?uzT zlTh1YDQds(LQTmzoBtR$y3FAz^X0SkG>uZ8{*3v2UxHal-^L{P5)0yMY=QaCnzvsR zRwBLrEaM+YITo%=lmNvgXY7NZBx_AJK(;??PKW;(r1@mYffw@R8 z!*2K$w!`cf%?J;~rlf~>iIgUC6g5OIP(#z@k{PNf%t+dcX>b;5O)SH-xF5^oDNKp~ zq84My%ceXFYB2|4I;?~Fu$4`Fqlsvay%>!%us%9h%%igbCMVew)o_1Q{a927#@YN? zsF7J>(D{Qg zJ%nobXKaJNp+>0gRkJI4TH~#gF+b(Yv9BE9FPl3kRFI-a5475v)BvE zUN=)V7b8fYz>k!F!@PthqRzW-&Gx-{UNpkm zE0JyZ8}7yxKbqHQho8)pJjRCPr@qJcJhnx$oS(2WetnAfP>VaAP zW3d3~Yq${KJz)Gd5}Egl8RELXns>okY{a(e_s~4?wmmW@KE+Mc&-B<_;E*-V6LV*s zup8xvP$QD(sri-d8Vn~L@QhK!F{qB-edaZbsr+wd|JOjR?z)%-+n^R#Kbszm+K!*v z^a4yzdNb;IaR9YTzDJ$^GbY0~*ah9^rhYf;K(CE_g2|~c4U^zp+=h!#tGem$=AEz% zLr5P&)lc?^8TxdXfpiDVg#9rejzo2AF}7qx_uxU&DPEfEcux{hg)^w0Kg87d619l* zyYo6w4|N9qxmc#0QnbjPPD!+rLvD)8e&Xd0~BiI#Fklzc|hMsd|KrsPm`Ie}$Ucq$!Q*FdgXt48lUF^BUt^Y=>Xqqm=ypO9LXaQke@}L#^uj zm=>R4PJDwJ%B-nf-?Kdslaj85T1*X4^_yWQ?2P?zCl0{eXi7!`z;x-%h!n!~ zq$^-9Y~Ur5l}IS+4u_&TFwQz1_2gQJ8__?#nai!HhAyLq_#SF;CCgya1yOg}2(^}4 zquT9)>TqAojNXw%)X)qpjLT6&cGBjT&1mkdE~>#MsOLpnEQ-;n1{a}5YAb4lzClgV zcc`hkiCPm6Q8)SuS(IKUNhWh*5mZBUP;=8BH8TBC`+5|rfw`y=S&f4+U1n2nH0r#0 zsCw&AQ<#Xl(^IzmHmbenm`D3Rc@{JG1yPUCdZ?jlht;qLs=>vmk=lT&_m#~*jg?4$ zZ_6`fb$vg|1zEddJId!_1$>O!&Vkunr-=4{M@4W9@+x;WU|pOT;QBtPPNPov3pJ!A zvYV+WhZ?c!SP)yI??GepXQD=A4QeD4QFne8H3j$4Tb;;rBD$jzIn0G>VoB2RsNaUI z#t~RQm+KrO|4?pIJ}wXY*q`71;g95Z3Ur-$SS`q`jZ3JGy+h{O3F7&!bO;u}$o%Yo zoiK|GJxYrdFptodsPuRoj~h`PEM3rbYG57w1iiQd|H0=xk(L#5oyF|S8AV+uI4SRi zlCE=>j(04_onxU2uJaUYRCJx1SiCa(zdDftRm`?oTh(|9wYs08dK^&Abf^Z7A>9X` z;{$An*Jz|W=Br^=`zX|!nTpyCi&0as4z(B$qISh4FA?3zUDW>VPPer9K0!4w5zFFy zYSe@2AZkjyH*AG}P#wrt+gzZ6 zwK=MRFw}{oPz^7%`FpLGP#1WNda@<0W1bsr-T8uSNQ`r(30k6}Oh#s9$sER{S z7n+Q^@EX*k_8@8qkD*5925M-3wdp@mYa>ZrQ?D*+Bs!v|vOj9%W@ByKfN8Y<9}}rc z#w*l5E?3XYbp&ceW}|w(9o4`w)b_cFweT0zE-GB#w9^N5!R4q9e2co{8>lDjBh(aU zYQSrp>pOXf@lP$Tx%>K|f8A~mXBc57i&2P&c#aR}-; z6N!2<&P8tok#$5glvx^@RT+pH`chaM8=>xe5~@QhQ4Q`u-RTX~n(%LA+R2aFzNJx9 z*#T=~4C=x=Q0JX!#QrZ$ti+VK)u#8N9?d7QF8Vhy9S%X& z?}2aF)&p&R|7PaNHwN2Mz5sQ@Pnvnn39re}6DfIfbKzjrqp}(f#5SlqIgFaSn;3)- zP1DAdSKM@_MJDG}Z2ZY+ss zQA79+wfa+aFmqoNm9B$YtUXcNbrfpuXQMj$C8|T`Q7@-!sOP~G)Ci{NXg+rHV?XWx z7$Q*=e2;3VaVN8#!m%*vFHrmc9ID5cF&LkqhCWAUbAeziM!FFOVl0-xxu^>t!}W~V zZPbU%ME<^~zV`ntBD#~SsE@}-*d6P4a~%&Se2%+GAMft^e##x$!#wkkV-xbz^mKhc zPIthjq}QN^{&&PZ-lYH%KE&bOd0xDR!~uTj^zh^luT zH5JdjM6~^q4K&*&59$JCQLDH<>YdQnmQO~#OqQdz={AhTgQy0}Mwt<6gc{j_xE$kA z?PMKf9%xli<=(YK)U&OqRl6J2@DcRjdDMP?j=FHVXj4BQs^f)FkMJ7!3Zt++_8ZLF zUXyG*@Q0VjUCD2#PJ`SAK#CE!m6jd!zh=(k|lPH$XqIHV=c_a zkTI@v25*dIk>MBP&7J=;!3^;$`_wGH(9g`XeKcxK>_V-HZ%|LbXQ+|#pU9AN zUQS6mXc7-J^`saPomdYw_w7;py+3N-j<@*>P*bzPruU$x<`im?{fZ;;C2FptC!72^ zs3+$NR7dt=J-mQkT{z1Wv&svjdR7s&ifdvidfXJXJ4Q}5`}-y85t@z(t$+cj4m3yQ zcS5z>3w6PGEP_+9DDFZ{@ttYx|H4F)O*h-CB&va$sAqOV)ClxKH8=$Il9^=FU)b`! zsBL=I=HEgs*56R|of&4T@}RbHb<{{Uo57sxPCJvKec2DS7`+&XlTjyZvibW_`}!p6 zf)`O!br&@P?@$*^G1JU_LDczGu>>|jZPQ_>4o>$HNlIin>Q2|7w&Px`jfYVkbZ40c z)1gKpKWbDB)Xc|$j_ZRBCEc47F%ZpmXl~5zo7Yq?O&#=On7qv};QM;f5YL(Z= z5NwB9Ba5xaQSXSSwmk1j^8pjKlKtP8f+J*{#v-fimkw%iW%%6e+mfh7+8ouUN{@@*E ziq4?UPqWkf!m>PeCA|!_R^DOsH$gJG!Ezrwl^)$nfA zD*wjjUq_A5J=9_g*lQMLAnN=E)>arry31bnzvk!^85)v{sGi+H_0;{!EXFLT#h2S! z9Cd-JSP1K*7I6e>h~vnLrB*3dv9y7O_fR{Xy<&;C4kj{HHW zj@LZlI^%Eyc0_NpqBlUe2KQH#<4tobp%GHxUtkLp0+IoCHe)9`z}|F@WkGwHnfNv6*Q*Lgt2>&Sk`Yp2tnxX3V zMLk&)upJ}12X~TAdz<~Qo*pHlif2(Tp*NTsGu$zc%G}mo*q8iu*7SEx`4AjT{(g+a zl0UMYxzJ+tt%;w^jrrd*Ba;TxP%q#f`(GU>K!)~zDb#zv2I`Bb3r@#NxCuk=yUrjQ zPWQ9U*#YB#-lXcq6jM_$+WPb`iSo690JK-s)JH3Uu@geGa zAldI`R|R>AG$o?}w!vAbZE_zq1+D%tkJ_$Smvj^+!R@GeyRj+;y)Zx1b;C-eS6XkN z7Ins#W)0-9*2Gxyy}gO(j<4B*YJZwvqxVELv<&sRd=)iSnf@~7K`qiEsMQ~A^Q)mQ z7=l{mEwC_#+VV+wn)DpJq5a?UZ!>gNUzydr7}dZ=R0BIOAD%!BGKfa<_5)c!t#WAHTU zOQ-oiW=J!=H|JHw66Ci=4Ye1G;aXHXm#nv~k5D7}7y5qw&-SnBSy9x`R>l!Hz~=vq znv$2OZTb%NKuN_fXv$(KR0n!t5Y9x^+ktwk9zoslNz_PQL*3YO$It8g9DYNF_I)AO z&o>hFQ4gXnHa!@1;zZP=cO}ljFL4|;^fMPejT*^ksBM&1tUc>F;>QR)(WZo9GLwdl&{3}7(=}-gg%t>6!toCWX4hWC1Dux-%vxioC=*te>e`4 zeoZ1dh7d~8$ls(RiO(avvK8|XZ%)url(3dImJxE*^98$SIzwKfc!5AI|=Q{Dntk%@D=8CBTtKqPdcYAL0gHBDCa%-IzFbY z?`_=VFyusLQ)eha&xmO1=-~eOl`EMajxzSdWaMduXQpC=tvr~rhU8TseTnjBgrtPY zq&JdZp7N!HErgDwuVQJuPWYF2Zrjc_(z}UQ_2>HaXh6s3I0k?4rFa8!!c)SBqb?^* zq)sx-L;jbxF_ljs{{ne4a0;&fPuUvcg~|Vvz+=XDEK!^zLic}xL@_GqABpM6PkbS9 zz28UMirPZ+iHBe@$|l&lBz^yL{$tAKbKX2R8E%eX$z#fA;0@@nIWNau(+V6H42250bZ-_)moVob%zB zZsV;vH!H!Lk3UjVsS=@;EzCgPY0@c4A4eUjv-SMP)x zl)ogNfsljpU4(}JSI_G_w2c-e^A0C$C#^4&SEvWm7F#(x4fQ78)7Bqm?M8km;ShCo zJR;tm5Jk`tj?p%*^m5M2Pbf~_9_{~TwxNzRKElRTv9Z1I2AlUe7PSriNcjNDm)Z11 z(wm6y!1}1SqmJI3lbg`fww1(cN_ie=|LgElFp3lT>~mU^SB1QrIGJ=k;>js5hc!tD zkgbCHNbBf|yeOSCBx`4i$gDiLo=oF5IHUN{i-_6x8Vy-xZC`Rx+ix|zK#iLD~&XiZ5$LU+>s z_~B^9nR@T;B;+PPfN;W=Z=h`Rf9i&D?sug36Q)o$lkk?jR-AhU$J@Go9rekpM7TzJ2I*^rU4)8+uH=s-e~>*-@7au`bCC|j1ky(d zV+l8Ce=m7yw6cCC(uU0c9$!$Q2tmg~!mqv<6GUTYZ2l3>`-c3gq%))5%l|zlQC^ks zVe#~)a3^)^k=N0-Q9y-!v->{e4iVS!lCaxWPY=+mlK;33mxo$;eLFOregolbm_^wt!g=xr znPO+J>XA1XMp5T;;=kaBV-}IWsgsegig;057Nte~$kv*QzYzFQ$eBn3I;Ih?OXXwu zCmz9bh2@{4`sPXcOzcFo=?>GgWx92LS7Nd_1#t+8&f}4^FNowe~;uO z(o$HG{Aq+q#9Nb>36I&j6KJdwdFgDr1EwUehi&LFb!QQDlr{K%zgow3>?(N&RnGOD zY&J6+@zrFuBOOn8OnNEl1%!CwIbxiPB)vf29M!4Nl2Dw`m`pyheaC73EI~#6 zqedNb$p4ghR`LpBOPot+Zi;<>W}{99@@CpLDiE(i-FtY@<~6nL{lghKTs|_#laZbZ zx5%hSrRT(T@b&)x9fNFoCguEq?#xdZ+%U8EB(W8=5NVs$Db=a@6IQe>g%e+C&z_EL zRp~#+YVy9M?pE3ug!)NU$9X~y${N~pD_|?Q9R@%H4+rfeN?9nDF9PkcG?4TMXS>9|W+MEozCu7=&HTZXy^ zh#ycT4i9;GcscfNlF{3ScumUIP$vXOnJP{V;sXhBgdoZ`5Z)4WJSXqJ$3B~WOXgte zv?at58WAc}wu2DPbxvY4>eM9ECcWLCZ<~*(q+>WXp~7eisuQncvVDKZT{8wml)c znD1}or;;&%)C~&f;%m(Op9aWsb|+kHmf3rmk|(5Y;YGs7g!a@7qlGPajSx)mkpC+o zkG)ha@^myHZ#sD`iD$8S`S6vE52swmSkk8mwQc@l@;3YVmJAD>L_7s6Y~@56Y(Y@+ zQ$h&wu>>6}Z39avte>#5d4RXS%{ffz92;Lqya#7oK^=FgU7L`E_+v~)7){7V{l@sl zp7$;BwS>CV3(|@9C`VilFXBOXBbhoEBthEjPF;f~EyehcdUL}*LiKHGR-tIBl**-nKLKTD`+ z(<&QD-8zIn{Op<^LgtqVV_Igeu#sx9G~0yY`{eo&pJ6Y(N9Wq(na%qV3+?!}<>O@Y zZx(c$?MTvLLQ>bWV^Y_Uyl{TR!EAXv?fQqudisWi#>K~kd5DG$iw=tk9~c%D7aF-^ z>a4#0JN)P74cO6a)893B{PARa+8xi|Tuqhm?UVe8N0YiWGFFO>nP z@qImg!oxh(W8-MQU(NP|Vq)n-e2KRF85!3%^4RL${ln&uEb7imxZEXU!t>Ci^Ya&T zBNNVbDKh`7Vs5%rp6aFSx$`d3CSo{8i1| zlHOzcdvQx#G&amrNB3BwB^mZgp1Se9`^Pf`QJ&DK$S^GFsT&>_7v|{|7TUXiTv)KD zPiSncJ@Nl4M}<@984?;9PQx*AX;Y<486VZhi>Ei?CBNGZStr3t5FTHb5`O*qmkjU6tOZqZTk<3iR(Rx>S5vBqdMF?tUu!tIwIav zuuOs2y1us5O5OO}zA=e4XNM2`U%S3@6T7!?%jF96)Ypi{dP4rU2IKy-2*V;H6K96I ziT;V52D+1TCk9M**ECH`ece5nJ~7v?ZtFDjOTTcF6+5;&DoR7ot$Nyp4UCQqrMvAy z`^9>Om_ZBsFph~4FWsG4TDCRIc4$0f%V-QV6T@A`Fb$gYC^H9|wg2mOzp!JgwIJfO TnBz4XzGhg?c~kn$Nc#T(WaV@8 diff --git a/languages/commonsbooking-de_DE.po b/languages/commonsbooking-de_DE.po index cfad8aae1..f8afc4064 100644 --- a/languages/commonsbooking-de_DE.po +++ b/languages/commonsbooking-de_DE.po @@ -2,16 +2,16 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/commonsbooking\n" +"POT-Creation-Date: 2023-09-15T04:04:14+02:00\n" +"PO-Revision-Date: 2026-06-17 15:48+0200\n" "Last-Translator: Christian Wenzel \n" "Language-Team: English \n" +"Language: de_DE\n" "MIME-Version: 1.0\n" "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: 2026-02-19 18:07+0100\n" -"Language: de_DE\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 3.8\n" +"X-Generator: Poedit 3.9\n" #. Plugin Name of the plugin #: commonsbooking.php @@ -41,8 +41,7 @@ msgstr "Alle Zeitrahmen-Typen" msgid "Welcome" msgstr "Willkommen" -#: includes/OptionsArray.php:44 -#: templates/dashboard-index.php:8 +#: includes/OptionsArray.php:44 templates/dashboard-index.php:8 msgid "Welcome to CommonsBooking" msgstr "Willkommen bei CommonsBooking" @@ -83,8 +82,7 @@ msgstr "Buchungsseite" msgid "The page where you included the [cb_bookings] shortcode. This is used in the Users Widget" msgstr "Die Seite, auf der Du den [cb_bookings]-Kurzcode eingefügt hast. Dies wird im Benutzer*in Widget verwendet" -#: includes/OptionsArray.php:151 -#: includes/OptionsArray.php:165 +#: includes/OptionsArray.php:151 includes/OptionsArray.php:165 msgid "Booking comment" msgstr "Buchungskommentar" @@ -130,23 +128,19 @@ msgstr "Vorlagen" msgid "Email templates" msgstr "E-Mail Vorlagen" -#: includes/OptionsArray.php:284 -#: includes/OptionsArray.php:660 +#: includes/OptionsArray.php:284 includes/OptionsArray.php:660 msgid "Mail-Header from E-Mail" msgstr "Absender E-Mail Mail-Adresse" -#: includes/OptionsArray.php:285 -#: includes/OptionsArray.php:661 +#: includes/OptionsArray.php:285 includes/OptionsArray.php:661 msgid "E-Mail that will be shown as sender in generated emails" msgstr "E-Mail, die als Absender in automatisch versendeten E-Mails angezeigt wird" -#: includes/OptionsArray.php:291 -#: includes/OptionsArray.php:667 +#: includes/OptionsArray.php:291 includes/OptionsArray.php:667 msgid "Mail-Header from Name" msgstr "Absender E-Mail Name" -#: includes/OptionsArray.php:292 -#: includes/OptionsArray.php:668 +#: includes/OptionsArray.php:292 includes/OptionsArray.php:668 msgid "Name that will be shown as sender in generated emails" msgstr "Name, der als Absender in automatisch versendeten E-Mails angezeigt wird" @@ -656,29 +650,22 @@ msgstr "Erinnerung" msgid "Booking reminder" msgstr "Buchungserinnerung" -#: includes/OptionsArray.php:912 -#: includes/OptionsArray.php:1023 -#: includes/OptionsArray.php:1071 -#: includes/OptionsArray.php:1158 +#: includes/OptionsArray.php:912 includes/OptionsArray.php:1023 +#: includes/OptionsArray.php:1071 includes/OptionsArray.php:1158 msgid "Activate" msgstr "Aktivieren" -#: includes/OptionsArray.php:918 -#: includes/OptionsArray.php:1029 -#: includes/OptionsArray.php:1078 -#: includes/OptionsArray.php:1165 +#: includes/OptionsArray.php:918 includes/OptionsArray.php:1029 +#: includes/OptionsArray.php:1078 includes/OptionsArray.php:1165 msgid "E-mail subject" msgstr "E-Mail Betreff" -#: includes/OptionsArray.php:921 -#: includes/OptionsArray.php:1081 +#: includes/OptionsArray.php:921 includes/OptionsArray.php:1081 msgid "Upcoming booking of {{item:post_title}} {{booking:formattedBookingDate}}" msgstr "Bevorstehende Buchung von {{item:post_title}} {{booking:formattedBookingDate}}" -#: includes/OptionsArray.php:924 -#: includes/OptionsArray.php:1035 -#: includes/OptionsArray.php:1084 -#: includes/OptionsArray.php:1171 +#: includes/OptionsArray.php:924 includes/OptionsArray.php:1035 +#: includes/OptionsArray.php:1084 includes/OptionsArray.php:1171 msgid "email body" msgstr "E-Mail-Text" @@ -713,14 +700,12 @@ msgstr "Sende eine Erinnerung x Tage vor Buchungsbeginn" 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:965 -#: includes/OptionsArray.php:1101 +#: includes/OptionsArray.php:965 includes/OptionsArray.php:1101 #: includes/OptionsArray.php:1189 msgid "Time" msgstr "Uhrzeit" -#: includes/OptionsArray.php:968 -#: includes/OptionsArray.php:1104 +#: includes/OptionsArray.php:968 includes/OptionsArray.php:1104 #: includes/OptionsArray.php:1192 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." @@ -762,8 +747,7 @@ msgstr "Migration" msgid "Migrate from Commons Booking Version 0.X" msgstr "Migriere von Commons Booking Version 0.X" -#: includes/OptionsArray.php:1265 -#: src/View/Migration.php:77 +#: includes/OptionsArray.php:1265 src/View/Migration.php:77 msgid "Start Migration" msgstr "Migration starten" @@ -791,14 +775,12 @@ msgstr "Buchungen auf neue Version migrieren" 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:1300 -#: src/View/MassOperations.php:109 +#: includes/OptionsArray.php:1300 src/View/MassOperations.php:109 #: src/View/Migration.php:112 msgid "Migrate bookings" msgstr "Buchungen migrieren" -#: includes/OptionsArray.php:1313 -#: includes/OptionsArray.php:1373 +#: includes/OptionsArray.php:1313 includes/OptionsArray.php:1373 msgid "Export" msgstr "Export" @@ -806,8 +788,7 @@ msgstr "Export" msgid "Download timeframes export" msgstr "Zeitrahmen-Export herunterladen" -#: includes/OptionsArray.php:1321 -#: src/Wordpress/CustomPostType/Map.php:557 +#: includes/OptionsArray.php:1321 src/Wordpress/CustomPostType/Map.php:557 #: src/Wordpress/CustomPostType/Restriction.php:47 #: src/Wordpress/CustomPostType/Restriction.php:415 #: src/Wordpress/CustomPostType/Timeframe.php:98 @@ -824,8 +805,7 @@ msgid "Location-Fields" msgstr "Standort-Felder" #. translators: %s formatted meta field as an var_dump-like assoc array string -#: includes/OptionsArray.php:1331 -#: includes/OptionsArray.php:1341 +#: includes/OptionsArray.php:1331 includes/OptionsArray.php:1341 #, php-format 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" @@ -862,8 +842,7 @@ msgstr "Als Cronjob anlegen" msgid "Export interval" msgstr "Exportintervall" -#: includes/OptionsArray.php:1394 -#: includes/OptionsArray.php:1395 +#: includes/OptionsArray.php:1394 includes/OptionsArray.php:1395 msgid "minutes" msgstr "Minuten" @@ -887,8 +866,7 @@ msgstr "Dateipfad" 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:1423 -#: includes/OptionsArray.php:1469 +#: includes/OptionsArray.php:1423 includes/OptionsArray.php:1469 msgid "API" msgstr "Schnittstelle" @@ -1030,8 +1008,7 @@ msgstr "Telefonnummer" msgid "Please enter your phone number" msgstr "Bitte gib Deine Telefonnummer ein" -#: src/CB/CB1UserFields.php:90 -#: src/CB/CB1UserFields.php:279 +#: src/CB/CB1UserFields.php:90 src/CB/CB1UserFields.php:279 #: src/Wordpress/CustomPostType/Location.php:237 #: templates/booking-single.php:77 msgid "Address" @@ -1078,8 +1055,7 @@ msgstr "Nutzungsbedingungen akzeptiert" msgid "map is not published" msgstr "Karte ist nicht veröffentlicht" -#: src/Map/BaseShortcode.php:26 -#: src/Map/BaseShortcode.php:32 +#: src/Map/BaseShortcode.php:26 src/Map/BaseShortcode.php:32 msgid "no valid map id provided" msgstr "keine gültige Karten-ID angegeben" @@ -1111,23 +1087,19 @@ msgstr "Tag(e)" msgid "Sorry, no locations found." msgstr "Leider wurden keine Standorte gefunden." -#: src/Map/MapShortcode.php:58 -#: src/Wordpress/CustomPostType/Map.php:533 +#: src/Map/MapShortcode.php:58 src/Wordpress/CustomPostType/Map.php:533 msgid "filter" msgstr "Filter" -#: src/Map/MapShortcode.php:59 -#: src/Wordpress/CustomPostType/Map.php:515 +#: src/Map/MapShortcode.php:59 src/Wordpress/CustomPostType/Map.php:515 msgid "availability" msgstr "Verfügbarkeit" -#: src/Map/MapShortcode.php:60 -#: src/Wordpress/CustomPostType/Map.php:524 +#: src/Map/MapShortcode.php:60 src/Wordpress/CustomPostType/Map.php:524 msgid "categories" msgstr "Kategorien" -#: src/Map/MapShortcode.php:61 -#: src/Wordpress/CustomPostType/Map.php:476 +#: src/Map/MapShortcode.php:61 src/Wordpress/CustomPostType/Map.php:476 msgid "distance" msgstr "Entfernung" @@ -1179,8 +1151,7 @@ msgstr "Link zu deiner Buchung" msgid "Please contact the contact persons at the location directly if you have any questions regarding collection or return:" msgstr "Bitte kontaktiere die Kontaktpersonen vor Ort direkt, wenn du Fragen zur Abholung oder Rückgabe hast:" -#: src/Model/Restriction.php:244 -#: src/Model/Restriction.php:268 +#: src/Model/Restriction.php:244 src/Model/Restriction.php:268 msgid "Not set" msgstr "Nicht gesetzt" @@ -1189,8 +1160,7 @@ msgid "Available here" msgstr "Hier verfügbar" #. translators: %s = date in WordPress defined format -#: src/Model/Booking.php:437 -#: src/Model/Timeframe.php:336 +#: src/Model/Booking.php:437 src/Model/Timeframe.php:336 #, php-format msgid "on %s" msgstr "am %s" @@ -1207,8 +1177,7 @@ msgstr "dauerhaft" #. translators: %1 = startdate, %2 = enddate in WordPress defined format #. translators: %1$s = startdate, second %2$s = enddate in WordPress defined format -#: src/Model/Booking.php:440 -#: src/Model/Timeframe.php:351 +#: src/Model/Booking.php:440 src/Model/Timeframe.php:351 #, php-format msgid "from %1$s until %2$s" msgstr "von %1$s bis %2$s" @@ -1233,13 +1202,11 @@ msgstr "Enddatum liegt vor dem Startdatum. Bitte setze ein gültiges Enddatum." msgid "Item is already bookable at another location within the same date range. See other timeframe ID: %1$s: %2$s" msgstr "Artikel ist bereits an einem anderen Ort innerhalb desselben Datumsbereichs buchbar. Siehe andere Zeitrahmen ID: %1$s: %2$s" -#: src/Plugin.php:384 -#: src/Plugin.php:385 +#: src/Plugin.php:384 src/Plugin.php:385 msgid "Item Categories" msgstr "Artikel-Kategorien" -#: src/Plugin.php:394 -#: src/Plugin.php:395 +#: src/Plugin.php:394 src/Plugin.php:395 msgid "Location Categories" msgstr "Standort-Kategorien" @@ -1274,15 +1241,13 @@ msgstr "Aktueller Verbindungsstatus:" msgid "Directory %s could not be written to." msgstr "Der Ordner %s ist nicht beschreibbar." -#: src/View/Admin/Filter.php:58 -#: src/Wordpress/CustomPostType/Booking.php:792 +#: src/View/Admin/Filter.php:58 src/Wordpress/CustomPostType/Booking.php:792 #: src/Wordpress/CustomPostType/Restriction.php:451 #: src/Wordpress/CustomPostType/Timeframe.php:678 msgid "Start date" msgstr "Startdatum" -#: src/View/Admin/Filter.php:62 -#: src/Wordpress/CustomPostType/Booking.php:809 +#: src/View/Admin/Filter.php:62 src/Wordpress/CustomPostType/Booking.php:809 #: src/Wordpress/CustomPostType/Restriction.php:461 #: src/Wordpress/CustomPostType/Timeframe.php:702 msgid "End date" @@ -1300,21 +1265,18 @@ msgstr "Benutze diesen Link um die Buchungsdaten automatisch in deinem Kalender msgid "iCalendar Link:" msgstr "iCalendar Link:" -#: src/View/Booking.php:171 -#: src/View/Booking.php:173 +#: src/View/Booking.php:171 src/View/Booking.php:173 msgid "Not available" msgstr "Nicht verfügbar" -#: src/View/Booking.php:196 -#: src/View/MassOperations.php:38 +#: src/View/Booking.php:196 src/View/MassOperations.php:38 #: src/Wordpress/CustomPostType/Booking.php:459 #: src/Wordpress/CustomPostType/Timeframe.php:97 #: templates/shortcode-bookings.php:74 msgid "User" msgstr "Nutzende*r" -#: src/View/Booking.php:200 -#: src/View/MassOperations.php:42 +#: src/View/Booking.php:200 src/View/MassOperations.php:42 #: src/Wordpress/CustomPostType/Booking.php:986 #: src/Wordpress/CustomPostType/Restriction.php:477 msgid "Status" @@ -1332,8 +1294,7 @@ msgstr "Die Datei wird als .txt Datei durch Tabstopp getrennt exportiert, sodass msgid "Booking codes list" msgstr "Liste der Buchungscodes" -#: src/View/Calendar.php:237 -#: src/Wordpress/CustomPostType/Booking.php:460 +#: src/View/Calendar.php:237 src/Wordpress/CustomPostType/Booking.php:460 #: src/Wordpress/CustomPostType/Booking.php:774 #: src/Wordpress/CustomPostType/Booking.php:1002 #: src/Wordpress/CustomPostType/Item.php:117 @@ -1348,8 +1309,7 @@ msgstr "Artikel" msgid "No items found." msgstr "Keine Artikel gefunden." -#: src/View/Calendar.php:238 -#: src/Wordpress/CustomPostType/Booking.php:461 +#: src/View/Calendar.php:238 src/Wordpress/CustomPostType/Booking.php:461 #: src/Wordpress/CustomPostType/Booking.php:780 #: src/Wordpress/CustomPostType/Booking.php:998 #: src/Wordpress/CustomPostType/Location.php:139 @@ -1361,8 +1321,7 @@ msgstr "Keine Artikel gefunden." msgid "Location" msgstr "Standort" -#: src/View/Dashboard.php:48 -#: src/View/Dashboard.php:94 +#: src/View/Dashboard.php:48 src/View/Dashboard.php:94 msgid "at" msgstr "bei" @@ -1434,8 +1393,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:99 -#: src/View/Migration.php:57 +#: src/View/MassOperations.php:99 src/View/Migration.php:57 #: src/View/Migration.php:103 msgid "Migration finished" msgstr "Migration beendet" @@ -1448,13 +1406,11 @@ 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:94 -#: src/View/Migration.php:98 +#: src/View/MassOperations.php:94 src/View/Migration.php:98 msgid "migration in process .. please wait ..." msgstr "Migration wird durchgeführt … bitte warten ..." -#: src/View/MassOperations.php:104 -#: src/View/Migration.php:108 +#: src/View/MassOperations.php:104 src/View/Migration.php:108 msgid "Migration failed" msgstr "Migration fehlgeschlagen" @@ -1474,12 +1430,9 @@ msgstr "CSV Herunterladen" msgid "Download Export" msgstr "Download Export" -#: src/Model/Booking.php:1028 -#: src/Service/TimeframeExport.php:591 -#: src/Service/TimeframeExport.php:601 -#: src/Service/TimeframeExport.php:607 -#: src/Service/TimeframeExport.php:619 -#: src/Service/TimeframeExport.php:632 +#: src/Model/Booking.php:1028 src/Service/TimeframeExport.php:591 +#: src/Service/TimeframeExport.php:601 src/Service/TimeframeExport.php:607 +#: src/Service/TimeframeExport.php:619 src/Service/TimeframeExport.php:632 msgid "Unknown" msgstr "Unbekannt" @@ -1672,8 +1625,7 @@ msgstr "Lege das Startdatum fest. Setze die Uhrzeit auf 00:00, wenn du den ganze msgid "Set the end date. You must set time to 23:59 if you want to book the full day" msgstr "Lege das Enddatum fest. Setze die Zeit auf 23:59 Uhr, wenn du den ganzen Tag buchen willst" -#: src/Wordpress/CustomPostType/Booking.php:826 -#: templates/booking-single.php:59 +#: src/Wordpress/CustomPostType/Booking.php:826 templates/booking-single.php:59 msgid "Booking Code" msgstr "Buchungscode" @@ -1694,8 +1646,7 @@ msgid "Filter By Category " msgstr "Nach Kategorie filtern " #: src/Wordpress/CustomPostType/Item.php:116 -#: src/Wordpress/CustomPostType/Item.php:137 -#: templates/dashboard-index.php:33 +#: src/Wordpress/CustomPostType/Item.php:137 templates/dashboard-index.php:33 msgid "Items" msgstr "Artikel" @@ -1924,8 +1875,7 @@ msgid "Location email" msgstr "Standort E-Mail" #: src/Wordpress/CustomPostType/Location.php:395 -#: templates/booking-single.php:86 -#: templates/location-single-meta.php:53 +#: templates/booking-single.php:86 templates/location-single-meta.php:53 msgid "Pickup instructions" msgstr "Abhol-Hinweise" @@ -1961,8 +1911,7 @@ msgstr "Überbuchen von geblockten Tagen erlauben" msgid "Location Meta-Data" msgstr "Standort-Metadaten" -#: src/Wordpress/CustomPostType/Map.php:616 -#: templates/dashboard-index.php:55 +#: src/Wordpress/CustomPostType/Map.php:616 templates/dashboard-index.php:55 msgid "Maps" msgstr "Karten" @@ -2506,13 +2455,11 @@ msgstr "Du darfst nicht auf diese Buchung zugreifen." msgid "Login to your account" msgstr "Login zu deinem Nutzerkonto" -#: templates/booking-single.php:45 -#: templates/timeframe-calendar.php:51 +#: templates/booking-single.php:45 templates/timeframe-calendar.php:51 msgid "Pickup" msgstr "Abholung" -#: templates/booking-single.php:49 -#: templates/timeframe-calendar.php:62 +#: templates/booking-single.php:49 templates/timeframe-calendar.php:62 msgid "Return" msgstr "Rückgabe" @@ -2520,8 +2467,7 @@ msgstr "Rückgabe" msgid "Location: " msgstr "Standort: " -#: templates/booking-single.php:95 -#: templates/booking-single.php:103 +#: templates/booking-single.php:95 templates/booking-single.php:103 msgid "Contact" msgstr "Kontakt" @@ -2610,8 +2556,7 @@ msgid "No returns today" msgstr "Keine Rückgaben heute" #. translators: %1$s: wp_login_url, 1$s: wp_registration_url -#: templates/item-single.php:44 -#: templates/location-single.php:49 +#: templates/item-single.php:44 templates/location-single.php:49 #, php-format msgid "To be able to book, you must first login or register." msgstr "Um buchen zu können, musst du dich zuerst anmelden oder registrieren." @@ -2945,13 +2890,11 @@ msgstr "Vorfiltern nach Standort-Kategorien" msgid "No bookings available." msgstr "Keine Buchungen vorhanden." -#: templates/shortcode-bookings.php:35 -#: templates/shortcode-bookings.php:71 +#: templates/shortcode-bookings.php:35 templates/shortcode-bookings.php:71 msgid "Startdate" msgstr "Startdatum" -#: templates/shortcode-bookings.php:42 -#: templates/shortcode-bookings.php:72 +#: templates/shortcode-bookings.php:42 templates/shortcode-bookings.php:72 msgid "Enddate" msgstr "Enddatum" @@ -3029,8 +2972,7 @@ 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:720 -#: src/Plugin.php:735 +#: src/Plugin.php:720 src/Plugin.php:735 #: src/Wordpress/CustomPostType/Booking.php:949 msgid "CommonsBooking Bookings" msgstr "CommonsBooking Buchungen" @@ -3127,8 +3069,7 @@ msgstr "Mehrere buchbare Zeiträume überschneiden sich in den definierten Woche msgid "Overlapping bookable timeframes are not allowed to have the same dates." msgstr "Mehrere buchbare Zeiträume überschneiden sich in dem definierten Datumsbereich." -#: src/Model/Timeframe.php:915 -#: src/Model/Timeframe.php:922 +#: src/Model/Timeframe.php:915 src/Model/Timeframe.php:922 msgid "The other timeframe is overlapping with your weekly configuration." msgstr "Der andere Zeitrahmen überschneidet sich mit einer wöchentlichen Konfiguration." @@ -3172,8 +3113,7 @@ msgstr "Wählen Sie das Jahr und das Bundesland, für das Sie Feiertage importie msgid "Daily repeated time periods are not allowed to overlap." msgstr "Täglich wiederholende Zeiträume dürfen sich nicht überschneiden." -#: includes/OptionsArray.php:188 -#: includes/OptionsArray.php:192 +#: includes/OptionsArray.php:188 includes/OptionsArray.php:192 #: includes/OptionsArray.php:208 msgid "Booking codes" msgstr "Buchungscodes" @@ -3222,8 +3162,7 @@ msgstr "iCalendar-Datei an eine E-Mail mit Buchungscodes anhängen" msgid "Will attach an iCalendar compatible file with booking codes per day to import in their respective calendar application." msgstr "Fügt eine iCalendar-kompatible Datei mit Buchungscodes für die einzelnen Tage bei, um sie in die jeweilige Kalenderanwendung zu importieren." -#: src/Messages/BookingCodesMessage.php:56 -#: src/View/BookingCodes.php:181 +#: src/Messages/BookingCodesMessage.php:56 src/View/BookingCodes.php:181 #: src/View/BookingCodes.php:290 msgid "Unable to send Emails. No location email(s) configured, check location" msgstr "Emails können nicht gesendet werden. Keine Standort-E-Mail(s) konfiguriert, bitte Standort prüfen" @@ -3242,15 +3181,12 @@ msgstr "Buchungscodes für Artikel \"%1$s\": %2$s" msgid "Error sending booking codes by E-mail for Timeframe " msgstr "Fehler beim Senden von Buchungscodes per E-Mail für Zeitrahmen " -#: src/View/BookingCodes.php:178 -#: src/View/BookingCodes.php:287 +#: src/View/BookingCodes.php:178 src/View/BookingCodes.php:287 msgid "No location configured for this timeframe" msgstr "Kein Standort für diesen Zeitraum konfiguriert" -#: src/View/BookingCodes.php:185 -#: src/View/BookingCodes.php:294 -#: src/View/BookingCodes.php:397 -#: src/View/BookingCodes.php:424 +#: src/View/BookingCodes.php:185 src/View/BookingCodes.php:294 +#: src/View/BookingCodes.php:397 src/View/BookingCodes.php:424 msgid "This timeframe has no booking codes. To generate booking codes you need to save the timeframe." msgstr "Dieser Zeitrahmen hat keine Buchungscodes. Um Buchungscodes zu generieren, muss der Zeitrahmen gespeichert werden." @@ -3326,8 +3262,7 @@ msgstr "Ein unbekannter Fehler ist aufgetreten" msgid "Email booking codes" msgstr "Buchungscodes per E-Mail versenden" -#: src/View/BookingCodes.php:281 -#: src/Wordpress/CustomPostType/Timeframe.php:756 +#: src/View/BookingCodes.php:281 src/Wordpress/CustomPostType/Timeframe.php:756 msgid "Send booking codes automated by email" msgstr "Buchungscodes automatisch per E-Mail versenden" @@ -3355,8 +3290,7 @@ msgstr "Nächste E-Mail geplant am: " msgid "(not planned)" msgstr "(nichts geplant)" -#: includes/OptionsArray.php:1597 -#: src/Service/Cache.php:478 +#: includes/OptionsArray.php:1597 src/Service/Cache.php:478 msgid "Clear Cache" msgstr "Cache leeren" @@ -3486,16 +3420,13 @@ msgstr "Kettenbuchungen verhindern" msgid "Users can no longer work around the maximum booking limit by chaining two bookings directly after one another." msgstr "Nutzende können nicht mehr das maximale Buchungslimit umgehen indem sie zwei Buchungen direkt aneinanderhängen." -#: src/Service/BookingRule.php:235 -#: src/Service/BookingRule.php:242 -#: src/Service/BookingRule.php:260 -#: src/Service/BookingRule.php:297 +#: src/Service/BookingRule.php:235 src/Service/BookingRule.php:242 +#: src/Service/BookingRule.php:260 src/Service/BookingRule.php:297 #: src/Service/BookingRule.php:315 msgid "You have reached your booking limit. Please leave some time in between bookings." msgstr "Du hast dein maximales Buchungslimit erreicht. Bitte lasse etwas Zeit zwischen deinen Buchungen." -#: src/Service/BookingRule.php:240 -#: src/Service/BookingRule.php:246 +#: src/Service/BookingRule.php:240 src/Service/BookingRule.php:246 msgid "Maximum booked days per week" msgstr "Maximal buchbare Tage pro Woche" @@ -3507,13 +3438,11 @@ msgstr "Nutzende können nur eine begrenzte Anzahl an Tagen pro Woche buchen." msgid "Number of days each user is allowed to book per week" msgstr "Anzahl der Tage, die jeder Nutzende pro Woche buchen darf" -#: src/Service/BookingRule.php:251 -#: src/Service/BookingRule.php:306 +#: src/Service/BookingRule.php:251 src/Service/BookingRule.php:306 msgid "At what day of the week should the counter be reset?" msgstr "An welchem Wochentag soll der Zähler zurückgesetzt werden?" -#: src/Service/BookingRule.php:258 -#: src/Service/BookingRule.php:264 +#: src/Service/BookingRule.php:258 src/Service/BookingRule.php:264 msgid "Maximum booked days per month" msgstr "Maximal buchbare Tage pro Monat" @@ -3525,8 +3454,7 @@ msgstr "Nutzende können nur eine begrenzte Anzahl an Tagen pro Monat buchen." msgid "Number of days each user is allowed to book per month" msgstr "Anzahl der Tage, die jeder Nutzende pro Monat buchen darf" -#: src/Service/BookingRule.php:269 -#: src/Service/BookingRule.php:324 +#: src/Service/BookingRule.php:269 src/Service/BookingRule.php:324 msgid "At what day of the month should the counter be reset?" msgstr "An welchem Tag im Monat soll der Zähler zurückgesetzt werden?" @@ -3558,8 +3486,7 @@ msgstr "Über den Zeitraum von Y Tagen" msgid "The length of the period for which the booking is limited. This period always lies in the middle, so if you define 30 days, the 15 days before and after will count towards the maximum quota." msgstr "Die Länger der Periode in denen die Buchungen eingeschränkt werden. Die Periode liegt immer in der Mitte, wenn du also 30 Tage definierst werden 15 Tage davor und 15 Tage danach in die Buchungsperiode mit eingerechnet." -#: src/Service/BookingRule.php:295 -#: src/Service/BookingRule.php:301 +#: src/Service/BookingRule.php:295 src/Service/BookingRule.php:301 msgid "Maximum number of bookings per week" msgstr "Maximale Anzahl an Buchungen pro Woche" @@ -3571,8 +3498,7 @@ msgstr "Nutzende dürfen nur so viele Buchungen pro Woche tätigen (die Länge d msgid "Number of bookings each user is allowed to make per week" msgstr "Anzahl der Buchungen die jeder Nutzende pro Woche tätigen darf" -#: src/Service/BookingRule.php:313 -#: src/Service/BookingRule.php:319 +#: src/Service/BookingRule.php:313 src/Service/BookingRule.php:319 msgid "Maximum number of bookings per month" msgstr "Maximale Anzahl an Buchungen pro Monat" @@ -3646,8 +3572,7 @@ msgstr "Deine Daten" msgid "Reminder for locations before booking starts" msgstr "Erinnerung für Standorte vor Buchungsbeginn" -#: includes/OptionsArray.php:1074 -#: includes/OptionsArray.php:1161 +#: includes/OptionsArray.php:1074 includes/OptionsArray.php:1161 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." @@ -3667,8 +3592,7 @@ msgstr "" "\n" "{{booking:getEmailSignature}}" -#: includes/OptionsArray.php:1121 -#: includes/OptionsArray.php:1210 +#: includes/OptionsArray.php:1121 includes/OptionsArray.php:1210 msgid "Bookings of" msgstr "Buchungen von" @@ -3676,13 +3600,11 @@ msgstr "Buchungen von" 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:1133 -#: includes/OptionsArray.php:1222 +#: includes/OptionsArray.php:1133 includes/OptionsArray.php:1222 msgid "current day" msgstr "Gleicher Tag" -#: includes/OptionsArray.php:1134 -#: includes/OptionsArray.php:1223 +#: includes/OptionsArray.php:1134 includes/OptionsArray.php:1223 msgid "next day" msgstr "Nächstem Tag" @@ -3807,8 +3729,7 @@ msgstr "Ungültiges Enddatum" msgid "Start date must not be after the end date." msgstr "Das Startdatum darf nicht nach dem Enddatum liegen." -#: src/Service/TimeframeExport.php:223 -#: src/View/TimeframeExport.php:39 +#: src/Service/TimeframeExport.php:223 src/View/TimeframeExport.php:39 msgid "Export finished" msgstr "Export beendet" @@ -3844,8 +3765,7 @@ msgstr "Zeitrahmen wurde als Entwurf gespeichert." msgid "Item not found" msgstr "Artikel nicht gefunden" -#: src/Model/Booking.php:621 -#: src/Wordpress/CustomPostType/Location.php:147 +#: src/Model/Booking.php:621 src/Wordpress/CustomPostType/Location.php:147 msgid "Location not found" msgstr "Standort nicht gefunden" @@ -3887,8 +3807,7 @@ msgstr "Das gleiche Datum wurde mehrere Male ausgewählt. Bitte ein Datum nur ei msgid "Startdate is missing. Please enter a start date to publish this timeframe." msgstr "Das Startdatum fehlt. Ein Startdatum muss eingegeben werden, damit der Zeitrahmen veröffentlicht werden kann." -#: src/View/Booking.php:578 -#: src/Wordpress/CustomPostType/Booking.php:877 +#: src/View/Booking.php:578 src/Wordpress/CustomPostType/Booking.php:877 msgid "Submit booking" msgstr "Buchung abschicken" @@ -3918,8 +3837,7 @@ msgstr "" msgid "This will create the specified booking and send out the booking confirmation email." msgstr "Dadurch wird die angegebene Buchung erstellt und die Buchungsbestätigung per E-Mail verschickt." -#: src/Plugin.php:404 -#: src/Plugin.php:405 +#: src/Plugin.php:404 src/Plugin.php:405 msgid "Mass Operations" msgstr "Massenverarbeitung" @@ -3964,8 +3882,7 @@ msgid "Migrate orphaned bookings" msgstr "Verwaiste Buchungen migrieren" #. translators: %s numeric post id -#: src/Service/MassOperations.php:65 -#: src/Service/MassOperations.php:69 +#: src/Service/MassOperations.php:65 src/Service/MassOperations.php:69 #, php-format msgid "New location not found for booking with ID %s" msgstr "Neuer Standort für Buchung mit ID %s konnte nicht gefunden werden" @@ -4413,25 +4330,17 @@ msgstr "" "\t\t\t\t%1$sWeitere Informationen in der Dokumentation%2$s\r\n" "\t\t\t\t" -#: src/Model/Booking.php:1024 -#~ msgid "Unconfirmed" -#~ msgstr "Unbestätigt" - -#: src/Model/Booking.php:1022 -#~ msgid "Confirmed" -#~ msgstr "Bestätigt" - #: includes/OptionsArray.php:1553 msgid "Enables users to copy a url for a dynamic iCalendar feed into their own digital calendars." -msgstr "" +msgstr "Erlaubt Nutzenden eine URL für einen dynamischen iCalendar in ihre eigenen digitalen Kalender zu kopieren." #: includes/OptionsArray.php:1567 msgid "This is the event title that will be given to bookings that do not belong to the current user. This is what the CB-Manager will see when they subscribe to the station calendar. You can use template tags here as well" -msgstr "" +msgstr "Dies ist der Titel für Kalendereinträge von Buchungen, die nicht dem aktuell angemeldeten Nutzenden zugeordnet sind. Solche Einträge sind für Personen mit der Rolle „CB-Manager“ sichtbar, wenn sie den Kalender einer Station abonnieren. Hier können auch Template-Tags genutzt werden." #: includes/OptionsArray.php:1574 msgid "This is the event description that will be given to bookings that do not belong to the current user. This is what the CB-Manager will see when they subscribe to the station calendar. You can use template tags here." -msgstr "" +msgstr "Dies ist die Beschreibung für Kalendereinträge von Buchungen, die nicht dem aktuell angemeldeten Nutzenden zugeordnet sind. Solche Einträge sind für Personen mit der Rolle „CB-Manager“ sichtbar, wenn sie den Kalender einer Station abonnieren. Hier können auch Template-Tags genutzt werden." #: includes/OptionsArray.php:1576 msgid "" @@ -4441,14 +4350,19 @@ msgid "" "Booking code: {{booking:formattedBookingCode}}\n" "User Email: {{user:user_email}}" msgstr "" +"\n" +"Abholung: {{booking:pickupDatetime}}\r\n" +"Rückgabe: {{booking:returnDatetime}}\r\n" +"Buchungscode: {{booking:formattedBookingCode}}\r\n" +"E-Mail des Nutzenden: {{user:user_email}}" #: src/Wordpress/CustomPostType/Item.php:287 msgid "Exclude from API" -msgstr "" +msgstr "In API verstecken" #: src/Wordpress/CustomPostType/Item.php:288 msgid "When this box is checked, the item will not appear in any of the API shares." -msgstr "" +msgstr "Wenn diese Box angewählt ist taucht der Artikel in keiner der API Freigaben auf." #: src/Wordpress/CustomPostType/Booking.php:758 msgid "" @@ -4461,6 +4375,14 @@ 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.
      \r\n" +"\t\t\t\t

        \r\n" +"
      • Klicke auf den Vorschau Knopf auf der rechten Seite, um weitere Buchungsdetails zu sehen und die Buchung über die Schaltfläche „Stornieren“ zu stornieren.
      • \r\n" +"
      • Klicke auf den Buchung abschicken Knopf am Ende der Seite um die Buchung zu bestätigen..
      • \r\n" +"
      \r\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.\r\n" +"

      \r\n" +"\t\t\t\t" #: src/Wordpress/CustomPostType/Booking.php:901 #, php-format @@ -4472,7 +4394,19 @@ msgid "" "\t\tTo search and filter bookings please integrate the frontend booking list via shortcode.\n" "\t\tSee here %1$sHow to display the booking list%2$s" msgstr "" +"Buchungen sollten über den Buchungskalender im Frontend erstellt werden.
      \r\n" +"\t\tAls Admin kannst du Buchungen über das Backend erstellen. Bitte beachte, dass die Buchungen dort nicht validiert werden.\r\n" +"\t\tNutze diese Funktion mit Vorsicht.
      \r\n" +"\t\tKlicke auf den Vorschau Knopf, um die Details der Buchung im Frontend anzuzeigen.
      \r\n" +"\t\tUm Buchungen zu filtern und durchsuchen, kann der Buchungsshortcode auf einer Frontend Seite eingefügt werden.\r\n" +"\t\tIn der Dokumentation %1$sBuchungsliste anzeigen%2$s" #: src/Wordpress/CustomPostType/Booking.php:304 msgid "Invalid booking request. Please try again." -msgstr "" +msgstr "Ungültige Buchungsanfrage. Bitte erneut versuchen." + +#~ msgid "Unconfirmed" +#~ msgstr "Unbestätigt" + +#~ msgid "Confirmed" +#~ msgstr "Bestätigt" From 9dfdc7fd429aaab8d017bfba86893c0b05bae936 Mon Sep 17 00:00:00 2001 From: hansmorb Date: Wed, 17 Jun 2026 13:53:32 +0000 Subject: [PATCH 098/148] Ran wp i18n make-pot --- languages/commonsbooking-de_DE.po | 287 +++++++++++++++++++----------- languages/commonsbooking.pot | 40 ++--- 2 files changed, 206 insertions(+), 121 deletions(-) diff --git a/languages/commonsbooking-de_DE.po b/languages/commonsbooking-de_DE.po index f8afc4064..1aa95cf0f 100644 --- a/languages/commonsbooking-de_DE.po +++ b/languages/commonsbooking-de_DE.po @@ -2,14 +2,14 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/commonsbooking\n" -"POT-Creation-Date: 2023-09-15T04:04:14+02:00\n" -"PO-Revision-Date: 2026-06-17 15:48+0200\n" "Last-Translator: Christian Wenzel \n" "Language-Team: English \n" -"Language: de_DE\n" "MIME-Version: 1.0\n" "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: 2026-06-17 15:48+0200\n" +"Language: de_DE\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.9\n" @@ -41,7 +41,8 @@ msgstr "Alle Zeitrahmen-Typen" msgid "Welcome" msgstr "Willkommen" -#: includes/OptionsArray.php:44 templates/dashboard-index.php:8 +#: includes/OptionsArray.php:44 +#: templates/dashboard-index.php:8 msgid "Welcome to CommonsBooking" msgstr "Willkommen bei CommonsBooking" @@ -82,7 +83,8 @@ msgstr "Buchungsseite" msgid "The page where you included the [cb_bookings] shortcode. This is used in the Users Widget" msgstr "Die Seite, auf der Du den [cb_bookings]-Kurzcode eingefügt hast. Dies wird im Benutzer*in Widget verwendet" -#: includes/OptionsArray.php:151 includes/OptionsArray.php:165 +#: includes/OptionsArray.php:151 +#: includes/OptionsArray.php:165 msgid "Booking comment" msgstr "Buchungskommentar" @@ -128,19 +130,23 @@ msgstr "Vorlagen" msgid "Email templates" msgstr "E-Mail Vorlagen" -#: includes/OptionsArray.php:284 includes/OptionsArray.php:660 +#: includes/OptionsArray.php:284 +#: includes/OptionsArray.php:660 msgid "Mail-Header from E-Mail" msgstr "Absender E-Mail Mail-Adresse" -#: includes/OptionsArray.php:285 includes/OptionsArray.php:661 +#: includes/OptionsArray.php:285 +#: includes/OptionsArray.php:661 msgid "E-Mail that will be shown as sender in generated emails" msgstr "E-Mail, die als Absender in automatisch versendeten E-Mails angezeigt wird" -#: includes/OptionsArray.php:291 includes/OptionsArray.php:667 +#: includes/OptionsArray.php:291 +#: includes/OptionsArray.php:667 msgid "Mail-Header from Name" msgstr "Absender E-Mail Name" -#: includes/OptionsArray.php:292 includes/OptionsArray.php:668 +#: includes/OptionsArray.php:292 +#: includes/OptionsArray.php:668 msgid "Name that will be shown as sender in generated emails" msgstr "Name, der als Absender in automatisch versendeten E-Mails angezeigt wird" @@ -650,22 +656,29 @@ msgstr "Erinnerung" msgid "Booking reminder" msgstr "Buchungserinnerung" -#: includes/OptionsArray.php:912 includes/OptionsArray.php:1023 -#: includes/OptionsArray.php:1071 includes/OptionsArray.php:1158 +#: includes/OptionsArray.php:912 +#: includes/OptionsArray.php:1023 +#: includes/OptionsArray.php:1071 +#: includes/OptionsArray.php:1158 msgid "Activate" msgstr "Aktivieren" -#: includes/OptionsArray.php:918 includes/OptionsArray.php:1029 -#: includes/OptionsArray.php:1078 includes/OptionsArray.php:1165 +#: includes/OptionsArray.php:918 +#: includes/OptionsArray.php:1029 +#: includes/OptionsArray.php:1078 +#: includes/OptionsArray.php:1165 msgid "E-mail subject" msgstr "E-Mail Betreff" -#: includes/OptionsArray.php:921 includes/OptionsArray.php:1081 +#: includes/OptionsArray.php:921 +#: includes/OptionsArray.php:1081 msgid "Upcoming booking of {{item:post_title}} {{booking:formattedBookingDate}}" msgstr "Bevorstehende Buchung von {{item:post_title}} {{booking:formattedBookingDate}}" -#: includes/OptionsArray.php:924 includes/OptionsArray.php:1035 -#: includes/OptionsArray.php:1084 includes/OptionsArray.php:1171 +#: includes/OptionsArray.php:924 +#: includes/OptionsArray.php:1035 +#: includes/OptionsArray.php:1084 +#: includes/OptionsArray.php:1171 msgid "email body" msgstr "E-Mail-Text" @@ -700,12 +713,14 @@ msgstr "Sende eine Erinnerung x Tage vor Buchungsbeginn" 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:965 includes/OptionsArray.php:1101 +#: includes/OptionsArray.php:965 +#: includes/OptionsArray.php:1101 #: includes/OptionsArray.php:1189 msgid "Time" msgstr "Uhrzeit" -#: includes/OptionsArray.php:968 includes/OptionsArray.php:1104 +#: includes/OptionsArray.php:968 +#: includes/OptionsArray.php:1104 #: includes/OptionsArray.php:1192 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." @@ -747,7 +762,8 @@ msgstr "Migration" msgid "Migrate from Commons Booking Version 0.X" msgstr "Migriere von Commons Booking Version 0.X" -#: includes/OptionsArray.php:1265 src/View/Migration.php:77 +#: includes/OptionsArray.php:1265 +#: src/View/Migration.php:77 msgid "Start Migration" msgstr "Migration starten" @@ -775,12 +791,14 @@ msgstr "Buchungen auf neue Version migrieren" 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:1300 src/View/MassOperations.php:109 +#: includes/OptionsArray.php:1300 +#: src/View/MassOperations.php:109 #: src/View/Migration.php:112 msgid "Migrate bookings" msgstr "Buchungen migrieren" -#: includes/OptionsArray.php:1313 includes/OptionsArray.php:1373 +#: includes/OptionsArray.php:1313 +#: includes/OptionsArray.php:1373 msgid "Export" msgstr "Export" @@ -788,7 +806,8 @@ msgstr "Export" msgid "Download timeframes export" msgstr "Zeitrahmen-Export herunterladen" -#: includes/OptionsArray.php:1321 src/Wordpress/CustomPostType/Map.php:557 +#: includes/OptionsArray.php:1321 +#: src/Wordpress/CustomPostType/Map.php:557 #: src/Wordpress/CustomPostType/Restriction.php:47 #: src/Wordpress/CustomPostType/Restriction.php:415 #: src/Wordpress/CustomPostType/Timeframe.php:98 @@ -805,7 +824,8 @@ msgid "Location-Fields" msgstr "Standort-Felder" #. translators: %s formatted meta field as an var_dump-like assoc array string -#: includes/OptionsArray.php:1331 includes/OptionsArray.php:1341 +#: includes/OptionsArray.php:1331 +#: includes/OptionsArray.php:1341 #, php-format 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" @@ -842,7 +862,8 @@ msgstr "Als Cronjob anlegen" msgid "Export interval" msgstr "Exportintervall" -#: includes/OptionsArray.php:1394 includes/OptionsArray.php:1395 +#: includes/OptionsArray.php:1394 +#: includes/OptionsArray.php:1395 msgid "minutes" msgstr "Minuten" @@ -866,7 +887,8 @@ msgstr "Dateipfad" 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:1423 includes/OptionsArray.php:1469 +#: includes/OptionsArray.php:1423 +#: includes/OptionsArray.php:1469 msgid "API" msgstr "Schnittstelle" @@ -984,70 +1006,71 @@ msgstr "Erlaubt die Anpassung der Optionen für das Caching-System" msgid "Current connection status" msgstr "Aktueller Verbindungsstatus" -#: src/CB/CB1UserFields.php:69 +#: src/CB/CB1UserFields.php:72 msgid "First Name" msgstr "Vorname" -#: src/CB/CB1UserFields.php:72 +#: src/CB/CB1UserFields.php:75 msgid "Please enter your first name" msgstr "Bitte gib deinen Vornamen ein" -#: src/CB/CB1UserFields.php:76 +#: src/CB/CB1UserFields.php:79 msgid "Last Name" msgstr "Nachname" -#: src/CB/CB1UserFields.php:79 +#: src/CB/CB1UserFields.php:82 msgid "Please enter your last name" msgstr "Bitte gib Deinen Nachnamen ein" -#: src/CB/CB1UserFields.php:83 +#: src/CB/CB1UserFields.php:86 msgid "Phone Number" msgstr "Telefonnummer" -#: src/CB/CB1UserFields.php:86 +#: src/CB/CB1UserFields.php:89 msgid "Please enter your phone number" msgstr "Bitte gib Deine Telefonnummer ein" -#: src/CB/CB1UserFields.php:90 src/CB/CB1UserFields.php:279 +#: src/CB/CB1UserFields.php:93 +#: src/CB/CB1UserFields.php:283 #: src/Wordpress/CustomPostType/Location.php:237 #: templates/booking-single.php:77 msgid "Address" msgstr "Adresse" -#: src/CB/CB1UserFields.php:93 +#: src/CB/CB1UserFields.php:96 msgid "Please enter your address" msgstr "Bitte gib deine Adresse ein" -#: src/CB/CB1UserFields.php:96 +#: src/CB/CB1UserFields.php:99 msgid "Terms and Conditions" msgstr "Nutzungsbedingungen" -#: src/CB/CB1UserFields.php:99 +#: src/CB/CB1UserFields.php:102 msgid "I accept the terms & conditions" msgstr "Ich akzeptiere die Nutzungsbedingungen" -#: src/CB/CB1UserFields.php:100 +#: src/CB/CB1UserFields.php:103 msgid "Please accept the terms & conditions" msgstr "Bitte akzeptiere die Nutzungsbedingungen" -#: src/CB/CB1UserFields.php:188 +#: src/CB/CB1UserFields.php:191 #, php-format msgid "Read the terms and services" msgstr "Lies die Nutzungsbedingungen" -#: src/CB/CB1UserFields.php:267 +#: src/CB/CB1UserFields.php:271 msgid "Extra Fields" msgstr "Zusatzfelder" -#: src/CB/CB1UserFields.php:271 +#: src/CB/CB1UserFields.php:275 msgid "Phone number" msgstr "Telefonnummer" -#: src/CB/CB1UserFields.php:287 +#: src/CB/CB1UserFields.php:291 msgid "Terms and conditions" msgstr "Nutzungsbedingungen" -#: src/CB/CB1UserFields.php:297 +#: src/CB/CB1UserFields.php:301 msgid "Accepted Terms & Conditions" msgstr "Nutzungsbedingungen akzeptiert" @@ -1055,7 +1078,8 @@ msgstr "Nutzungsbedingungen akzeptiert" msgid "map is not published" msgstr "Karte ist nicht veröffentlicht" -#: src/Map/BaseShortcode.php:26 src/Map/BaseShortcode.php:32 +#: src/Map/BaseShortcode.php:26 +#: src/Map/BaseShortcode.php:32 msgid "no valid map id provided" msgstr "keine gültige Karten-ID angegeben" @@ -1087,19 +1111,23 @@ msgstr "Tag(e)" msgid "Sorry, no locations found." msgstr "Leider wurden keine Standorte gefunden." -#: src/Map/MapShortcode.php:58 src/Wordpress/CustomPostType/Map.php:533 +#: src/Map/MapShortcode.php:58 +#: src/Wordpress/CustomPostType/Map.php:533 msgid "filter" msgstr "Filter" -#: src/Map/MapShortcode.php:59 src/Wordpress/CustomPostType/Map.php:515 +#: src/Map/MapShortcode.php:59 +#: src/Wordpress/CustomPostType/Map.php:515 msgid "availability" msgstr "Verfügbarkeit" -#: src/Map/MapShortcode.php:60 src/Wordpress/CustomPostType/Map.php:524 +#: src/Map/MapShortcode.php:60 +#: src/Wordpress/CustomPostType/Map.php:524 msgid "categories" msgstr "Kategorien" -#: src/Map/MapShortcode.php:61 src/Wordpress/CustomPostType/Map.php:476 +#: src/Map/MapShortcode.php:61 +#: src/Wordpress/CustomPostType/Map.php:476 msgid "distance" msgstr "Entfernung" @@ -1151,7 +1179,8 @@ msgstr "Link zu deiner Buchung" msgid "Please contact the contact persons at the location directly if you have any questions regarding collection or return:" msgstr "Bitte kontaktiere die Kontaktpersonen vor Ort direkt, wenn du Fragen zur Abholung oder Rückgabe hast:" -#: src/Model/Restriction.php:244 src/Model/Restriction.php:268 +#: src/Model/Restriction.php:248 +#: src/Model/Restriction.php:275 msgid "Not set" msgstr "Nicht gesetzt" @@ -1160,7 +1189,8 @@ msgid "Available here" msgstr "Hier verfügbar" #. translators: %s = date in WordPress defined format -#: src/Model/Booking.php:437 src/Model/Timeframe.php:336 +#: src/Model/Booking.php:437 +#: src/Model/Timeframe.php:336 #, php-format msgid "on %s" msgstr "am %s" @@ -1177,7 +1207,8 @@ msgstr "dauerhaft" #. translators: %1 = startdate, %2 = enddate in WordPress defined format #. translators: %1$s = startdate, second %2$s = enddate in WordPress defined format -#: src/Model/Booking.php:440 src/Model/Timeframe.php:351 +#: src/Model/Booking.php:440 +#: src/Model/Timeframe.php:351 #, php-format msgid "from %1$s until %2$s" msgstr "von %1$s bis %2$s" @@ -1202,11 +1233,13 @@ msgstr "Enddatum liegt vor dem Startdatum. Bitte setze ein gültiges Enddatum." msgid "Item is already bookable at another location within the same date range. See other timeframe ID: %1$s: %2$s" msgstr "Artikel ist bereits an einem anderen Ort innerhalb desselben Datumsbereichs buchbar. Siehe andere Zeitrahmen ID: %1$s: %2$s" -#: src/Plugin.php:384 src/Plugin.php:385 +#: src/Plugin.php:384 +#: src/Plugin.php:385 msgid "Item Categories" msgstr "Artikel-Kategorien" -#: src/Plugin.php:394 src/Plugin.php:395 +#: src/Plugin.php:394 +#: src/Plugin.php:395 msgid "Location Categories" msgstr "Standort-Kategorien" @@ -1241,13 +1274,15 @@ msgstr "Aktueller Verbindungsstatus:" msgid "Directory %s could not be written to." msgstr "Der Ordner %s ist nicht beschreibbar." -#: src/View/Admin/Filter.php:58 src/Wordpress/CustomPostType/Booking.php:792 +#: src/View/Admin/Filter.php:58 +#: src/Wordpress/CustomPostType/Booking.php:792 #: src/Wordpress/CustomPostType/Restriction.php:451 #: src/Wordpress/CustomPostType/Timeframe.php:678 msgid "Start date" msgstr "Startdatum" -#: src/View/Admin/Filter.php:62 src/Wordpress/CustomPostType/Booking.php:809 +#: src/View/Admin/Filter.php:62 +#: src/Wordpress/CustomPostType/Booking.php:809 #: src/Wordpress/CustomPostType/Restriction.php:461 #: src/Wordpress/CustomPostType/Timeframe.php:702 msgid "End date" @@ -1265,18 +1300,21 @@ msgstr "Benutze diesen Link um die Buchungsdaten automatisch in deinem Kalender msgid "iCalendar Link:" msgstr "iCalendar Link:" -#: src/View/Booking.php:171 src/View/Booking.php:173 +#: src/View/Booking.php:171 +#: src/View/Booking.php:173 msgid "Not available" msgstr "Nicht verfügbar" -#: src/View/Booking.php:196 src/View/MassOperations.php:38 +#: src/View/Booking.php:196 +#: src/View/MassOperations.php:38 #: src/Wordpress/CustomPostType/Booking.php:459 #: src/Wordpress/CustomPostType/Timeframe.php:97 #: templates/shortcode-bookings.php:74 msgid "User" msgstr "Nutzende*r" -#: src/View/Booking.php:200 src/View/MassOperations.php:42 +#: src/View/Booking.php:200 +#: src/View/MassOperations.php:42 #: src/Wordpress/CustomPostType/Booking.php:986 #: src/Wordpress/CustomPostType/Restriction.php:477 msgid "Status" @@ -1294,7 +1332,8 @@ msgstr "Die Datei wird als .txt Datei durch Tabstopp getrennt exportiert, sodass msgid "Booking codes list" msgstr "Liste der Buchungscodes" -#: src/View/Calendar.php:237 src/Wordpress/CustomPostType/Booking.php:460 +#: src/View/Calendar.php:237 +#: src/Wordpress/CustomPostType/Booking.php:460 #: src/Wordpress/CustomPostType/Booking.php:774 #: src/Wordpress/CustomPostType/Booking.php:1002 #: src/Wordpress/CustomPostType/Item.php:117 @@ -1309,7 +1348,8 @@ msgstr "Artikel" msgid "No items found." msgstr "Keine Artikel gefunden." -#: src/View/Calendar.php:238 src/Wordpress/CustomPostType/Booking.php:461 +#: src/View/Calendar.php:238 +#: src/Wordpress/CustomPostType/Booking.php:461 #: src/Wordpress/CustomPostType/Booking.php:780 #: src/Wordpress/CustomPostType/Booking.php:998 #: src/Wordpress/CustomPostType/Location.php:139 @@ -1321,7 +1361,8 @@ msgstr "Keine Artikel gefunden." msgid "Location" msgstr "Standort" -#: src/View/Dashboard.php:48 src/View/Dashboard.php:94 +#: src/View/Dashboard.php:48 +#: src/View/Dashboard.php:94 msgid "at" msgstr "bei" @@ -1393,7 +1434,8 @@ 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:99 src/View/Migration.php:57 +#: src/View/MassOperations.php:99 +#: src/View/Migration.php:57 #: src/View/Migration.php:103 msgid "Migration finished" msgstr "Migration beendet" @@ -1406,11 +1448,13 @@ 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:94 src/View/Migration.php:98 +#: src/View/MassOperations.php:94 +#: src/View/Migration.php:98 msgid "migration in process .. please wait ..." msgstr "Migration wird durchgeführt … bitte warten ..." -#: src/View/MassOperations.php:104 src/View/Migration.php:108 +#: src/View/MassOperations.php:104 +#: src/View/Migration.php:108 msgid "Migration failed" msgstr "Migration fehlgeschlagen" @@ -1430,9 +1474,12 @@ msgstr "CSV Herunterladen" msgid "Download Export" msgstr "Download Export" -#: src/Model/Booking.php:1028 src/Service/TimeframeExport.php:591 -#: src/Service/TimeframeExport.php:601 src/Service/TimeframeExport.php:607 -#: src/Service/TimeframeExport.php:619 src/Service/TimeframeExport.php:632 +#: src/Model/Booking.php:1028 +#: src/Service/TimeframeExport.php:591 +#: src/Service/TimeframeExport.php:601 +#: src/Service/TimeframeExport.php:607 +#: src/Service/TimeframeExport.php:619 +#: src/Service/TimeframeExport.php:632 msgid "Unknown" msgstr "Unbekannt" @@ -1625,7 +1672,8 @@ msgstr "Lege das Startdatum fest. Setze die Uhrzeit auf 00:00, wenn du den ganze msgid "Set the end date. You must set time to 23:59 if you want to book the full day" msgstr "Lege das Enddatum fest. Setze die Zeit auf 23:59 Uhr, wenn du den ganzen Tag buchen willst" -#: src/Wordpress/CustomPostType/Booking.php:826 templates/booking-single.php:59 +#: src/Wordpress/CustomPostType/Booking.php:826 +#: templates/booking-single.php:59 msgid "Booking Code" msgstr "Buchungscode" @@ -1646,7 +1694,8 @@ msgid "Filter By Category " msgstr "Nach Kategorie filtern " #: src/Wordpress/CustomPostType/Item.php:116 -#: src/Wordpress/CustomPostType/Item.php:137 templates/dashboard-index.php:33 +#: src/Wordpress/CustomPostType/Item.php:137 +#: templates/dashboard-index.php:33 msgid "Items" msgstr "Artikel" @@ -1875,7 +1924,8 @@ msgid "Location email" msgstr "Standort E-Mail" #: src/Wordpress/CustomPostType/Location.php:395 -#: templates/booking-single.php:86 templates/location-single-meta.php:53 +#: templates/booking-single.php:86 +#: templates/location-single-meta.php:53 msgid "Pickup instructions" msgstr "Abhol-Hinweise" @@ -1911,7 +1961,8 @@ msgstr "Überbuchen von geblockten Tagen erlauben" msgid "Location Meta-Data" msgstr "Standort-Metadaten" -#: src/Wordpress/CustomPostType/Map.php:616 templates/dashboard-index.php:55 +#: src/Wordpress/CustomPostType/Map.php:616 +#: templates/dashboard-index.php:55 msgid "Maps" msgstr "Karten" @@ -2455,11 +2506,13 @@ msgstr "Du darfst nicht auf diese Buchung zugreifen." msgid "Login to your account" msgstr "Login zu deinem Nutzerkonto" -#: templates/booking-single.php:45 templates/timeframe-calendar.php:51 +#: templates/booking-single.php:45 +#: templates/timeframe-calendar.php:51 msgid "Pickup" msgstr "Abholung" -#: templates/booking-single.php:49 templates/timeframe-calendar.php:62 +#: templates/booking-single.php:49 +#: templates/timeframe-calendar.php:62 msgid "Return" msgstr "Rückgabe" @@ -2467,7 +2520,8 @@ msgstr "Rückgabe" msgid "Location: " msgstr "Standort: " -#: templates/booking-single.php:95 templates/booking-single.php:103 +#: templates/booking-single.php:95 +#: templates/booking-single.php:103 msgid "Contact" msgstr "Kontakt" @@ -2556,7 +2610,8 @@ msgid "No returns today" msgstr "Keine Rückgaben heute" #. translators: %1$s: wp_login_url, 1$s: wp_registration_url -#: templates/item-single.php:44 templates/location-single.php:49 +#: templates/item-single.php:44 +#: templates/location-single.php:49 #, php-format msgid "To be able to book, you must first login or register." msgstr "Um buchen zu können, musst du dich zuerst anmelden oder registrieren." @@ -2890,11 +2945,13 @@ msgstr "Vorfiltern nach Standort-Kategorien" msgid "No bookings available." msgstr "Keine Buchungen vorhanden." -#: templates/shortcode-bookings.php:35 templates/shortcode-bookings.php:71 +#: templates/shortcode-bookings.php:35 +#: templates/shortcode-bookings.php:71 msgid "Startdate" msgstr "Startdatum" -#: templates/shortcode-bookings.php:42 templates/shortcode-bookings.php:72 +#: templates/shortcode-bookings.php:42 +#: templates/shortcode-bookings.php:72 msgid "Enddate" msgstr "Enddatum" @@ -2972,7 +3029,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:720 src/Plugin.php:735 +#: src/Plugin.php:720 +#: src/Plugin.php:735 #: src/Wordpress/CustomPostType/Booking.php:949 msgid "CommonsBooking Bookings" msgstr "CommonsBooking Buchungen" @@ -3069,7 +3127,8 @@ msgstr "Mehrere buchbare Zeiträume überschneiden sich in den definierten Woche msgid "Overlapping bookable timeframes are not allowed to have the same dates." msgstr "Mehrere buchbare Zeiträume überschneiden sich in dem definierten Datumsbereich." -#: src/Model/Timeframe.php:915 src/Model/Timeframe.php:922 +#: src/Model/Timeframe.php:915 +#: src/Model/Timeframe.php:922 msgid "The other timeframe is overlapping with your weekly configuration." msgstr "Der andere Zeitrahmen überschneidet sich mit einer wöchentlichen Konfiguration." @@ -3113,7 +3172,8 @@ msgstr "Wählen Sie das Jahr und das Bundesland, für das Sie Feiertage importie msgid "Daily repeated time periods are not allowed to overlap." msgstr "Täglich wiederholende Zeiträume dürfen sich nicht überschneiden." -#: includes/OptionsArray.php:188 includes/OptionsArray.php:192 +#: includes/OptionsArray.php:188 +#: includes/OptionsArray.php:192 #: includes/OptionsArray.php:208 msgid "Booking codes" msgstr "Buchungscodes" @@ -3162,7 +3222,8 @@ msgstr "iCalendar-Datei an eine E-Mail mit Buchungscodes anhängen" msgid "Will attach an iCalendar compatible file with booking codes per day to import in their respective calendar application." msgstr "Fügt eine iCalendar-kompatible Datei mit Buchungscodes für die einzelnen Tage bei, um sie in die jeweilige Kalenderanwendung zu importieren." -#: src/Messages/BookingCodesMessage.php:56 src/View/BookingCodes.php:181 +#: src/Messages/BookingCodesMessage.php:56 +#: src/View/BookingCodes.php:181 #: src/View/BookingCodes.php:290 msgid "Unable to send Emails. No location email(s) configured, check location" msgstr "Emails können nicht gesendet werden. Keine Standort-E-Mail(s) konfiguriert, bitte Standort prüfen" @@ -3181,12 +3242,15 @@ msgstr "Buchungscodes für Artikel \"%1$s\": %2$s" msgid "Error sending booking codes by E-mail for Timeframe " msgstr "Fehler beim Senden von Buchungscodes per E-Mail für Zeitrahmen " -#: src/View/BookingCodes.php:178 src/View/BookingCodes.php:287 +#: src/View/BookingCodes.php:178 +#: src/View/BookingCodes.php:287 msgid "No location configured for this timeframe" msgstr "Kein Standort für diesen Zeitraum konfiguriert" -#: src/View/BookingCodes.php:185 src/View/BookingCodes.php:294 -#: src/View/BookingCodes.php:397 src/View/BookingCodes.php:424 +#: src/View/BookingCodes.php:185 +#: src/View/BookingCodes.php:294 +#: src/View/BookingCodes.php:397 +#: src/View/BookingCodes.php:424 msgid "This timeframe has no booking codes. To generate booking codes you need to save the timeframe." msgstr "Dieser Zeitrahmen hat keine Buchungscodes. Um Buchungscodes zu generieren, muss der Zeitrahmen gespeichert werden." @@ -3262,7 +3326,8 @@ msgstr "Ein unbekannter Fehler ist aufgetreten" msgid "Email booking codes" msgstr "Buchungscodes per E-Mail versenden" -#: src/View/BookingCodes.php:281 src/Wordpress/CustomPostType/Timeframe.php:756 +#: src/View/BookingCodes.php:281 +#: src/Wordpress/CustomPostType/Timeframe.php:756 msgid "Send booking codes automated by email" msgstr "Buchungscodes automatisch per E-Mail versenden" @@ -3290,7 +3355,8 @@ msgstr "Nächste E-Mail geplant am: " msgid "(not planned)" msgstr "(nichts geplant)" -#: includes/OptionsArray.php:1597 src/Service/Cache.php:478 +#: includes/OptionsArray.php:1597 +#: src/Service/Cache.php:478 msgid "Clear Cache" msgstr "Cache leeren" @@ -3420,13 +3486,16 @@ msgstr "Kettenbuchungen verhindern" msgid "Users can no longer work around the maximum booking limit by chaining two bookings directly after one another." msgstr "Nutzende können nicht mehr das maximale Buchungslimit umgehen indem sie zwei Buchungen direkt aneinanderhängen." -#: src/Service/BookingRule.php:235 src/Service/BookingRule.php:242 -#: src/Service/BookingRule.php:260 src/Service/BookingRule.php:297 +#: src/Service/BookingRule.php:235 +#: src/Service/BookingRule.php:242 +#: src/Service/BookingRule.php:260 +#: src/Service/BookingRule.php:297 #: src/Service/BookingRule.php:315 msgid "You have reached your booking limit. Please leave some time in between bookings." msgstr "Du hast dein maximales Buchungslimit erreicht. Bitte lasse etwas Zeit zwischen deinen Buchungen." -#: src/Service/BookingRule.php:240 src/Service/BookingRule.php:246 +#: src/Service/BookingRule.php:240 +#: src/Service/BookingRule.php:246 msgid "Maximum booked days per week" msgstr "Maximal buchbare Tage pro Woche" @@ -3438,11 +3507,13 @@ msgstr "Nutzende können nur eine begrenzte Anzahl an Tagen pro Woche buchen." msgid "Number of days each user is allowed to book per week" msgstr "Anzahl der Tage, die jeder Nutzende pro Woche buchen darf" -#: src/Service/BookingRule.php:251 src/Service/BookingRule.php:306 +#: src/Service/BookingRule.php:251 +#: src/Service/BookingRule.php:306 msgid "At what day of the week should the counter be reset?" msgstr "An welchem Wochentag soll der Zähler zurückgesetzt werden?" -#: src/Service/BookingRule.php:258 src/Service/BookingRule.php:264 +#: src/Service/BookingRule.php:258 +#: src/Service/BookingRule.php:264 msgid "Maximum booked days per month" msgstr "Maximal buchbare Tage pro Monat" @@ -3454,7 +3525,8 @@ msgstr "Nutzende können nur eine begrenzte Anzahl an Tagen pro Monat buchen." msgid "Number of days each user is allowed to book per month" msgstr "Anzahl der Tage, die jeder Nutzende pro Monat buchen darf" -#: src/Service/BookingRule.php:269 src/Service/BookingRule.php:324 +#: src/Service/BookingRule.php:269 +#: src/Service/BookingRule.php:324 msgid "At what day of the month should the counter be reset?" msgstr "An welchem Tag im Monat soll der Zähler zurückgesetzt werden?" @@ -3486,7 +3558,8 @@ msgstr "Über den Zeitraum von Y Tagen" msgid "The length of the period for which the booking is limited. This period always lies in the middle, so if you define 30 days, the 15 days before and after will count towards the maximum quota." msgstr "Die Länger der Periode in denen die Buchungen eingeschränkt werden. Die Periode liegt immer in der Mitte, wenn du also 30 Tage definierst werden 15 Tage davor und 15 Tage danach in die Buchungsperiode mit eingerechnet." -#: src/Service/BookingRule.php:295 src/Service/BookingRule.php:301 +#: src/Service/BookingRule.php:295 +#: src/Service/BookingRule.php:301 msgid "Maximum number of bookings per week" msgstr "Maximale Anzahl an Buchungen pro Woche" @@ -3498,7 +3571,8 @@ msgstr "Nutzende dürfen nur so viele Buchungen pro Woche tätigen (die Länge d msgid "Number of bookings each user is allowed to make per week" msgstr "Anzahl der Buchungen die jeder Nutzende pro Woche tätigen darf" -#: src/Service/BookingRule.php:313 src/Service/BookingRule.php:319 +#: src/Service/BookingRule.php:313 +#: src/Service/BookingRule.php:319 msgid "Maximum number of bookings per month" msgstr "Maximale Anzahl an Buchungen pro Monat" @@ -3572,7 +3646,8 @@ msgstr "Deine Daten" msgid "Reminder for locations before booking starts" msgstr "Erinnerung für Standorte vor Buchungsbeginn" -#: includes/OptionsArray.php:1074 includes/OptionsArray.php:1161 +#: includes/OptionsArray.php:1074 +#: includes/OptionsArray.php:1161 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." @@ -3592,7 +3667,8 @@ msgstr "" "\n" "{{booking:getEmailSignature}}" -#: includes/OptionsArray.php:1121 includes/OptionsArray.php:1210 +#: includes/OptionsArray.php:1121 +#: includes/OptionsArray.php:1210 msgid "Bookings of" msgstr "Buchungen von" @@ -3600,11 +3676,13 @@ msgstr "Buchungen von" 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:1133 includes/OptionsArray.php:1222 +#: includes/OptionsArray.php:1133 +#: includes/OptionsArray.php:1222 msgid "current day" msgstr "Gleicher Tag" -#: includes/OptionsArray.php:1134 includes/OptionsArray.php:1223 +#: includes/OptionsArray.php:1134 +#: includes/OptionsArray.php:1223 msgid "next day" msgstr "Nächstem Tag" @@ -3729,7 +3807,8 @@ msgstr "Ungültiges Enddatum" msgid "Start date must not be after the end date." msgstr "Das Startdatum darf nicht nach dem Enddatum liegen." -#: src/Service/TimeframeExport.php:223 src/View/TimeframeExport.php:39 +#: src/Service/TimeframeExport.php:223 +#: src/View/TimeframeExport.php:39 msgid "Export finished" msgstr "Export beendet" @@ -3765,7 +3844,8 @@ msgstr "Zeitrahmen wurde als Entwurf gespeichert." msgid "Item not found" msgstr "Artikel nicht gefunden" -#: src/Model/Booking.php:621 src/Wordpress/CustomPostType/Location.php:147 +#: src/Model/Booking.php:621 +#: src/Wordpress/CustomPostType/Location.php:147 msgid "Location not found" msgstr "Standort nicht gefunden" @@ -3807,7 +3887,8 @@ msgstr "Das gleiche Datum wurde mehrere Male ausgewählt. Bitte ein Datum nur ei msgid "Startdate is missing. Please enter a start date to publish this timeframe." msgstr "Das Startdatum fehlt. Ein Startdatum muss eingegeben werden, damit der Zeitrahmen veröffentlicht werden kann." -#: src/View/Booking.php:578 src/Wordpress/CustomPostType/Booking.php:877 +#: src/View/Booking.php:578 +#: src/Wordpress/CustomPostType/Booking.php:877 msgid "Submit booking" msgstr "Buchung abschicken" @@ -3837,7 +3918,8 @@ msgstr "" msgid "This will create the specified booking and send out the booking confirmation email." msgstr "Dadurch wird die angegebene Buchung erstellt und die Buchungsbestätigung per E-Mail verschickt." -#: src/Plugin.php:404 src/Plugin.php:405 +#: src/Plugin.php:404 +#: src/Plugin.php:405 msgid "Mass Operations" msgstr "Massenverarbeitung" @@ -3882,7 +3964,8 @@ msgid "Migrate orphaned bookings" msgstr "Verwaiste Buchungen migrieren" #. translators: %s numeric post id -#: src/Service/MassOperations.php:65 src/Service/MassOperations.php:69 +#: src/Service/MassOperations.php:65 +#: src/Service/MassOperations.php:69 #, php-format msgid "New location not found for booking with ID %s" msgstr "Neuer Standort für Buchung mit ID %s konnte nicht gefunden werden" @@ -4405,8 +4488,10 @@ msgstr "" msgid "Invalid booking request. Please try again." msgstr "Ungültige Buchungsanfrage. Bitte erneut versuchen." +#: 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 06258bcfc..ccc305c2b 100644 --- a/languages/commonsbooking.pot +++ b/languages/commonsbooking.pot @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2026-06-17T13:27:47+00:00\n" +"POT-Creation-Date: 2026-06-17T13:53:30+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.12.0\n" "X-Domain: commonsbooking\n" @@ -1299,71 +1299,71 @@ msgstr "" msgid "Every day" msgstr "" -#: src/CB/CB1UserFields.php:69 +#: src/CB/CB1UserFields.php:72 msgid "First Name" msgstr "" -#: src/CB/CB1UserFields.php:72 +#: src/CB/CB1UserFields.php:75 msgid "Please enter your first name" msgstr "" -#: src/CB/CB1UserFields.php:76 +#: src/CB/CB1UserFields.php:79 msgid "Last Name" msgstr "" -#: src/CB/CB1UserFields.php:79 +#: src/CB/CB1UserFields.php:82 msgid "Please enter your last name" msgstr "" -#: src/CB/CB1UserFields.php:83 +#: src/CB/CB1UserFields.php:86 msgid "Phone Number" msgstr "" -#: src/CB/CB1UserFields.php:86 +#: src/CB/CB1UserFields.php:89 msgid "Please enter your phone number" msgstr "" -#: src/CB/CB1UserFields.php:90 -#: src/CB/CB1UserFields.php:279 +#: src/CB/CB1UserFields.php:93 +#: src/CB/CB1UserFields.php:283 #: src/Wordpress/CustomPostType/Location.php:237 #: templates/booking-single.php:77 msgid "Address" msgstr "" -#: src/CB/CB1UserFields.php:93 +#: src/CB/CB1UserFields.php:96 msgid "Please enter your address" msgstr "" -#: src/CB/CB1UserFields.php:96 +#: src/CB/CB1UserFields.php:99 msgid "Terms and Conditions" msgstr "" -#: src/CB/CB1UserFields.php:99 +#: src/CB/CB1UserFields.php:102 msgid "I accept the terms & conditions" msgstr "" -#: src/CB/CB1UserFields.php:100 +#: src/CB/CB1UserFields.php:103 msgid "Please accept the terms & conditions" msgstr "" -#: src/CB/CB1UserFields.php:188 +#: src/CB/CB1UserFields.php:191 #, php-format msgid "Read the terms and services" msgstr "" -#: src/CB/CB1UserFields.php:267 +#: src/CB/CB1UserFields.php:271 msgid "Extra Fields" msgstr "" -#: src/CB/CB1UserFields.php:271 +#: src/CB/CB1UserFields.php:275 msgid "Phone number" msgstr "" -#: src/CB/CB1UserFields.php:287 +#: src/CB/CB1UserFields.php:291 msgid "Terms and conditions" msgstr "" -#: src/CB/CB1UserFields.php:297 +#: src/CB/CB1UserFields.php:301 msgid "Accepted Terms & Conditions" msgstr "" @@ -1559,8 +1559,8 @@ msgstr "" msgid "Please contact the contact persons at the location directly if you have any questions regarding collection or return:" msgstr "" -#: src/Model/Restriction.php:244 -#: src/Model/Restriction.php:268 +#: src/Model/Restriction.php:248 +#: src/Model/Restriction.php:275 msgid "Not set" msgstr "" From 9968583009064b5dfd35434b640c83f9eb652d2a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Jun 2026 18:10:14 +0200 Subject: [PATCH 099/148] Bump actions/checkout from 6 to 7 (#2235) Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/benchmark.yml | 4 ++-- .github/workflows/build-docs.yml | 2 +- .github/workflows/build-rc.yml | 2 +- .github/workflows/compile.yml | 4 ++-- .github/workflows/copilot-setup-steps.yml | 2 +- .github/workflows/e2e.yml | 4 ++-- .github/workflows/phpcbf-check.yml | 2 +- .github/workflows/phpstan.yml | 4 ++-- .github/workflows/phpunit.yml | 2 +- .github/workflows/prettier.yml | 2 +- .github/workflows/release.yml | 2 +- .github/workflows/wpcs.yml | 2 +- .github/workflows/zip-pr.yml | 2 +- 13 files changed, 17 insertions(+), 17 deletions(-) diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 485e2b752..1f1f09134 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Checkout PR branch - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: ref: ${{ github.head_ref }} @@ -46,7 +46,7 @@ jobs: php vendor/bin/phpbench run tests/benchmark --report=aggregate > /tmp/pr-benchmark.txt - name: Checkout master branch - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: ref: master diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index b11c59776..c06819ef9 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -26,7 +26,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: fetch-depth: 0 diff --git a/.github/workflows/build-rc.yml b/.github/workflows/build-rc.yml index 0088935d6..fede46c33 100644 --- a/.github/workflows/build-rc.yml +++ b/.github/workflows/build-rc.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: ./.github/actions/build-plugin diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index 53f52dfb7..4935a41ed 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-24.04 name: Check i18n coverage steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: shivammathur/setup-php@v2 with: @@ -47,7 +47,7 @@ jobs: needs: i18n-coverage steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: ref: ${{ github.ref }} # checkout the latest commit so that we can push changes diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index 853bcfffb..2f478fe7e 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -27,7 +27,7 @@ jobs: # If you do not check out your code, Copilot will do this for you. steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Set up MySQL run: | diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index d65e57932..8aa1c050c 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -36,7 +36,7 @@ jobs: - {name: 'trunk', version: 'WordPress/WordPress#master'} steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: ./.github/actions/build-plugin @@ -77,7 +77,7 @@ jobs: wp-env --config=.wp-env.test.json run cli wp option patch insert commonsbooking_options_api apikey_not_required on - name: Checkout GBFS validator - uses: actions/checkout@v6 + uses: actions/checkout@v7 with: repository: MobilityData/gbfs-validator path: gbfs-validator diff --git a/.github/workflows/phpcbf-check.yml b/.github/workflows/phpcbf-check.yml index a5b72454e..0406c7514 100644 --- a/.github/workflows/phpcbf-check.yml +++ b/.github/workflows/phpcbf-check.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Set up PHP uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index e79a98618..82e25427e 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -25,7 +25,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 # TODO Use the composer action below - uses: shivammathur/setup-php@v2 @@ -44,7 +44,7 @@ jobs: run: | composer dump-autoload -o - #- uses: actions/checkout@v6 + #- uses: actions/checkout@v7 #- uses: php-actions/composer@v6 - name: PHPStan Static Analysis diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 688cde32c..5a1cc20fa 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -38,7 +38,7 @@ jobs: - { name: 'trunk', version: 'trunk' } steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Set up MySQL run: | diff --git a/.github/workflows/prettier.yml b/.github/workflows/prettier.yml index 277f7b4c5..9e5dbe541 100644 --- a/.github/workflows/prettier.yml +++ b/.github/workflows/prettier.yml @@ -7,7 +7,7 @@ jobs: prettier: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: actions/setup-node@v6 with: node-version-file: '.nvmrc' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5a9893530..d2903dd3f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ jobs: contents: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - uses: ./.github/actions/build-plugin diff --git a/.github/workflows/wpcs.yml b/.github/workflows/wpcs.yml index 755b720b4..d31045292 100644 --- a/.github/workflows/wpcs.yml +++ b/.github/workflows/wpcs.yml @@ -16,7 +16,7 @@ jobs: name: WPCS runs-on: ubuntu-latest steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 - name: Install dependencies run: composer install --prefer-dist --no-progress --ignore-platform-reqs - name: WPCS check diff --git a/.github/workflows/zip-pr.yml b/.github/workflows/zip-pr.yml index 271930dcb..40cde4f9a 100644 --- a/.github/workflows/zip-pr.yml +++ b/.github/workflows/zip-pr.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-24.04 steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 with: fetch-depth: 0 # Important for getting full commit history From af704b9cf18a16ece05d33d026153c2d26b5b8ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 21 Jun 2026 19:01:21 +0200 Subject: [PATCH 100/148] npm(deps-dev): bump @wordpress/env from 11.8.0 to 11.8.1 (#2236) Bumps [@wordpress/env](https://github.com/WordPress/gutenberg/tree/HEAD/packages/env) from 11.8.0 to 11.8.1. - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/env/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/v11.8.1/packages/env) --- updated-dependencies: - dependency-name: "@wordpress/env" dependency-version: 11.8.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 136 ++++++---------------------------------------- package.json | 2 +- 2 files changed, 18 insertions(+), 120 deletions(-) diff --git a/package-lock.json b/package-lock.json index fb9776306..e049d6de8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ }, "devDependencies": { "@babel/preset-env": "^7.29.7", - "@wordpress/env": "^11.8.0", + "@wordpress/env": "^11.8.1", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", "cypress": "^15.17.0", "editorconfig": "^3.0.2", @@ -5612,24 +5612,24 @@ } }, "node_modules/@wordpress/env": { - "version": "11.8.0", - "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-11.8.0.tgz", - "integrity": "sha512-VPsP81ID/XAuZn1DHDyApIeSx88WyKwwFhwc2u0RkGWzbYFB3xnkMBqx7ipFBS0TD79PLY5tcEgjMPU2R077pg==", + "version": "11.8.1", + "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-11.8.1.tgz", + "integrity": "sha512-wboYnQNPfMfcgYgiNDbrGGZj8RkdeZtaz2UvmAVUrhOgAvHFpZXsKuXuLdCCSv7JdcHGG5xLWMYhvRLTGOcQ1g==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { "@inquirer/prompts": "^7.2.0", "@wp-playground/cli": "^3.0.48", - "chalk": "^4.0.0", + "adm-zip": "^0.5.9", + "chalk": "^4.1.1", "copy-dir": "^1.3.0", "cross-spawn": "^7.0.6", "docker-compose": "^0.24.3", - "extract-zip": "^1.6.7", "got": "^11.8.5", "js-yaml": "^3.13.1", "ora": "^4.0.2", "rimraf": "^5.0.10", - "simple-git": "^3.5.0", + "simple-git": "^3.24.0", "yargs": "^17.3.0" }, "bin": { @@ -6222,6 +6222,16 @@ "node": ">= 0.6" } }, + "node_modules/adm-zip": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.17.tgz", + "integrity": "sha512-+Ut8d9LLqwEvHHJl1+PIHqoyDxFgVN847JTVM3Izi3xHDWPE4UtzzXysMZQs64DMcrJfBeS/uoEP4AD3HQHnQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0" + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -6954,15 +6964,6 @@ "ieee754": "^1.1.13" } }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/buffer-equal-constant-time": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", @@ -7577,21 +7578,6 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "engines": [ - "node >= 0.8" - ], - "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, "node_modules/console-browserify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", @@ -9030,36 +9016,6 @@ "node": ">=0.10.0" } }, - "node_modules/extract-zip": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", - "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", - "dev": true, - "dependencies": { - "concat-stream": "^1.6.2", - "debug": "^2.6.9", - "mkdirp": "^0.5.4", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - } - }, - "node_modules/extract-zip/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/extract-zip/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, "node_modules/extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", @@ -9108,15 +9064,6 @@ "node": ">=0.4.0" } }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, "node_modules/feiertagejs": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/feiertagejs/-/feiertagejs-1.5.1.tgz", @@ -13032,18 +12979,6 @@ "node": ">=0.10.0" } }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -14052,12 +13987,6 @@ "node": ">= 0.6.0" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, "node_modules/process-on-spawn": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", @@ -14203,21 +14132,6 @@ "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", "dev": true }, - "node_modules/readable-stream": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", - "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -18009,12 +17923,6 @@ "node": ">= 0.4" } }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", - "dev": true - }, "node_modules/typedarray-to-buffer": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", @@ -18939,16 +18847,6 @@ "node": ">=12" } }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "dependencies": { - "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", diff --git a/package.json b/package.json index 23342823f..5621af466 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "devDependencies": { "@babel/preset-env": "^7.29.7", - "@wordpress/env": "^11.8.0", + "@wordpress/env": "^11.8.1", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", "cypress": "^15.17.0", "editorconfig": "^3.0.2", From f64d8d0e6486eb833032fc46e86d4772a95a4854 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 00:42:00 +0200 Subject: [PATCH 101/148] npm(deps-dev): bump sass from 1.100.0 to 1.101.0 (#2223) Bumps [sass](https://github.com/sass/dart-sass) from 1.100.0 to 1.101.0. - [Release notes](https://github.com/sass/dart-sass/releases) - [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md) - [Commits](https://github.com/sass/dart-sass/compare/1.100.0...1.101.0) --- updated-dependencies: - dependency-name: sass dependency-version: 1.101.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index e049d6de8..ca62e7ef6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,7 @@ "matchdep": "^2.0.0", "medium-zoom": "^1.1.0", "prettier": "^3.8.3", - "sass": "^1.100.0", + "sass": "^1.101.0", "vitepress": "^1.6.4" } }, @@ -14505,9 +14505,9 @@ "dev": true }, "node_modules/sass": { - "version": "1.100.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.100.0.tgz", - "integrity": "sha512-B5j0rYMlinhhOo9tjQebMVVn0TfyXAF+wB3b2ggZUuJ/is/Y+7+JGjirAMxHZ9Z3hIP98NPfamlAkBHa1lAaXQ==", + "version": "1.101.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.101.0.tgz", + "integrity": "sha512-OL3GoQyoUdDt843DpVmDO6y2k1sc5IhUDSpu8XucEI+35neq5QivZ1iuegnpraEVTJXlQGK1gl27zKcTLEPbQw==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 5621af466..591953a45 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "grunt-dart-sass": "^2.0.1", "matchdep": "^2.0.0", "medium-zoom": "^1.1.0", - "sass": "^1.100.0", + "sass": "^1.101.0", "vitepress": "^1.6.4", "prettier": "^3.8.3" }, From ea97988de10b5b6624794427380a512e01879953 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 00:43:16 +0200 Subject: [PATCH 102/148] npm(deps): bump vue from 3.5.33 to 3.5.38 (#2222) Bumps [vue](https://github.com/vuejs/core) from 3.5.33 to 3.5.38. - [Release notes](https://github.com/vuejs/core/releases) - [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md) - [Commits](https://github.com/vuejs/core/compare/v3.5.33...v3.5.38) --- updated-dependencies: - dependency-name: vue dependency-version: 3.5.38 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 128 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/package-lock.json b/package-lock.json index ca62e7ef6..6a8b57937 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "select2": "^4.0.13", "shufflejs": "^6.1.1", "spin.js": "^2.3.2", - "vue": "^3.5.33" + "vue": "^3.5.38" }, "devDependencies": { "@babel/preset-env": "^7.29.7", @@ -5276,13 +5276,13 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.33.tgz", - "integrity": "sha512-3PZLQwFw4Za3TC8t0FvTy3wI16Kt+pmwcgNZca4Pj9iWL2E72a/gZlpBtAJvEdDMdCxdG/qq0C7PN0bsJuv0Rw==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.38.tgz", + "integrity": "sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.2", - "@vue/shared": "3.5.33", + "@babel/parser": "^7.29.7", + "@vue/shared": "3.5.38", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" @@ -5301,40 +5301,40 @@ } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.33.tgz", - "integrity": "sha512-PXq0yrfCLzzL07rbXO4awtXY1Z06LG2eu6Adg3RJFa/j3Cii217XxxLXG22N330gw7GmALCY0Z8RgXEviwgpjA==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.38.tgz", + "integrity": "sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.33", - "@vue/shared": "3.5.33" + "@vue/compiler-core": "3.5.38", + "@vue/shared": "3.5.38" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.33.tgz", - "integrity": "sha512-UTUvRO9cY+rROrx/pvN9P5Z7FgA6QGfokUCfhQE4EnmUj3rVnK+CHI0LsEO1pg+I7//iRYMUfcNcCPe7tg0CoA==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.38.tgz", + "integrity": "sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.2", - "@vue/compiler-core": "3.5.33", - "@vue/compiler-dom": "3.5.33", - "@vue/compiler-ssr": "3.5.33", - "@vue/shared": "3.5.33", + "@babel/parser": "^7.29.7", + "@vue/compiler-core": "3.5.38", + "@vue/compiler-dom": "3.5.38", + "@vue/compiler-ssr": "3.5.38", + "@vue/shared": "3.5.38", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", - "postcss": "^8.5.10", + "postcss": "^8.5.15", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.33.tgz", - "integrity": "sha512-IErjYdnj1qIupG5xxiVIYiiRvDhGWV4zuh/RCrwfYpuL+HWQzeU6lCk/nF9r7olWMnjKxCAkOctT2qFWFkzb1A==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.38.tgz", + "integrity": "sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.33", - "@vue/shared": "3.5.33" + "@vue/compiler-dom": "3.5.38", + "@vue/shared": "3.5.38" } }, "node_modules/@vue/devtools-api": { @@ -5371,53 +5371,53 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.33.tgz", - "integrity": "sha512-p8UfIqyIhb0rYGlSgSBV+lPhF2iUSBcRy7enhTmPqKWadHy9kcOFYF1AejYBP9P+avnd3OBbD49DU4pLWX/94A==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.38.tgz", + "integrity": "sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.33" + "@vue/shared": "3.5.38" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.33.tgz", - "integrity": "sha512-UpFF45RI9//a7rvq7RdOQblb4tup7hHG9QsmIrxkFQLzQ7R8/iNQ5LE15NhLZ1/WcHMU2b47u6P33CPUelHyIQ==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.38.tgz", + "integrity": "sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.33", - "@vue/shared": "3.5.33" + "@vue/reactivity": "3.5.38", + "@vue/shared": "3.5.38" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.33.tgz", - "integrity": "sha512-IOxMsAOwquhfITgmOgaPYl7/j8gKUxUFoflRc+u4LxyD3+783xne8vNta1PONVCvCV9A0w7hkyEepINDqfO0tw==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.38.tgz", + "integrity": "sha512-apX2wt9sdfDshS+a2xueFZLVpt0GkRJZSoPmrW/SA4yzXTznhfcMVW59gr7h4YQeY0vJhdJkk2rsIDwgfFgC5A==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.33", - "@vue/runtime-core": "3.5.33", - "@vue/shared": "3.5.33", + "@vue/reactivity": "3.5.38", + "@vue/runtime-core": "3.5.38", + "@vue/shared": "3.5.38", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.33.tgz", - "integrity": "sha512-0xylq/8/h44lVG0pZFknv1XIdEgymq2E9n59uTWJBG+dIgiT0TMCSsxrN7nO16Z0MU0MPjFcguBbZV8Itk52Hw==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.38.tgz", + "integrity": "sha512-vue8vbf2QlV4quHqzwmJy6dWfmRhP1J8l4wtZg60CL6VoKqcPY2oe7may3+1d9qfpedjK5PRLFqd5k3Isj9mUw==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.33", - "@vue/shared": "3.5.33" + "@vue/compiler-ssr": "3.5.38", + "@vue/shared": "3.5.38" }, "peerDependencies": { - "vue": "3.5.33" + "vue": "3.5.38" } }, "node_modules/@vue/shared": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.33.tgz", - "integrity": "sha512-5vR2QIlmaLG77Ygd4pMP6+SGQ5yox9VhtnbDWTy9DzMzdmeLxZ1QqxrywEZ9sa1AVubfIJyaCG3ytyWU81ufcQ==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.38.tgz", + "integrity": "sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==", "license": "MIT" }, "node_modules/@vueuse/core": { @@ -13010,9 +13010,9 @@ "optional": true }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", "funding": [ { "type": "github", @@ -13912,9 +13912,9 @@ } }, "node_modules/postcss": { - "version": "8.5.12", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.12.tgz", - "integrity": "sha512-W62t/Se6rA0Az3DfCL0AqJwXuKwBeYg6nOaIgzP+xZ7N5BFCI7DYi1qs6ygUYT6rvfi6t9k65UMLJC+PHZpDAA==", + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", "funding": [ { "type": "opencollective", @@ -13931,7 +13931,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -18529,16 +18529,16 @@ } }, "node_modules/vue": { - "version": "3.5.33", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.33.tgz", - "integrity": "sha512-1AgChhx5w3ALgT4oK3acm2Es/7jyZhWSVUfs3rOBlGQC0rjEDkS7G4lWlJJGGNQD+BV3reCwbQrOe1mPNwKHBQ==", + "version": "3.5.38", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.38.tgz", + "integrity": "sha512-vAMKHfImQlYSy0C+PBue4s3ERZ2xGKfgZg5GXAsLInq1dyh2H78ILVP5sK0KPFPVW4kv+OGCIvBEondcjpZp7A==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.33", - "@vue/compiler-sfc": "3.5.33", - "@vue/runtime-dom": "3.5.33", - "@vue/server-renderer": "3.5.33", - "@vue/shared": "3.5.33" + "@vue/compiler-dom": "3.5.38", + "@vue/compiler-sfc": "3.5.38", + "@vue/runtime-dom": "3.5.38", + "@vue/server-renderer": "3.5.38", + "@vue/shared": "3.5.38" }, "peerDependencies": { "typescript": "*" diff --git a/package.json b/package.json index 591953a45..073977d0d 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,6 @@ "select2": "^4.0.13", "shufflejs": "^6.1.1", "spin.js": "^2.3.2", - "vue": "^3.5.33" + "vue": "^3.5.38" } } From d38e9e3f9422757c704ec569a493c7264ad93502 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 00:55:15 +0200 Subject: [PATCH 103/148] npm(deps-dev): bump prettier from 3.8.3 to 3.8.4 (#2220) Bumps [prettier](https://github.com/prettier/prettier) from 3.8.3 to 3.8.4. - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/3.8.3...3.8.4) --- updated-dependencies: - dependency-name: prettier dependency-version: 3.8.4 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6a8b57937..cd4b2e524 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ "grunt-dart-sass": "^2.0.1", "matchdep": "^2.0.0", "medium-zoom": "^1.1.0", - "prettier": "^3.8.3", + "prettier": "^3.8.4", "sass": "^1.101.0", "vitepress": "^1.6.4" } @@ -13951,9 +13951,9 @@ } }, "node_modules/prettier": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", - "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", + "version": "3.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", + "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", "dev": true, "license": "MIT", "bin": { diff --git a/package.json b/package.json index 073977d0d..9a7d2c32b 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "medium-zoom": "^1.1.0", "sass": "^1.101.0", "vitepress": "^1.6.4", - "prettier": "^3.8.3" + "prettier": "^3.8.4" }, "scripts": { "start": "composer install --ignore-platform-reqs && npm install && npm run dist", From 0ee50c7970a9d7b0b3f568fc598191bfa76b1f01 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 00:55:38 +0200 Subject: [PATCH 104/148] npm(deps): bump select2 from 4.0.13 to 4.1.0 (#2212) Bumps [select2](https://github.com/select2/select2) from 4.0.13 to 4.1.0. - [Release notes](https://github.com/select2/select2/releases) - [Changelog](https://github.com/select2/select2/blob/develop/CHANGELOG.md) - [Commits](https://github.com/select2/select2/compare/4.0.13...4.1.0) --- updated-dependencies: - dependency-name: select2 dependency-version: 4.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 13 ++++++++----- package.json | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index cd4b2e524..8bfb02a77 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "leaflet.markercluster": "^1.5.0", "moment": "^2.19.4", "search-insights": "^2.17.3", - "select2": "^4.0.13", + "select2": "^4.1.0", "shufflejs": "^6.1.1", "spin.js": "^2.3.2", "vue": "^3.5.38" @@ -14572,10 +14572,13 @@ "license": "MIT" }, "node_modules/select2": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/select2/-/select2-4.0.13.tgz", - "integrity": "sha512-1JeB87s6oN/TDxQQYCvS5EFoQyvV6eYMZZ0AeA4tdFDYWN3BAGZ8npr17UBFddU0lgAt3H0yjX3X6/ekOj1yjw==", - "license": "MIT" + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/select2/-/select2-4.1.0.tgz", + "integrity": "sha512-i9KalWOP4/LRRGc8+rj2krNm0ZqP14cV+j1TRCEBSsOhCPkKH8rYZ2MCRXcgvqIqN+llqGci0hj9aVkCMvL0+g==", + "license": "MIT", + "engines": { + "node": ">=24" + } }, "node_modules/selfsigned": { "version": "5.5.0", diff --git a/package.json b/package.json index 9a7d2c32b..74bc6a9e6 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "leaflet.markercluster": "^1.5.0", "moment": "^2.19.4", "search-insights": "^2.17.3", - "select2": "^4.0.13", + "select2": "^4.1.0", "shufflejs": "^6.1.1", "spin.js": "^2.3.2", "vue": "^3.5.38" From 09f849a6a0e909f7f9b185f1f1bef5d2ba9ac49d Mon Sep 17 00:00:00 2001 From: Stefan Bomsdorf Date: Mon, 29 Jun 2026 15:28:38 +0200 Subject: [PATCH 105/148] Adds HTML decoding --- src/API/BaseRoute.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/API/BaseRoute.php b/src/API/BaseRoute.php index 5e13be79d..62d794abf 100644 --- a/src/API/BaseRoute.php +++ b/src/API/BaseRoute.php @@ -178,6 +178,21 @@ public function escapeJsonString( $string ) { return substr( wp_json_encode( $string ), 1, - 1 ) ? : ''; } + /** + * Decodes HTML entities in a post title for API output. + * + * WordPress stores post titles with encoded entities (e.g. "A&B"). + * Since the API returns plain text values that consumers render as text, + * we decode them so they receive "A&B" instead of "A&B". + * + * @param string $title + * + * @return string + */ + public function decodeTitle( string $title ): string { + return html_entity_decode( $title, ENT_QUOTES, 'UTF-8' ); + } + /** * Returns true if current request is allowed. * From ed3b7361a6a27dbd1be12ec540d46732c8f5083d Mon Sep 17 00:00:00 2001 From: Stefan Bomsdorf Date: Mon, 29 Jun 2026 15:28:50 +0200 Subject: [PATCH 106/148] Applies HTML decoding --- src/API/GBFS/StationInformation.php | 2 +- src/API/ItemsRoute.php | 2 +- src/API/LocationsRoute.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/API/GBFS/StationInformation.php b/src/API/GBFS/StationInformation.php index e3ea84ccc..656db5a14 100644 --- a/src/API/GBFS/StationInformation.php +++ b/src/API/GBFS/StationInformation.php @@ -38,7 +38,7 @@ public function prepare_item_for_response( $item, $request ): WP_REST_Response { $preparedItem->station_id = strval( $item->ID ); $preparedItem->name = [ (object) [ - 'text' => $item->post_title, + 'text' => $this->decodeTitle( $item->post_title ), 'language' => get_bloginfo( 'language' ), ], ]; diff --git a/src/API/ItemsRoute.php b/src/API/ItemsRoute.php index 99a4676bf..c9d7ee951 100644 --- a/src/API/ItemsRoute.php +++ b/src/API/ItemsRoute.php @@ -126,7 +126,7 @@ public function get_item( $request ): WP_REST_Response { public function prepare_item_for_response( $item, $request ): WP_REST_Response { $preparedItem = new stdClass(); $preparedItem->id = $item->ID . ''; - $preparedItem->name = $item->post_title; + $preparedItem->name = $this->decodeTitle( $item->post_title ); $preparedItem->url = get_permalink( $item->ID ); $preparedItem->description = $this->escapeJsonString( $item->post_content ); $preparedItem->ownerId = ''; // not implemented, but currently required by schema diff --git a/src/API/LocationsRoute.php b/src/API/LocationsRoute.php index c429278f0..eef4cfbe0 100644 --- a/src/API/LocationsRoute.php +++ b/src/API/LocationsRoute.php @@ -103,7 +103,7 @@ public function prepare_item_for_response( $item, $request ): WP_REST_Response { $preparedItem->properties = new stdClass(); $preparedItem->properties->id = $item->ID . ''; - $preparedItem->properties->name = $item->post_title; + $preparedItem->properties->name = $this->decodeTitle( $item->post_title ); $preparedItem->properties->description = $this->escapeJsonString( $item->post_content ); $preparedItem->properties->url = get_permalink( $item->ID ); $preparedItem->properties->address = $item->formattedAddressOneLine(); From e70584e6fe925be947cb3633d07c9543bbbfdec6 Mon Sep 17 00:00:00 2001 From: Stefan Bomsdorf Date: Mon, 29 Jun 2026 15:29:00 +0200 Subject: [PATCH 107/148] Tests HTML decoding --- .../API/GBFS/StationInformationRouteTest.php | 23 +++++++++++++++++++ tests/php/API/ItemsRouteTest.php | 15 ++++++++++++ tests/php/API/LocationsRouteTest.php | 15 ++++++++++++ 3 files changed, 53 insertions(+) diff --git a/tests/php/API/GBFS/StationInformationRouteTest.php b/tests/php/API/GBFS/StationInformationRouteTest.php index 465af31fd..cc370ec56 100644 --- a/tests/php/API/GBFS/StationInformationRouteTest.php +++ b/tests/php/API/GBFS/StationInformationRouteTest.php @@ -33,6 +33,29 @@ public function testBasicStationInformation_withLatLonMeta() { $this->assertEquals( 8.123, $station->lon ); } + public function testTitleHtmlEntitiesAreDecoded() { + update_post_meta( $this->locationId, 'geo_latitude', '50.123' ); + update_post_meta( $this->locationId, 'geo_longitude', '8.123' ); + + wp_update_post( + [ + 'ID' => $this->locationId, + 'post_title' => 'Station & Hof', + ] + ); + + // Sanity check: WordPress stores the title with the encoded entity. + $this->assertStringContainsString( '&', get_post( $this->locationId )->post_title ); + + $request = new WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + + $this->assertSame( 200, $response->get_status() ); + + $station = $response->get_data()->data->stations[0]; + $this->assertEquals( 'Station & Hof', $station->name[0]->text ); + } + // no gps data and no address defined, skip location public function testStationInformation_geocodingNonExistent() { delete_post_meta( $this->locationId, 'geo_latitude' ); diff --git a/tests/php/API/ItemsRouteTest.php b/tests/php/API/ItemsRouteTest.php index b4d6a644b..0ac069849 100644 --- a/tests/php/API/ItemsRouteTest.php +++ b/tests/php/API/ItemsRouteTest.php @@ -82,6 +82,21 @@ public function testSingleItem() { $this->assertEquals( (string) $this->itemId, $data->items[0]->id ); } + public function testTitleHtmlEntitiesAreDecoded() { + $entityItemId = $this->createItem( 'Bohrmaschine & Akkuschrauber', 'publish' ); + + // Sanity check: WordPress stores the title with the encoded entity. + $this->assertStringContainsString( '&', get_post( $entityItemId )->post_title ); + + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT . '/' . $entityItemId ); + $response = rest_do_request( $request ); + + $this->assertSame( 200, $response->get_status() ); + + $item = $response->get_data()->items[0]; + $this->assertEquals( 'Bohrmaschine & Akkuschrauber', $item->name ); + } + public function testExcludedIfBoxChecked() { update_post_meta( $this->itemId, COMMONSBOOKING_METABOX_PREFIX . 'api_exclude', 'on' ); $request = new \WP_REST_Request( 'GET', $this->ENDPOINT . '/' . $this->itemId ); diff --git a/tests/php/API/LocationsRouteTest.php b/tests/php/API/LocationsRouteTest.php index e0d53a7e1..6b3e83c45 100644 --- a/tests/php/API/LocationsRouteTest.php +++ b/tests/php/API/LocationsRouteTest.php @@ -58,6 +58,21 @@ public function testMultipleLocations() { $this->assertContains( (string) $secondId, $ids ); } + public function testTitleHtmlEntitiesAreDecoded() { + $entityLocationId = $this->createLocation( 'Markt & Mehr', 'publish', [] ); + + // Sanity check: WordPress stores the title with the encoded entity. + $this->assertStringContainsString( '&', get_post( $entityLocationId )->post_title ); + + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT . '/' . $entityLocationId ); + $response = rest_do_request( $request ); + + $this->assertSame( 200, $response->get_status() ); + + $feature = $response->get_data()->locations->features[0]; + $this->assertEquals( 'Markt & Mehr', $feature->properties->name ); + } + public function testEmptyLocations() { // Remove the location created in setUp wp_delete_post( array_pop( $this->locationIds ), true ); From 2f4bc1c3c8d10b5b65f0c2b8d86cd32efa2b0994 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Wed, 1 Jul 2026 08:08:14 +0200 Subject: [PATCH 108/148] fix #2229 GBFS vehicle_status.json now only contains actually available items --- src/API/GBFS/StationStatus.php | 2 +- src/API/GBFS/VehicleStatus.php | 31 +++++- src/Model/Calendar.php | 21 ++++ src/Model/Day.php | 23 ++++- src/Model/Item.php | 12 ++- tests/php/API/GBFS/StationStatusRouteTest.php | 15 +++ tests/php/API/GBFS/VehicleStatusRouteTest.php | 97 +++++++++++++++++-- tests/php/Model/ItemTest.php | 4 +- 8 files changed, 185 insertions(+), 20 deletions(-) diff --git a/src/API/GBFS/StationStatus.php b/src/API/GBFS/StationStatus.php index 3c38ffb08..6c0f8156e 100644 --- a/src/API/GBFS/StationStatus.php +++ b/src/API/GBFS/StationStatus.php @@ -35,7 +35,7 @@ public function prepare_item_for_response( $location, $request ): WP_REST_Respon $availableItems = count( array_filter( Item::getByLocation( $location->ID, true ), - fn( $item ) => $item->isCurrentlyFreeAtLocation( $location->ID ) && ! $item->getMeta( COMMONSBOOKING_METABOX_PREFIX . 'api_exclude' ) == 'on' + fn( $item ) => $item->isCurrentlyFreeAtLocation( $location->ID, true ) && $item->getMeta( COMMONSBOOKING_METABOX_PREFIX . 'api_exclude' ) != 'on' ) ); diff --git a/src/API/GBFS/VehicleStatus.php b/src/API/GBFS/VehicleStatus.php index 3374a3fdc..abc3cf867 100644 --- a/src/API/GBFS/VehicleStatus.php +++ b/src/API/GBFS/VehicleStatus.php @@ -2,11 +2,18 @@ namespace CommonsBooking\API\GBFS; +use CommonsBooking\Model\Day; +use CommonsBooking\Model\Location; +use CommonsBooking\Model\Restriction; use CommonsBooking\Repository\Item; use CommonsBooking\Repository\PostRepository; +use CommonsBooking\Wordpress\CustomPostType\Timeframe; use stdClass; use WP_REST_Response; +/** + * Describes all vehicles that are not currently in active rental. + */ class VehicleStatus extends BaseRoute { /** @@ -36,12 +43,17 @@ public function prepare_item_for_response( $item, $request ): WP_REST_Response { throw new \Exception( 'No location for item. (ID: ' . $item->ID . ')' ); } + // Vehicles that are part of an active rental MUST NOT appear in this feed + if ( ! $item->isCurrentlyFreeAtLocation( $location->ID, true, true ) ) { + throw new \Exception( 'Item currently not available (skipped in VehicleStatus) ' . '(ID: ' . $item->ID . ')' ); + } + $preparedItem = new stdClass(); $preparedItem->vehicle_id = strval( $item->getCloakedId() ); $preparedItem->vehicle_type_id = VehicleTypes::DEFAULT_NAME; $preparedItem->station_id = strval( $location->ID ); - $preparedItem->is_reserved = ! $item->isCurrentlyFreeAtLocation( intval( $preparedItem->station_id ) ); - $preparedItem->is_disabled = false; // This never happens, when the item is disabled it does not have a location and is therefore skipped + $preparedItem->is_reserved = false; // this never happens, we do not know the difference between the start of a booking period and if it has actually been picked up + $preparedItem->is_disabled = $this->isDisabled( $item, $location ); $preparedItem->rental_uris = (object) [ 'web' => $item->getCloakedURL(), ]; @@ -50,6 +62,21 @@ public function prepare_item_for_response( $item, $request ): WP_REST_Response { return new WP_REST_Response( $preparedItem ); } + private function isDisabled( \CommonsBooking\Model\Item $item, Location $location ): bool { + $today = new Day( date( 'Y-m-d', time() ), [ $location->ID ], [ $item->ID ], [ Timeframe::BOOKABLE_ID ] ); + $restrictions = $today->getRestrictions(); + $restrictions = array_filter( + $restrictions, + fn( $restriction ) => $restriction->isActive() && $restriction->getType() == Restriction::TYPE_REPAIR + ); + + if ( empty( $restrictions ) ) { + return false; + } else { + return true; + } + } + protected static function getListName(): string { return 'vehicles'; } diff --git a/src/Model/Calendar.php b/src/Model/Calendar.php index 713fa8505..ed33cf093 100644 --- a/src/Model/Calendar.php +++ b/src/Model/Calendar.php @@ -53,6 +53,19 @@ class Calendar { */ protected bool $ignoreStartDayOffset = false; + /** + * When this is enabled, restrictions are ignored when creating availabilities. + * This is useful when you want to differentiate between an item that is booked / not available + * and an item that would be bookable but is in repair. + * + * Just passed to the \CommonsBooking\Model\Day model, because restriction calculations are made there + * + * Used in @see \CommonsBooking\API\GBFS\VehicleStatus to differentiate between booked items and disabled items + * + * @var bool + */ + protected bool $ignoreRestrictions = false; + /** * Calendar constructor. * @@ -68,6 +81,9 @@ public function __construct( Day $startDate, Day $endDate, array $locations = [] throw new \InvalidArgumentException( 'Calendar must span at least two days' ); } + $startDate->setIgnoreRestrictions( $this->ignoreRestrictions ); + $endDate->setIgnoreRestrictions( $this->ignoreRestrictions ); + $this->startDate = $startDate; $this->endDate = $endDate; $this->items = $items; @@ -147,6 +163,7 @@ public function getAvailabilitySlots(): array { foreach ( $this->getWeeks() as $week ) { /** @var Day $day */ foreach ( $week->getDays() as $day ) { + $day->setIgnoreRestrictions( $this->ignoreRestrictions ); foreach ( $day->getGrid() as $slot ) { $timeframe = new Timeframe( $slot['timeframe'] ); $timeFrameType = get_post_meta( $slot['timeframe']->ID, 'type', true ); @@ -197,4 +214,8 @@ public function getAvailabilitySlots(): array { public function setIgnoreStartDayOffset( bool $ignoreStartDayOffset ): void { $this->ignoreStartDayOffset = $ignoreStartDayOffset; } + + public function setIgnoreRestrictions( bool $ignoreRestrictions ): void { + $this->ignoreRestrictions = $ignoreRestrictions; + } } diff --git a/src/Model/Day.php b/src/Model/Day.php index 72d0ec13f..4928b8e23 100644 --- a/src/Model/Day.php +++ b/src/Model/Day.php @@ -42,6 +42,17 @@ class Day { */ protected ?array $timeframes = null; + /** + * When this is enabled, restrictions are ignored when creating availabilities. + * This is useful when you want to differentiate between an item that is booked / not available + * and an item that would be bookable but is in repair. + * + * Used in @see \CommonsBooking\API\GBFS\VehicleStatus to differentiate between booked items and disabled items + * + * @var bool + */ + protected bool $ignoreRestrictions = false; + /** * Day constructor. * @@ -151,7 +162,7 @@ public function getTimeframes(): array { /** * Returns array with restrictions. * - * @return array + * @return Restriction[] * @throws Exception */ public function getRestrictions(): array { @@ -545,7 +556,7 @@ protected function removeEmptySlots( &$slots ) { * @throws Exception */ protected function getTimeframeSlots(): array { - $customCacheKey = $this->getDate() . serialize( $this->items ) . serialize( $this->locations ); + $customCacheKey = $this->getDate() . serialize( $this->items ) . serialize( $this->locations ) . serialize( $this->ignoreRestrictions ); $customCacheKey = md5( $customCacheKey ); $cacheItem = Plugin::getCacheItem( $customCacheKey ); if ( $cacheItem ) { @@ -566,7 +577,9 @@ protected function getTimeframeSlots(): array { } $this->mapTimeFrames( $slots ); - $this->mapRestrictions( $slots ); + if ( ! $this->ignoreRestrictions ) { + $this->mapRestrictions( $slots ); + } $this->sanitizeSlots( $slots ); Plugin::setCacheItem( @@ -602,4 +615,8 @@ protected function getSlotTimestampStart( $slotsPerDay, $slotNr ) { protected function getSlotTimestampEnd( $slotsPerDay, $slotNr ) { return strtotime( $this->getDate() ) + ( ( $slotNr + 1 ) * ( ( 24 / $slotsPerDay ) * 3600 ) ) - 1; } + + public function setIgnoreRestrictions( bool $ignoreRestrictions ): void { + $this->ignoreRestrictions = $ignoreRestrictions; + } } diff --git a/src/Model/Item.php b/src/Model/Item.php index 4957ad387..378a72eec 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -207,12 +207,13 @@ public function getLocation(): ?Location { * This method will include items that may only be booked in advance (\CommonsBooking\Model\Timeframe::META_TIMEFRAME_ADVANCE_BOOKING_DAYS), * because they are technically available at this location. Just not for pickup right now. * - * @param int $locationId - * + * @param int $locationId + * @param bool $ignoreStartDayOffset + * @param bool $ignoreRestrictions * @return bool true if the item is free right now, false otherwise - * @throws \Exception + * @throws Exception */ - public function isCurrentlyFreeAtLocation( int $locationId ): bool { + public function isCurrentlyFreeAtLocation( int $locationId, bool $ignoreStartDayOffset = false, bool $ignoreRestrictions = false ): bool { $nowDT = Wordpress::getUTCDateTimeByTimestamp( current_time( 'timestamp' ) ); $itemCalendar = new Calendar( new Day( date( 'Y-m-d', strtotime( '-1 day' ) ) ), @@ -220,7 +221,8 @@ public function isCurrentlyFreeAtLocation( int $locationId ): bool { [ $locationId ], [ $this->ID ] ); - $itemCalendar->setIgnoreStartDayOffset( true ); + $itemCalendar->setIgnoreStartDayOffset( $ignoreStartDayOffset ); + $itemCalendar->setIgnoreRestrictions( $ignoreRestrictions ); foreach ( $itemCalendar->getAvailabilitySlots() as $availabilitySlot ) { $startDT = new \DateTime( $availabilitySlot->start ); diff --git a/tests/php/API/GBFS/StationStatusRouteTest.php b/tests/php/API/GBFS/StationStatusRouteTest.php index 218172f52..6d59a174e 100644 --- a/tests/php/API/GBFS/StationStatusRouteTest.php +++ b/tests/php/API/GBFS/StationStatusRouteTest.php @@ -2,6 +2,7 @@ namespace CommonsBooking\Tests\API\GBFS; +use CommonsBooking\Model\Restriction; use CommonsBooking\Tests\API\CB_REST_Route_UnitTestCase; use CommonsBooking\Tests\Wordpress\CustomPostTypeTest; use SlopeIt\ClockMock\ClockMock; @@ -114,6 +115,20 @@ function ( $station ) use ( $otherLocationId ) { ); $this->assertEquals( 1, $relevantStation->num_vehicles_available ); } + public function testStationStatusWithRestriction() { + $this->createRestriction( + Restriction::TYPE_REPAIR, + $this->locationId, + $this->itemId, + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), + ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + $station = $data->stations[0]; + $this->assertEquals( 0, $station->num_vehicles_available ); + } public function testNotCountedWhenItemExcluded() { update_post_meta( $this->itemId, COMMONSBOOKING_METABOX_PREFIX . 'api_exclude', 'on' ); diff --git a/tests/php/API/GBFS/VehicleStatusRouteTest.php b/tests/php/API/GBFS/VehicleStatusRouteTest.php index 6dddda813..f75b67ee3 100644 --- a/tests/php/API/GBFS/VehicleStatusRouteTest.php +++ b/tests/php/API/GBFS/VehicleStatusRouteTest.php @@ -12,7 +12,7 @@ class VehicleStatusRouteTest extends CB_REST_Route_UnitTestCase { private $end; private $timeframe; - public function testIsReserved() { + public function testIsBooked() { $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); $response = rest_do_request( $request ); @@ -20,23 +20,22 @@ public function testIsReserved() { $data = $response->get_data()->data; - $this->assertFalse( $data->vehicles[0]->is_reserved ); + $this->assertCount( 1, $data->vehicles ); $this->createConfirmedBookingStartingToday(); $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); $response = rest_do_request( $request ); $this->assertSame( 200, $response->get_status() ); $data = $response->get_data()->data; - $this->assertTrue( $data->vehicles[0]->is_reserved ); + $this->assertEmpty( $data->vehicles ); } /** - * This does not test is_disabled for when there is no timeframe. - * This is, because there is no way for us to get a location for an item - * when there is no active timeframe. + * Item should not appear, when it is currently not available for rent. + * * @return void */ - public function testIsDisabled() { + public function testNoTimeframe() { // base case, not disabled $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); $response = rest_do_request( $request ); @@ -54,6 +53,90 @@ public function testIsDisabled() { $this->assertEmpty( $data->vehicles ); } + /** + * This field is used to indicate vehicles that are in the field but not available for rental due to a mechanical issue or low battery etc. + * Publishing this data may prevent users from attempting to rent vehicles that are disabled and not available for rental. + * This field SHOULD NOT be set to true when the system is closed for vehicles that would otherwise be rentable. + * + * In CB, this is handled through restrictions. When a total breakdown is present, the item is disabled. + * @return void + */ + public function testIsDisabled() { + // base case, not disabled + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertFalse( $data->vehicles[0]->is_disabled ); + + // restriction present: should not disappear from feed, but is considered disabled + $this->createRestriction( + \CommonsBooking\Model\Restriction::TYPE_REPAIR, + $this->locationId, + $this->itemId, + strtotime( self::CURRENT_DATE ), + strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ) + ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertCount( 1, $data->vehicles ); + $this->assertTrue( $data->vehicles[0]->is_disabled ); + } + + public function testIsDisabled_hint() { + // hints should not affect availability + $this->createRestriction( + \CommonsBooking\Model\Restriction::TYPE_HINT, + $this->locationId, + $this->itemId, + strtotime( self::CURRENT_DATE ), + strtotime( '+2 days', strtotime( self::CURRENT_DATE ) ) + ); + + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertFalse( $data->vehicles[0]->is_disabled ); + } + + public function testIsDisabled_inFuture() { + // restrictions in the future should not affect current state + $this->createRestriction( + \CommonsBooking\Model\Restriction::TYPE_REPAIR, + $this->locationId, + $this->itemId, + strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+2 days', strtotime( self::CURRENT_DATE ) ) + ); + + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertFalse( $data->vehicles[0]->is_disabled ); + } + + public function testIsDisabled_inactiveRestriction() { + // inactive restrictions should also not trigger + $this->createRestriction( + \CommonsBooking\Model\Restriction::TYPE_REPAIR, + $this->locationId, + $this->itemId, + strtotime( self::CURRENT_DATE ), + null, + \CommonsBooking\Model\Restriction::STATE_SOLVED + ); + + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $this->assertFalse( $data->vehicles[0]->is_disabled ); + } + public function testExclusion() { ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); update_post_meta( $this->itemId, COMMONSBOOKING_METABOX_PREFIX . 'api_exclude', 'on' ); diff --git a/tests/php/Model/ItemTest.php b/tests/php/Model/ItemTest.php index 6a07cfc70..67fda0616 100644 --- a/tests/php/Model/ItemTest.php +++ b/tests/php/Model/ItemTest.php @@ -266,11 +266,11 @@ public function testIsCurrentlyFreeAtLocation_withBookingOffset() { ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); // With offset → item is still free, it's just not possible to pick it up right now - $this->assertTrue( $otherItemModel->isCurrentlyFreeAtLocation( $otherLocationId ) ); + $this->assertTrue( $otherItemModel->isCurrentlyFreeAtLocation( $otherLocationId, true ) ); // Remove offset → still free, no change in rental status update_post_meta( $timeframeId, \CommonsBooking\Model\Timeframe::META_BOOKING_START_DAY_OFFSET, 0 ); - $this->assertTrue( $otherItemModel->isCurrentlyFreeAtLocation( $otherLocationId ) ); + $this->assertTrue( $otherItemModel->isCurrentlyFreeAtLocation( $otherLocationId, true ) ); } protected function setUp(): void { From 8d25e1867844c2ef862094487783c224660affbc Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Wed, 1 Jul 2026 08:08:29 +0200 Subject: [PATCH 109/148] fix prettier finding --- assets/public/js/src/lib/litepicker.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/assets/public/js/src/lib/litepicker.js b/assets/public/js/src/lib/litepicker.js index 64f0e754a..3d0a3a41c 100644 --- a/assets/public/js/src/lib/litepicker.js +++ b/assets/public/js/src/lib/litepicker.js @@ -247,7 +247,7 @@ ) t.styleSheet.cssText = o; else { - for (; t.firstChild; ) t.removeChild(t.firstChild); + for (; t.firstChild;) t.removeChild(t.firstChild); t.appendChild(document.createTextNode(o)); } } @@ -826,7 +826,7 @@ this.datePicked[0].getTime() < k.getTime() && u.push(k); } - for (; h > 0; ) { + for (; h > 0;) { ((h -= 1), (c = c.add(1, 'day'))); for (var D = 0, v = u; D < v.length; D++) v[D].getTime() === c.getTime() && @@ -1113,7 +1113,7 @@ if (/^-?\d{10,}$/.test(e)) return t.getDateZeroTime(new Date(Number(e))); if ('string' == typeof e) { - for (var n = [], s = null; null != (s = t.regex.exec(i)); ) + for (var n = [], s = null; null != (s = t.regex.exec(i));) '\\' !== s[1] && n.push(s); if (n.length) { var a = { @@ -1510,7 +1510,7 @@ }), (t.prototype.format = function (e, i) { void 0 === i && (i = 'en-US'); - for (var o = '', n = [], s = null; null != (s = t.regex.exec(e)); ) + for (var o = '', n = [], s = null; null != (s = t.regex.exec(e));) '\\' !== s[1] && n.push(s); if (n.length) { n[0].index > 0 && (o += e.substring(0, n[0].index)); From 1e800c008049c10fa0cdeeb274a49e1f8b7e78ac Mon Sep 17 00:00:00 2001 From: Stefan Bomsdorf Date: Wed, 1 Jul 2026 08:19:24 +0200 Subject: [PATCH 110/148] Decode HTML5 entities in API titles --- src/API/BaseRoute.php | 4 ++-- src/API/GBFS/StationInformation.php | 2 +- src/API/ItemsRoute.php | 2 +- src/API/LocationsRoute.php | 2 +- tests/php/API/ItemsRouteTest.php | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/API/BaseRoute.php b/src/API/BaseRoute.php index 62d794abf..72b19b380 100644 --- a/src/API/BaseRoute.php +++ b/src/API/BaseRoute.php @@ -189,8 +189,8 @@ public function escapeJsonString( $string ) { * * @return string */ - public function decodeTitle( string $title ): string { - return html_entity_decode( $title, ENT_QUOTES, 'UTF-8' ); + protected function decodeApiTitle( string $title ): string { + return html_entity_decode( $title, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'UTF-8' ); } /** diff --git a/src/API/GBFS/StationInformation.php b/src/API/GBFS/StationInformation.php index 656db5a14..a0ad9e46a 100644 --- a/src/API/GBFS/StationInformation.php +++ b/src/API/GBFS/StationInformation.php @@ -38,7 +38,7 @@ public function prepare_item_for_response( $item, $request ): WP_REST_Response { $preparedItem->station_id = strval( $item->ID ); $preparedItem->name = [ (object) [ - 'text' => $this->decodeTitle( $item->post_title ), + 'text' => $this->decodeApiTitle( $item->post_title ), 'language' => get_bloginfo( 'language' ), ], ]; diff --git a/src/API/ItemsRoute.php b/src/API/ItemsRoute.php index c9d7ee951..410732222 100644 --- a/src/API/ItemsRoute.php +++ b/src/API/ItemsRoute.php @@ -126,7 +126,7 @@ public function get_item( $request ): WP_REST_Response { public function prepare_item_for_response( $item, $request ): WP_REST_Response { $preparedItem = new stdClass(); $preparedItem->id = $item->ID . ''; - $preparedItem->name = $this->decodeTitle( $item->post_title ); + $preparedItem->name = $this->decodeApiTitle( $item->post_title ); $preparedItem->url = get_permalink( $item->ID ); $preparedItem->description = $this->escapeJsonString( $item->post_content ); $preparedItem->ownerId = ''; // not implemented, but currently required by schema diff --git a/src/API/LocationsRoute.php b/src/API/LocationsRoute.php index eef4cfbe0..688472706 100644 --- a/src/API/LocationsRoute.php +++ b/src/API/LocationsRoute.php @@ -103,7 +103,7 @@ public function prepare_item_for_response( $item, $request ): WP_REST_Response { $preparedItem->properties = new stdClass(); $preparedItem->properties->id = $item->ID . ''; - $preparedItem->properties->name = $this->decodeTitle( $item->post_title ); + $preparedItem->properties->name = $this->decodeApiTitle( $item->post_title ); $preparedItem->properties->description = $this->escapeJsonString( $item->post_content ); $preparedItem->properties->url = get_permalink( $item->ID ); $preparedItem->properties->address = $item->formattedAddressOneLine(); diff --git a/tests/php/API/ItemsRouteTest.php b/tests/php/API/ItemsRouteTest.php index 0ac069849..1287a3d18 100644 --- a/tests/php/API/ItemsRouteTest.php +++ b/tests/php/API/ItemsRouteTest.php @@ -83,7 +83,7 @@ public function testSingleItem() { } public function testTitleHtmlEntitiesAreDecoded() { - $entityItemId = $this->createItem( 'Bohrmaschine & Akkuschrauber', 'publish' ); + $entityItemId = $this->createItem( 'Bohrmaschine & Akkuschrauber 'Pro'', 'publish' ); // Sanity check: WordPress stores the title with the encoded entity. $this->assertStringContainsString( '&', get_post( $entityItemId )->post_title ); @@ -94,7 +94,7 @@ public function testTitleHtmlEntitiesAreDecoded() { $this->assertSame( 200, $response->get_status() ); $item = $response->get_data()->items[0]; - $this->assertEquals( 'Bohrmaschine & Akkuschrauber', $item->name ); + $this->assertEquals( 'Bohrmaschine & Akkuschrauber \'Pro\'', $item->name ); } public function testExcludedIfBoxChecked() { From 8cd5947428463051f0caf8f1adbc966aa9a4118b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2026 17:25:47 +0200 Subject: [PATCH 111/148] npm(deps-dev): bump @wordpress/env from 11.8.1 to 11.10.0 (#2247) Bumps [@wordpress/env](https://github.com/WordPress/gutenberg/tree/HEAD/packages/env) from 11.8.1 to 11.10.0. - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/env/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/env@11.10.0/packages/env) --- updated-dependencies: - dependency-name: "@wordpress/env" dependency-version: 11.10.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8bfb02a77..c7619e2a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ }, "devDependencies": { "@babel/preset-env": "^7.29.7", - "@wordpress/env": "^11.8.1", + "@wordpress/env": "^11.10.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", "cypress": "^15.17.0", "editorconfig": "^3.0.2", @@ -5612,9 +5612,9 @@ } }, "node_modules/@wordpress/env": { - "version": "11.8.1", - "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-11.8.1.tgz", - "integrity": "sha512-wboYnQNPfMfcgYgiNDbrGGZj8RkdeZtaz2UvmAVUrhOgAvHFpZXsKuXuLdCCSv7JdcHGG5xLWMYhvRLTGOcQ1g==", + "version": "11.10.0", + "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-11.10.0.tgz", + "integrity": "sha512-y0q2RLJ3PsWHrRPt7bQbJauF/23JvCkfjBHRefJlGDZ49x1ma+UYQCrhT07G/05CYYJH2Sw6qC3Q4XYBKe7ASA==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { diff --git a/package.json b/package.json index 74bc6a9e6..39eed42e9 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "devDependencies": { "@babel/preset-env": "^7.29.7", - "@wordpress/env": "^11.8.1", + "@wordpress/env": "^11.10.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", "cypress": "^15.17.0", "editorconfig": "^3.0.2", From a31022e8951309189d58e95219e989e893dd6257 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Mon, 6 Jul 2026 18:05:49 +0200 Subject: [PATCH 112/148] #2227 add gbfs vehicle_status available_until field (#2230) * GBFS: #2227 add available_until to vehicle_status.json * clanker fixes --- src/API/GBFS/VehicleStatus.php | 41 ++++++- src/Model/Item.php | 18 +-- tests/php/API/GBFS/VehicleStatusRouteTest.php | 112 +++++++++++++++++- tests/php/Model/ItemTest.php | 57 +++++++++ 4 files changed, 219 insertions(+), 9 deletions(-) diff --git a/src/API/GBFS/VehicleStatus.php b/src/API/GBFS/VehicleStatus.php index abc3cf867..4f385b7af 100644 --- a/src/API/GBFS/VehicleStatus.php +++ b/src/API/GBFS/VehicleStatus.php @@ -2,6 +2,7 @@ namespace CommonsBooking\API\GBFS; +use CommonsBooking\Model\Calendar; use CommonsBooking\Model\Day; use CommonsBooking\Model\Location; use CommonsBooking\Model\Restriction; @@ -39,6 +40,7 @@ class VehicleStatus extends BaseRoute { */ public function prepare_item_for_response( $item, $request ): WP_REST_Response { $location = $item->getLocation(); + if ( ! $location ) { throw new \Exception( 'No location for item. (ID: ' . $item->ID . ')' ); } @@ -57,7 +59,7 @@ public function prepare_item_for_response( $item, $request ): WP_REST_Response { $preparedItem->rental_uris = (object) [ 'web' => $item->getCloakedURL(), ]; - // $preparedItem->available_until //TODO: The date and time when any rental of the vehicle must be completed. The vehicle must be returned and made available for the next user by this time. If this field is empty, it indicates that the vehicle is available indefinitely. This field SHOULD be published by carsharing or other mobility systems where vehicles can be booked in advance for future travel. + $preparedItem->available_until = $this->getAvailableUntil( $item ); return new WP_REST_Response( $preparedItem ); } @@ -77,6 +79,43 @@ private function isDisabled( \CommonsBooking\Model\Item $item, Location $locatio } } + /** + * The date and time when any rental of the vehicle must be completed. + * The vehicle must be returned and made available for the next user by this time. + * If this field is empty, it indicates that the vehicle is available indefinitely. + * This field SHOULD be published by carsharing or other mobility systems where vehicles can be booked in advance for future travel. + * + * @param \CommonsBooking\Model\Item $item + * @return string in ISO 8601 notation + */ + private function getAvailableUntil( \CommonsBooking\Model\Item $item ): string { + $timeframe = $item->getClosestBookableTimeframe(); + $maxDays = $timeframe->getMaxDays() - 1; // WHY - 1: Counting from now, the amount of days an item is available includes the current day. So if we, for instance count three full days, the item is bookable today, tomorrow and the day after. Addind three days would put our pointer on the fourth day, where the item is not available anymore. Another option would have been to subtract 1 minute from the end timestamp. + $endDt = new \DateTime( '+' . $maxDays . ' day 23:59:59' ); + $itemCalendar = new Calendar( + new Day( date( 'Y-m-d', strtotime( '-1 day' ) ) ), + new Day( date( 'Y-m-d', strtotime( '+' . $maxDays . ' day' ) ) ), + [ $timeframe->getLocation()->ID ], + [ $item->ID ] + ); + $itemCalendar->setIgnoreStartDayOffset( true ); + + $availabilitySlots = $itemCalendar->getAvailabilitySlots(); + usort( + $availabilitySlots, + function ( $a, $b ) { + return new \DateTime( $a->end ) <=> new \DateTime( $b->end ); + } + ); + $availabilitySlots = array_filter( + $availabilitySlots, + fn( $availabilitySlot ) => new \DateTime( $availabilitySlot->end ) <= $endDt + ); + + $end = new \DateTime( array_pop( $availabilitySlots )->end ); + return $end->format( 'c' ); + } + protected static function getListName(): string { return 'vehicles'; } diff --git a/src/Model/Item.php b/src/Model/Item.php index 378a72eec..084be6bd1 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -177,16 +177,22 @@ function ( $a, $b ) { * @return ?Location will return null when no Location was found */ public function getLocation(): ?Location { + return $this->getClosestBookableTimeframe()?->getLocation();// why I used a deprecated method here: https://github.com/wielebenwir/commonsbooking/issues/507#issuecomment-4235848408 + } + + /** + * Will get the timeframe that is currently applicable for this item. + * When there are multiple timeframes, it wil select the closest. + * + * @return \CommonsBooking\Model\Timeframe|null + */ + public function getClosestBookableTimeframe(): ?\CommonsBooking\Model\Timeframe { $locations = \CommonsBooking\Repository\Location::getByItem( $this->ID, true ); if ( empty( $locations ) ) { return null; } - if ( count( $locations ) === 1 ) { - return reset( $locations ); - } - $timeframes = []; foreach ( $locations as $location ) { $timeframes = array_merge( @@ -194,9 +200,7 @@ public function getLocation(): ?Location { $location->getBookableTimeframesByItem( $this->ID, true ) ); } - $closestTimeframe = \CommonsBooking\View\Calendar::getClosestBookableTimeFrameForToday( $timeframes ); - - return $closestTimeframe?->getLocation();// why I used a deprecated method here: https://github.com/wielebenwir/commonsbooking/issues/507#issuecomment-4235848408 + return \CommonsBooking\View\Calendar::getClosestBookableTimeFrameForToday( $timeframes ); } /** diff --git a/tests/php/API/GBFS/VehicleStatusRouteTest.php b/tests/php/API/GBFS/VehicleStatusRouteTest.php index f75b67ee3..dedd9672a 100644 --- a/tests/php/API/GBFS/VehicleStatusRouteTest.php +++ b/tests/php/API/GBFS/VehicleStatusRouteTest.php @@ -3,6 +3,8 @@ namespace CommonsBooking\Tests\API\GBFS; use CommonsBooking\Tests\API\CB_REST_Route_UnitTestCase; +use CommonsBooking\Tests\Wordpress\CustomPostTypeTest; +use CommonsBooking\Wordpress\CustomPostType\Timeframe; use SlopeIt\ClockMock\ClockMock; class VehicleStatusRouteTest extends CB_REST_Route_UnitTestCase { @@ -147,6 +149,114 @@ public function testExclusion() { $this->assertEmpty( $data->vehicles ); } + public function testAvailableUntil_BaseCase() { + $rightNow = new \DateTime( self::CURRENT_DATE ); + ClockMock::freeze( $rightNow ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $inThreeDays = clone $rightNow; + $inThreeDays->modify( '+3 days' ); + $inThreeDays->modify( '-1 second' ); // because the item is only available exactly three days, not on the fourth + + $this->assertCount( 1, $data->vehicles ); + $this->assertSame( $inThreeDays->format( 'c' ), $data->vehicles[0]->available_until ); + } + + public function testAvailableUntil_hourlyBooking() { + // delete our original timeframe so we don't have multiple vehicles + wp_delete_post( $this->timeframe, true ); + + // create a timeframe with hourly availability and one day max booking + $this->createTimeframe( + $this->locationId, + $this->itemId, + strtotime( self::CURRENT_DATE ), + null, + Timeframe::BOOKABLE_ID, + 'off', + 'd', + 1, + '8:00 AM', + '5:00 PM', + 'publish', + [ '1', '2', '3', '4', '5', '6', '7' ], + '', + CustomPostTypeTest::USER_ID, + 1 + ); + + $rightNow = new \DateTime( self::CURRENT_DATE . ' 10:00 AM' ); + ClockMock::freeze( $rightNow ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $sameDayFivePM = clone $rightNow; + $sameDayFivePM->modify( '5:00 PM' ); + $sameDayFivePM->modify( '-1 second' ); + + $this->assertCount( 1, $data->vehicles ); + $this->assertSame( $sameDayFivePM->format( 'c' ), $data->vehicles[0]->available_until ); + } + + public function testAvailableUntil_slotBased() { + // delete our original timeframe so we don't have multiple vehicles + wp_delete_post( $this->timeframe, true ); + + // create a timeframe a slot based timeframe and one day max booking + $this->createTimeframe( + $this->locationId, + $this->itemId, + strtotime( self::CURRENT_DATE ), + null, + Timeframe::BOOKABLE_ID, + 'off', + 'd', + 0, + '8:00 AM', + '10:00 AM', + 'publish', + [ '1', '2', '3', '4', '5', '6', '7' ], + '', + CustomPostTypeTest::USER_ID, + 1 + ); + + // create another slot for the afternoon + $this->createTimeframe( + $this->locationId, + $this->itemId, + strtotime( self::CURRENT_DATE ), + null, + Timeframe::BOOKABLE_ID, + 'off', + 'd', + 0, + '1:00 PM', + '5:00 PM', + 'publish', + [ '1', '2', '3', '4', '5', '6', '7' ], + '', + CustomPostTypeTest::USER_ID, + 1 + ); + + $rightNow = new \DateTime( self::CURRENT_DATE . ' 9:00 AM' ); + ClockMock::freeze( $rightNow ); + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $this->assertSame( 200, $response->get_status() ); + $data = $response->get_data()->data; + $sameDayFivePM = clone $rightNow; + $sameDayFivePM->modify( '5:00 PM' ); + $sameDayFivePM->modify( '-1 second' ); + + $this->assertCount( 1, $data->vehicles ); + $this->assertSame( $sameDayFivePM->format( 'c' ), $data->vehicles[0]->available_until ); + } + public function setUp(): void { parent::setUp(); @@ -157,7 +267,7 @@ public function setUp(): void { $mocked = new \DateTimeImmutable( self::CURRENT_DATE ); $this->start = $mocked->modify( '-1 days' ); - $this->end = $mocked->modify( '+1 days' ); + $this->end = $mocked->modify( '+5 days' ); $this->timeframe = $this->createTimeframe( $this->locationId, diff --git a/tests/php/Model/ItemTest.php b/tests/php/Model/ItemTest.php index 67fda0616..e564cd5bd 100644 --- a/tests/php/Model/ItemTest.php +++ b/tests/php/Model/ItemTest.php @@ -273,6 +273,63 @@ public function testIsCurrentlyFreeAtLocation_withBookingOffset() { $this->assertTrue( $otherItemModel->isCurrentlyFreeAtLocation( $otherLocationId, true ) ); } + public function testGetClosestBookableTimeframe() { + $dt = new \DateTime( self::CURRENT_DATE ); + ClockMock::freeze( $dt ); + $this->assertEquals( $this->timeframeModel->ID, $this->itemModel->getClosestBookableTimeframe()->ID ); + // in two weeks, the timeframe is expired, so the item will not be at the location anymore + $dt->modify( '+2 weeks' ); + ClockMock::freeze( $dt ); + $this->assertNull( $this->itemModel->getClosestBookableTimeframe() ); + } + + public function testGetClosestBookableTimeframe_withBookingOffset() { + $otherLocationId = $this->createLocation( 'Other Location' ); + $otherItemId = $this->createItem( 'Other Item' ); + $otherItemModel = new Item( $otherItemId ); + + $timeframeId = $this->createTimeframe( + $otherLocationId, + $otherItemId, + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ), + \CommonsBooking\Wordpress\CustomPostType\Timeframe::BOOKABLE_ID, + 'on', + 'd', + 0, + '8:00 AM', + '12:00 PM', + 'publish', + [], + '', + CustomPostTypeTest::USER_ID, + 3, // booking start day offset + 30, + 2 + ); + + ClockMock::freeze( new \DateTime( self::CURRENT_DATE ) ); + + // should still show the timeframe as the closest + $this->assertEquals( $timeframeId, $otherItemModel->getClosestBookableTimeframe()->ID ); + } + + public function testGetClosestBookableTimeframe_withSlots() { + $otherLocationId = $this->createLocation( 'Other Location' ); + $otherItemId = $this->createItem( 'Other Item' ); + $timeframes = $this->createTwoBookableTimeframeSlotsIncludingCurrentDay( $otherLocationId, $otherItemId ); + $otherItemModel = new Item( $otherItemId ); + $dt = new \DateTime( self::CURRENT_DATE ); + ClockMock::freeze( $dt ); + + // even though it is not open yet (bc we have midnight), the first slot should be the closest + $this->assertEquals( $timeframes[0], $otherItemModel->getClosestBookableTimeframe()->ID ); + + // After 3PM, the other one should be picked + $dt->modify( '15:01' ); + ClockMock::freeze( $dt ); + $this->assertEquals( $timeframes[1], $otherItemModel->getClosestBookableTimeframe()->ID ); + } protected function setUp(): void { parent::setUp(); $this->restrictionIds[] = $this->createRestriction( From fb0c449c1eae1be541fdf4a7fc664d6780a956f1 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Mon, 6 Jul 2026 18:26:45 +0200 Subject: [PATCH 113/148] Revert "fix #2204: api routes could not be validated when api key was present" This reverts commit 617cef54a0461b91f6757c1c8ee4ec0feb36166d. --- src/API/GBFS/Discovery.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/API/GBFS/Discovery.php b/src/API/GBFS/Discovery.php index b5ff69270..0f923c88f 100644 --- a/src/API/GBFS/Discovery.php +++ b/src/API/GBFS/Discovery.php @@ -70,10 +70,6 @@ private function get_feed( $name ): stdClass { $feed = new stdClass(); $feed->name = $name; $feed->url = get_rest_url() . 'commonsbooking/v1/' . $name . '.json'; - $apiKey = array_key_exists( self::API_KEY_PARAM, $_REQUEST ) ? sanitize_text_field( $_REQUEST[ self::API_KEY_PARAM ] ) : false; - if ( $apiKey ) { - $feed->url .= '?apikey=' . $apiKey; - } return $feed; } } From ebf3a291d44da678bdea5e2877470607bd1d2d43 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Wed, 8 Jul 2026 10:41:32 +0200 Subject: [PATCH 114/148] #2251 support passing apikey by header --- src/API/BaseRoute.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/API/BaseRoute.php b/src/API/BaseRoute.php index 5e13be79d..2a6bdefa5 100644 --- a/src/API/BaseRoute.php +++ b/src/API/BaseRoute.php @@ -187,7 +187,12 @@ public static function hasPermission(): bool { $isApiActive = Settings::getOption( 'commonsbooking_options_api', 'api-activated' ); $anonymousAccessAllowed = Settings::getOption( 'commonsbooking_options_api', 'apikey_not_required' ); $apiKey = array_key_exists( self::API_KEY_PARAM, $_REQUEST ) ? sanitize_text_field( $_REQUEST[ self::API_KEY_PARAM ] ) : false; - $apiShare = ApiShares::getByKey( $apiKey ); + if ( ! $apiKey ) { + // get apikey from headers (#2251) + $allHeaders = array_change_key_case( getallheaders(), CASE_LOWER ); + $apiKey = array_key_exists( self::API_KEY_PARAM, $allHeaders ) ? sanitize_text_field( $allHeaders[ self::API_KEY_PARAM ] ) : false; + } + $apiShare = ApiShares::getByKey( $apiKey ); // Only if api is active we return something if ( $isApiActive ) { From 4ea14ab31d6c3fbed17545070fbb4161cb0e9c71 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Wed, 8 Jul 2026 11:00:28 +0200 Subject: [PATCH 115/148] #2251 make independent from existence of apache getallheaders fn --- src/API/BaseRoute.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/API/BaseRoute.php b/src/API/BaseRoute.php index 2a6bdefa5..f2ab20f75 100644 --- a/src/API/BaseRoute.php +++ b/src/API/BaseRoute.php @@ -189,8 +189,12 @@ public static function hasPermission(): bool { $apiKey = array_key_exists( self::API_KEY_PARAM, $_REQUEST ) ? sanitize_text_field( $_REQUEST[ self::API_KEY_PARAM ] ) : false; if ( ! $apiKey ) { // get apikey from headers (#2251) - $allHeaders = array_change_key_case( getallheaders(), CASE_LOWER ); - $apiKey = array_key_exists( self::API_KEY_PARAM, $allHeaders ) ? sanitize_text_field( $allHeaders[ self::API_KEY_PARAM ] ) : false; + if ( function_exists( 'getallheaders' ) ) { + $allHeaders = array_change_key_case( getallheaders(), CASE_LOWER ); + $apiKey = array_key_exists( self::API_KEY_PARAM, $allHeaders ) ? sanitize_text_field( $allHeaders[ self::API_KEY_PARAM ] ) : false; + } else { + $apiKey = array_key_exists( 'HTTP_' . strtoupper( self::API_KEY_PARAM ), $_SERVER ) ? sanitize_text_field( $_SERVER[ 'HTTP_' . strtoupper( self::API_KEY_PARAM ) ] ) : false; + } } $apiShare = ApiShares::getByKey( $apiKey ); From 2937dae369b3fea01781e3ef2206f84c39ebac01 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Jul 2026 11:53:32 +0200 Subject: [PATCH 116/148] npm(deps-dev): bump cypress from 15.17.0 to 15.18.0 (#2240) Bumps [cypress](https://github.com/cypress-io/cypress) from 15.17.0 to 15.18.0. - [Release notes](https://github.com/cypress-io/cypress/releases) - [Changelog](https://github.com/cypress-io/cypress/blob/develop/CHANGELOG.md) - [Commits](https://github.com/cypress-io/cypress/compare/v15.17.0...v15.18.0) --- updated-dependencies: - dependency-name: cypress dependency-version: 15.18.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index c7619e2a8..14d30577f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,7 @@ "@babel/preset-env": "^7.29.7", "@wordpress/env": "^11.10.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", - "cypress": "^15.17.0", + "cypress": "^15.18.0", "editorconfig": "^3.0.2", "grunt": "^1.6.2", "grunt-babel": "^8.0.0", @@ -7745,9 +7745,9 @@ "license": "MIT" }, "node_modules/cypress": { - "version": "15.17.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.17.0.tgz", - "integrity": "sha512-WL5Gcqi1GaDWozBwXmkSAtOPafTsVSRS764iX6xvuz3DPzvBAxbkRyEi4BreVdVWxLDpiYRgZCyJUafBw44njw==", + "version": "15.18.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.18.0.tgz", + "integrity": "sha512-aLfOYSLlVt1b6QSoVUjbCY27taZlYAT8ST47xQbwd9pvQrY/g5gXi12yItZTB+kxkkj+ZcvUYmRLUC95SlCJsw==", "dev": true, "hasInstallScript": true, "license": "MIT", diff --git a/package.json b/package.json index 39eed42e9..4974ed749 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "@babel/preset-env": "^7.29.7", "@wordpress/env": "^11.10.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", - "cypress": "^15.17.0", + "cypress": "^15.18.0", "editorconfig": "^3.0.2", "grunt": "^1.6.2", "grunt-babel": "^8.0.0", From d61f418e340143a48cc0d5854b1baf3c55b55ab4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Jul 2026 11:54:11 +0200 Subject: [PATCH 117/148] Bump actions/cache from 5 to 6 (#2237) Bumps [actions/cache](https://github.com/actions/cache) from 5 to 6. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/cache dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/e2e.yml | 2 +- .github/workflows/phpunit.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 8aa1c050c..d20a3abc9 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -83,7 +83,7 @@ jobs: path: gbfs-validator - name: Cache GBFS validator dependencies - uses: actions/cache@v5 + uses: actions/cache@v6 with: path: gbfs-validator/node_modules key: ${{ runner.os }}-gbfs-validator-${{ hashFiles('gbfs-validator/yarn.lock') }} diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 5a1cc20fa..442861e46 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -58,7 +58,7 @@ jobs: - name: Cache Composer packages id: composer-cache - uses: actions/cache@v5 + uses: actions/cache@v6 with: path: vendor key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} From b268ffaf8686bfa4a0af2cc2facbf79a44f5519b Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Wed, 8 Jul 2026 18:10:21 +0200 Subject: [PATCH 118/148] #2253 GBFS: tests for available_until incorrect when booking offset is set --- tests/php/API/GBFS/VehicleStatusRouteTest.php | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/tests/php/API/GBFS/VehicleStatusRouteTest.php b/tests/php/API/GBFS/VehicleStatusRouteTest.php index dedd9672a..7918b06a5 100644 --- a/tests/php/API/GBFS/VehicleStatusRouteTest.php +++ b/tests/php/API/GBFS/VehicleStatusRouteTest.php @@ -257,6 +257,48 @@ public function testAvailableUntil_slotBased() { $this->assertSame( $sameDayFivePM->format( 'c' ), $data->vehicles[0]->available_until ); } + public function testAvailableUntil_offset() { + // delete our original timeframe so we don't have multiple vehicles + wp_delete_post( $this->timeframe, true ); + + $rightNow = new \DateTime( self::CURRENT_DATE ); + ClockMock::freeze( $rightNow ); + $otherLocationId = $this->createLocation( 'Other Location', ); + $otherItemId = $this->createItem( 'Other Item', ); + + $timeframeID = $this->createTimeframe( + $otherLocationId, + $otherItemId, + strtotime( '-1 day', strtotime( self::CURRENT_DATE ) ), + strtotime( '+10 days', strtotime( self::CURRENT_DATE ) ), + \CommonsBooking\Wordpress\CustomPostType\Timeframe::BOOKABLE_ID, + 'on', + 'd', + 0, + '8:00 AM', + '12:00 PM', + 'publish', + [], + '', + CustomPostTypeTest::USER_ID, + 3, + 30, + 2 + ); + + // with offset - available until is extended to account for the offset + $availableUntil = clone $rightNow; + $availableUntil->modify( '+5 days' ); + $availableUntil->modify( '-1 second' ); + + $request = new \WP_REST_Request( 'GET', $this->ENDPOINT ); + $response = rest_do_request( $request ); + $data = $response->get_data()->data; + + $this->assertCount( 1, $data->vehicles ); + $this->assertSame( $availableUntil->format( 'c' ), $data->vehicles[0]->available_until ); + } + public function setUp(): void { parent::setUp(); From 10c6d69c459f637c88c99c25dea5ec2408176ee3 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Wed, 8 Jul 2026 18:28:17 +0200 Subject: [PATCH 119/148] #2253 GBFS: fix for available_until incorrect when booking offset is set --- src/API/GBFS/VehicleStatus.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/API/GBFS/VehicleStatus.php b/src/API/GBFS/VehicleStatus.php index 4f385b7af..c778d809f 100644 --- a/src/API/GBFS/VehicleStatus.php +++ b/src/API/GBFS/VehicleStatus.php @@ -89,12 +89,13 @@ private function isDisabled( \CommonsBooking\Model\Item $item, Location $locatio * @return string in ISO 8601 notation */ private function getAvailableUntil( \CommonsBooking\Model\Item $item ): string { - $timeframe = $item->getClosestBookableTimeframe(); - $maxDays = $timeframe->getMaxDays() - 1; // WHY - 1: Counting from now, the amount of days an item is available includes the current day. So if we, for instance count three full days, the item is bookable today, tomorrow and the day after. Addind three days would put our pointer on the fourth day, where the item is not available anymore. Another option would have been to subtract 1 minute from the end timestamp. - $endDt = new \DateTime( '+' . $maxDays . ' day 23:59:59' ); - $itemCalendar = new Calendar( + $timeframe = $item->getClosestBookableTimeframe(); + $maxDays = $timeframe->getMaxDays() - 1; // WHY - 1: Counting from now, the amount of days an item is available includes the current day. So if we, for instance count three full days, the item is bookable today, tomorrow and the day after. Addind three days would put our pointer on the fourth day, where the item is not available anymore. Another option would have been to subtract 1 minute from the end timestamp. + $endDt = new \DateTime( $timeframe->getFirstBookableDay() . ' +' . $maxDays . ' day 23:59:59' ); + $firstBookableDay = $timeframe->getFirstBookableDay(); + $itemCalendar = new Calendar( new Day( date( 'Y-m-d', strtotime( '-1 day' ) ) ), - new Day( date( 'Y-m-d', strtotime( '+' . $maxDays . ' day' ) ) ), + new Day( date( 'Y-m-d', strtotime( '+' . $maxDays . ' day', strtotime( $firstBookableDay ) ) ) ), [ $timeframe->getLocation()->ID ], [ $item->ID ] ); From 03011cfb8582550afec82a5a221f86de439e4559 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Wed, 8 Jul 2026 18:35:55 +0200 Subject: [PATCH 120/148] refactor getAvailableUntil to make it more readable --- src/API/GBFS/VehicleStatus.php | 37 +++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/API/GBFS/VehicleStatus.php b/src/API/GBFS/VehicleStatus.php index c778d809f..180357a75 100644 --- a/src/API/GBFS/VehicleStatus.php +++ b/src/API/GBFS/VehicleStatus.php @@ -89,32 +89,37 @@ private function isDisabled( \CommonsBooking\Model\Item $item, Location $locatio * @return string in ISO 8601 notation */ private function getAvailableUntil( \CommonsBooking\Model\Item $item ): string { - $timeframe = $item->getClosestBookableTimeframe(); - $maxDays = $timeframe->getMaxDays() - 1; // WHY - 1: Counting from now, the amount of days an item is available includes the current day. So if we, for instance count three full days, the item is bookable today, tomorrow and the day after. Addind three days would put our pointer on the fourth day, where the item is not available anymore. Another option would have been to subtract 1 minute from the end timestamp. - $endDt = new \DateTime( $timeframe->getFirstBookableDay() . ' +' . $maxDays . ' day 23:59:59' ); + $timeframe = $item->getClosestBookableTimeframe(); + + // Counting from the first bookable day (inclusive), maxDays of 3 means + // the item is bookable today, tomorrow, and the day after. Using + // maxDays as-is for the offset would incorrectly point to the fourth, + // unavailable day, so we subtract 1. + $maxDaysOffset = $timeframe->getMaxDays() - 1; $firstBookableDay = $timeframe->getFirstBookableDay(); - $itemCalendar = new Calendar( + $latestAllowedEnd = new \DateTime( $firstBookableDay . ' +' . $maxDaysOffset . ' day 23:59:59' ); + + $itemCalendar = new Calendar( new Day( date( 'Y-m-d', strtotime( '-1 day' ) ) ), - new Day( date( 'Y-m-d', strtotime( '+' . $maxDays . ' day', strtotime( $firstBookableDay ) ) ) ), + new Day( date( 'Y-m-d', strtotime( '+' . $maxDaysOffset . ' day', strtotime( $firstBookableDay ) ) ) ), [ $timeframe->getLocation()->ID ], [ $item->ID ] ); $itemCalendar->setIgnoreStartDayOffset( true ); - $availabilitySlots = $itemCalendar->getAvailabilitySlots(); - usort( - $availabilitySlots, - function ( $a, $b ) { - return new \DateTime( $a->end ) <=> new \DateTime( $b->end ); - } + $slotsInRange = array_filter( + $itemCalendar->getAvailabilitySlots(), + fn( $slot ) => new \DateTime( $slot->end ) <= $latestAllowedEnd ); - $availabilitySlots = array_filter( - $availabilitySlots, - fn( $availabilitySlot ) => new \DateTime( $availabilitySlot->end ) <= $endDt + + usort( + $slotsInRange, + fn( $a, $b ) => new \DateTime( $a->end ) <=> new \DateTime( $b->end ) ); - $end = new \DateTime( array_pop( $availabilitySlots )->end ); - return $end->format( 'c' ); + $lastSlot = array_pop( $slotsInRange ); + + return ( new \DateTime( $lastSlot->end ) )->format( 'c' ); } protected static function getListName(): string { From a2867776175865a60c880ffc019fd8cd6c1081ef Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Thu, 9 Jul 2026 14:55:52 +0200 Subject: [PATCH 121/148] bump version to 2.11 --- commonsbooking.php | 4 ++-- composer.json | 2 +- composer.lock | 2 +- docs/.vitepress/config.mts | 2 +- package.json | 2 +- readme.txt | 21 ++++++++++++++++++++- 6 files changed, 26 insertions(+), 7 deletions(-) diff --git a/commonsbooking.php b/commonsbooking.php index 6d9c4884e..a300ea23d 100644 --- a/commonsbooking.php +++ b/commonsbooking.php @@ -2,7 +2,7 @@ /** * Plugin Name: Commons Booking - * Version: 2.10.10 + * Version: 2.11 * Requires at least: 5.2 * Requires PHP: 8.1 * Plugin URI: https://commonsbooking.org @@ -16,7 +16,7 @@ */ defined( 'ABSPATH' ) || die( 'Thanks for visiting' ); -define( 'COMMONSBOOKING_VERSION', '2.10.10' ); +define( 'COMMONSBOOKING_VERSION', '2.11' ); 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' ); diff --git a/composer.json b/composer.json index ef863aa4d..3392478a0 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "wielebenwir/commonsbooking", "description": "~", "homepage": "https://commonsbooking.org", - "version": "2.10.10", + "version": "2.11", "type": "wordpress-plugin", "license": "GPL-2.0-or-later", "prefer-stable": true, diff --git a/composer.lock b/composer.lock index b12caf2cd..a4ebb91b9 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": "2faad4821957e84dda680c7d58ef1488", + "content-hash": "f799e9654eb730088e62c4f40e997bb4", "packages": [ { "name": "clue/stream-filter", diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index a1ae2fa7d..ab735d895 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -4,7 +4,7 @@ import { defineConfig, type DefaultTheme } from 'vitepress' const require = createRequire(import.meta.url) const pkg = require('../../package.json') -const COMMONSBOOKING_VERSION_STRING = '2.10.10'; +const COMMONSBOOKING_VERSION_STRING = '2.11'; // https://vitepress.dev/reference/site-config export default defineConfig({ diff --git a/package.json b/package.json index 4974ed749..5155c64d3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "commonsbooking", - "version": "2.10.10", + "version": "2.11", "description": "Wordpress plugin for managing and booking of common goods.", "author": "The CommonsBooking Team ", "license": "SEE LICENSE IN LICENSE.txt", diff --git a/readme.txt b/readme.txt index e5ff1b205..a015a70f2 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: 7.0 -Stable Tag: 2.10.10 +Stable Tag: 2.11 Requires PHP: 8.1 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -81,6 +81,25 @@ CommonsBooking was developed for the ["Commons Cargobike" movement](http://commo ## Changelog +### 2.11 (13.07.2026) +ADDED: GBFS routes vehicle_availability.json, vehicle_types.json, vehicle_status.json +ADDED: Multi-select now also available for timeframes of type repair +ADDED: Checkbox to exclude individual items from API shares +ADDED: Filter hook for external plugins to add additional GBFS feeds +ENHANCED: GBFS updated to version 3.1-RC3 +ENHANCED: iCalendar feed now differentiates between a users own bookings and other users bookings, using two different types of templates +ENHANCED: Better performance through pre-fetching timeframes for each item +ENHANCED: API Keys can now also be passed using HTTP headers (using apikey as key and the key as the value) +ENHANCED: GBFS system_id now uses human-readable format +FIXED: Admins could not cancel bookings of other users through frontend (thx @nelarsen) +FIXED: Fixed filter hook commonsbooking_isCurrentUserAdmin and changed to to commonsbooking_isUserAdmin (see documentation) +FIXED: Updated CMB2 to fix checkboxes breaking with WP 7.0 +FIXED: Users could delete already confirmed bookings (thx @poilu) +FIXED: GBFS availability of bikes had a timezone issue +FIXED: GBFS station_information syntax was incorrect +FIXED: Booking rule "Maximum of bookable days in time period" would not work for uneven amount of days +FIXED: Better compatibility with other plugins by dependency prefixing using Strauss (thx to @BrianHenryIE) + ### 2.10.10 (23.03.2026) FIXED: Two users booking same item possible when two users tried to book the same time period (thx @nelarsen) FIXED: Location specific sending of booking start / end reminder (for location owners) always sent email, not only when it is checked at location (thx @poilu) From 7d7721ff89bd81958445ccca4173dd73267e008f Mon Sep 17 00:00:00 2001 From: hansmorb Date: Thu, 9 Jul 2026 12:57:54 +0000 Subject: [PATCH 122/148] Ran wp i18n make-pot --- languages/commonsbooking.pot | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/languages/commonsbooking.pot b/languages/commonsbooking.pot index ccc305c2b..488291bb6 100644 --- a/languages/commonsbooking.pot +++ b/languages/commonsbooking.pot @@ -2,14 +2,14 @@ # This file is distributed under the GPL v2 or later. msgid "" msgstr "" -"Project-Id-Version: Commons Booking 2.10.10\n" +"Project-Id-Version: Commons Booking 2.11\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: 2026-06-17T13:53:30+00:00\n" +"POT-Creation-Date: 2026-07-09T12:57:50+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.12.0\n" "X-Domain: commonsbooking\n" From e7ac349445bdc0d38dbaf3670a587a40aab2c660 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Jul 2026 22:55:25 +0200 Subject: [PATCH 123/148] Merge pull request #2256 from wielebenwir/dependabot/npm_and_yarn/cypress-15.18.1 npm(deps-dev): bump cypress from 15.18.0 to 15.18.1 --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 14d30577f..ad17d1fbb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,7 @@ "@babel/preset-env": "^7.29.7", "@wordpress/env": "^11.10.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", - "cypress": "^15.18.0", + "cypress": "^15.18.1", "editorconfig": "^3.0.2", "grunt": "^1.6.2", "grunt-babel": "^8.0.0", @@ -7745,9 +7745,9 @@ "license": "MIT" }, "node_modules/cypress": { - "version": "15.18.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.18.0.tgz", - "integrity": "sha512-aLfOYSLlVt1b6QSoVUjbCY27taZlYAT8ST47xQbwd9pvQrY/g5gXi12yItZTB+kxkkj+ZcvUYmRLUC95SlCJsw==", + "version": "15.18.1", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.18.1.tgz", + "integrity": "sha512-JtkTVtUE2lvLYgZCaug+Uai0H9IqsJirlBO49c87QwG0bJUGvAUVBz1EJve0b0oaYP244Ew9M0BkrHpcqkYxmw==", "dev": true, "hasInstallScript": true, "license": "MIT", diff --git a/package.json b/package.json index 5155c64d3..7e7c6e742 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "@babel/preset-env": "^7.29.7", "@wordpress/env": "^11.10.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", - "cypress": "^15.18.0", + "cypress": "^15.18.1", "editorconfig": "^3.0.2", "grunt": "^1.6.2", "grunt-babel": "^8.0.0", From d848ef84ec4a7a44b14bca1cdf49e01a7899fb6b Mon Sep 17 00:00:00 2001 From: Dirk Drutschmann Date: Thu, 16 Jul 2026 19:59:45 +0200 Subject: [PATCH 124/148] Optimize restriction list column rendering --- src/Wordpress/CustomPostType/Restriction.php | 26 +++----------- .../RestrictionListColumnsTest.php | 36 +++++++++++++++++++ 2 files changed, 40 insertions(+), 22 deletions(-) create mode 100644 tests/php/Wordpress/CustomPostType/RestrictionListColumnsTest.php diff --git a/src/Wordpress/CustomPostType/Restriction.php b/src/Wordpress/CustomPostType/Restriction.php index 9996acd06..2ce2818e6 100644 --- a/src/Wordpress/CustomPostType/Restriction.php +++ b/src/Wordpress/CustomPostType/Restriction.php @@ -159,31 +159,13 @@ public function setCustomColumnsData( $column, $post_id ) { echo '-'; break; case \CommonsBooking\Model\Restriction::META_TYPE: - $output = '-'; - - foreach ( $this->getCustomFields() as $customField ) { - if ( $customField['id'] == \CommonsBooking\Model\Restriction::META_TYPE ) { - foreach ( $customField['options'] as $key => $label ) { - if ( $value == $key ) { - $output = $label; - } - } - } - } + $types = self::getTypes(); + $output = $types[ $value ] ?? '-'; echo commonsbooking_sanitizeHTML( $output ); break; case \CommonsBooking\Model\Restriction::META_STATE: - $output = '-'; - - foreach ( $this->getCustomFields() as $customField ) { - if ( $customField['id'] == \CommonsBooking\Model\Restriction::META_STATE ) { - foreach ( $customField['options'] as $key => $label ) { - if ( $value == $key ) { - $output = $label; - } - } - } - } + $states = self::getStates(); + $output = $states[ $value ] ?? '-'; echo commonsbooking_sanitizeHTML( $output ); break; case \CommonsBooking\Model\Restriction::META_START: diff --git a/tests/php/Wordpress/CustomPostType/RestrictionListColumnsTest.php b/tests/php/Wordpress/CustomPostType/RestrictionListColumnsTest.php new file mode 100644 index 000000000..011b0b360 --- /dev/null +++ b/tests/php/Wordpress/CustomPostType/RestrictionListColumnsTest.php @@ -0,0 +1,36 @@ +createRestriction( + Restriction::TYPE_HINT, + $this->locationId, + $this->itemId, + strtotime( self::CURRENT_DATE ), + strtotime( '+1 day', strtotime( self::CURRENT_DATE ) ) + ); + $postType = new class() extends RestrictionPostType { + protected function getCustomFields(): array { + throw new \RuntimeException( 'List columns must not build assignment options.' ); + } + }; + + ob_start(); + $postType->setCustomColumnsData( Restriction::META_TYPE, $restrictionId ); + $typeOutput = ob_get_clean(); + + ob_start(); + $postType->setCustomColumnsData( Restriction::META_STATE, $restrictionId ); + $stateOutput = ob_get_clean(); + + $this->assertSame( RestrictionPostType::getTypes()[ Restriction::TYPE_HINT ], $typeOutput ); + $this->assertSame( RestrictionPostType::getStates()[ Restriction::STATE_ACTIVE ], $stateOutput ); + } +} From 3539eb756d988b2904178ca89f09e78423cf8c94 Mon Sep 17 00:00:00 2001 From: Dirk Drutschmann Date: Fri, 17 Jul 2026 15:08:48 +0200 Subject: [PATCH 125/148] Add rationale to restriction list regression test --- .../php/Wordpress/CustomPostType/RestrictionListColumnsTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/php/Wordpress/CustomPostType/RestrictionListColumnsTest.php b/tests/php/Wordpress/CustomPostType/RestrictionListColumnsTest.php index 011b0b360..be699d2d0 100644 --- a/tests/php/Wordpress/CustomPostType/RestrictionListColumnsTest.php +++ b/tests/php/Wordpress/CustomPostType/RestrictionListColumnsTest.php @@ -18,6 +18,8 @@ public function testListColumnsDoNotBuildAssignmentOptions(): void { ); $postType = new class() extends RestrictionPostType { protected function getCustomFields(): array { + // Regression guard: getCustomFields() loads dynamic location and item options, + // so calling it for static type/state columns degrades list rendering performance. throw new \RuntimeException( 'List columns must not build assignment options.' ); } }; From 3acb62e52061219de2407c4c10dca8388fd259e3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 7 Jun 2026 15:52:48 +0000 Subject: [PATCH 126/148] composer(deps-dev): bump phpstan/phpstan from 2.2.1 to 2.2.2 --- updated-dependencies: - dependency-name: phpstan/phpstan dependency-version: 2.2.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.lock b/composer.lock index a4ebb91b9..10d95e474 100644 --- a/composer.lock +++ b/composer.lock @@ -3749,11 +3749,11 @@ }, { "name": "phpstan/phpstan", - "version": "2.2.1", + "version": "2.2.2", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/dea9c8f2d25cc849391042b71e429c1a4bf82660", - "reference": "dea9c8f2d25cc849391042b71e429c1a4bf82660", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e5cc34d491a90e79c216d824f60fe21fd4d93bd6", + "reference": "e5cc34d491a90e79c216d824f60fe21fd4d93bd6", "shasum": "" }, "require": { @@ -3809,7 +3809,7 @@ "type": "github" } ], - "time": "2026-05-28T14:44:12+00:00" + "time": "2026-06-05T09:00:01+00:00" }, { "name": "phpunit/php-code-coverage", From 7acda734aa6b49c28603a7a8ce6f4cc1ad78a202 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 4 Jul 2026 14:10:53 +0200 Subject: [PATCH 127/148] phpstan: fix if-else-ifelse construct that leads to phpstan exhausting its typespace Before a new version of phpstan (introduced in pr #2208) would exhaust its typespace on the if-else construction we had placed here. Now the if-else construction is split into (maybe also more readable) indented blocks per condition. --- src/Model/Timeframe.php | 51 +++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/src/Model/Timeframe.php b/src/Model/Timeframe.php index 734bbba34..79ad2c5e0 100644 --- a/src/Model/Timeframe.php +++ b/src/Model/Timeframe.php @@ -316,42 +316,43 @@ public function getLatestPossibleBookingDateTimestamp() { * This is used to display the end date of the timeframe in the frontend. * This is mainly in use by the [cb_items] shortcode. * - * @param int $startDate - * @param int $endDate + * @param int $startDate + * @param int|false $endDate false when timeframe is open ended * * @return string */ - public static function formatBookableDate( int $startDate, int $endDate ): string { + public static function formatBookableDate( int $startDate, $endDate ): string { $format = self::getDateFormat(); $today = strtotime( 'now' ); $startDateFormatted = date_i18n( $format, $startDate ); - $endDateFormatted = date_i18n( $format, $endDate ); + $endDateFormatted = $endDate !== false ? date_i18n( $format, $endDate ) : ''; $label = commonsbooking_sanitizeHTML( __( 'Available here', 'commonsbooking' ) ); $availableString = ''; - if ( $startDate && $endDate && $startDate === $endDate ) { // available only one day - /* translators: %s = date in WordPress defined format */ - $availableString = sprintf( commonsbooking_sanitizeHTML( __( 'on %s', 'commonsbooking' ) ), $startDateFormatted ); - } elseif ( $startDate && ! $endDate ) { // start but no end date - if ( $startDate > $today ) { // start is in the future - $availableString = sprintf( - /* translators: %s = date in WordPress defined format */ - commonsbooking_sanitizeHTML( __( 'from %s', 'commonsbooking' ) ), - $startDateFormatted - ); - } else { // start has passed, no end date, probably a fixed location - $availableString = commonsbooking_sanitizeHTML( __( 'permanently', 'commonsbooking' ) ); - } - } elseif ( $startDate && $endDate ) { // start AND end date - if ( $startDate > $today ) { // start is in the future, with an end date - $availableString = sprintf( - /* translators: %1$s = startdate, second %2$s = enddate in WordPress defined format */ - commonsbooking_sanitizeHTML( __( 'from %1$s until %2$s', 'commonsbooking' ) ), - $startDateFormatted, - $endDateFormatted - ); + if ( $startDate !== 0 ) { + if ( $endDate === false ) { // start but no end date + if ( $startDate > $today ) { // start is in the future + $availableString = sprintf( + /* translators: %s = date in WordPress defined format */ + commonsbooking_sanitizeHTML( __( 'from %s', 'commonsbooking' ) ), + $startDateFormatted + ); + } else { // start has passed, no end date, probably a fixed location + $availableString = commonsbooking_sanitizeHTML( __( 'permanently', 'commonsbooking' ) ); + } + } elseif ( $startDate === $endDate ) { // available only one day + /* translators: %s = date in WordPress defined format */ + $availableString = sprintf( commonsbooking_sanitizeHTML( __( 'on %s', 'commonsbooking' ) ), $startDateFormatted ); + } elseif ( $startDate > $today ) { // start AND end date + // start is in the future, with an end date + $availableString = sprintf( + /* translators: %1$s = startdate, second %2$s = enddate in WordPress defined format */ + commonsbooking_sanitizeHTML( __( 'from %1$s until %2$s', 'commonsbooking' ) ), + $startDateFormatted, + $endDateFormatted + ); } else { // start has passed, with an end date $availableString = sprintf( /* translators: %s = enddate in WordPress defined format */ From ab55db336ab45600bddeccc799dcb24a83e92722 Mon Sep 17 00:00:00 2001 From: datengraben Date: Sat, 18 Jul 2026 08:20:32 +0000 Subject: [PATCH 128/148] Ran wp i18n make-pot --- languages/commonsbooking-de_DE.po | 42 ++++++++++++++--------------- languages/commonsbooking.pot | 44 +++++++++++++++---------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/languages/commonsbooking-de_DE.po b/languages/commonsbooking-de_DE.po index 1aa95cf0f..44baa27bf 100644 --- a/languages/commonsbooking-de_DE.po +++ b/languages/commonsbooking-de_DE.po @@ -1190,45 +1190,45 @@ msgstr "Hier verfügbar" #. translators: %s = date in WordPress defined format #: src/Model/Booking.php:437 -#: src/Model/Timeframe.php:336 +#: src/Model/Timeframe.php:347 #, php-format msgid "on %s" msgstr "am %s" #. translators: %s = date in WordPress defined format -#: src/Model/Timeframe.php:341 +#: src/Model/Timeframe.php:339 #, php-format msgid "from %s" msgstr "von %s" -#: src/Model/Timeframe.php:345 +#: src/Model/Timeframe.php:343 msgid "permanently" msgstr "dauerhaft" #. translators: %1 = startdate, %2 = enddate in WordPress defined format #. translators: %1$s = startdate, second %2$s = enddate in WordPress defined format #: src/Model/Booking.php:440 -#: src/Model/Timeframe.php:351 +#: src/Model/Timeframe.php:352 #, php-format msgid "from %1$s until %2$s" msgstr "von %1$s bis %2$s" #. translators: %s = enddate in WordPress defined format -#: src/Model/Timeframe.php:358 +#: src/Model/Timeframe.php:359 #, php-format msgid "until %s" msgstr "bis %s" -#: src/Model/Timeframe.php:686 +#: src/Model/Timeframe.php:687 msgid "A pickup time but no return time has been set. Please set the return time." msgstr "Eine Abholzeit, aber keine Rückgabezeit wurde festgelegt. Lege bitte eine Rückgabezeit fest." -#: src/Model/Timeframe.php:696 +#: src/Model/Timeframe.php:697 msgid "End date is before start date. Please set a valid end date." msgstr "Enddatum liegt vor dem Startdatum. Bitte setze ein gültiges Enddatum." #. translators: %1$s = timeframe-ID, %2$s is timeframe post_title -#: src/Model/Timeframe.php:731 +#: src/Model/Timeframe.php:732 #, php-format msgid "Item is already bookable at another location within the same date range. See other timeframe ID: %1$s: %2$s" msgstr "Artikel ist bereits an einem anderen Ort innerhalb desselben Datumsbereichs buchbar. Siehe andere Zeitrahmen ID: %1$s: %2$s" @@ -3025,7 +3025,7 @@ msgstr "Es ist nicht möglich, diesen Zeitrahmen im Frontend abzurufen. Bitte be msgid "Cancelled" msgstr "Storniert" -#: src/Model/Timeframe.php:706 +#: src/Model/Timeframe.php:707 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." @@ -3110,25 +3110,25 @@ msgid "If selected, days that are overbooked will be counted towards the maximum msgstr "Ist diese Option aktiviert, werden überbuchte Tage auf die maximale Anzahl buchbarer Tage angerechnet. Wenn diese Option deaktiviert ist, dann werden überbuchte Tage nicht zusätzlich gezählt und ermöglichen Buchungszeiträume die länger sind als die im Zeitrahmen konfigurierte maximale Anzahl an gebuchten Tagen." #. translators: first %s = timeframe-ID, second %s is timeframe post_title -#: src/Model/Timeframe.php:767 +#: src/Model/Timeframe.php:768 #, php-format msgid "See overlapping timeframe ID: %1$s %2$s" msgstr "Sich überschneidende Zeitrahmen ID: %1$s %2$s" -#: src/Model/Timeframe.php:866 +#: src/Model/Timeframe.php:867 msgid "Overlapping bookable timeframes are only allowed to have the same grid." msgstr "Sich überschneidende buchbare Zeiträume müssen das gleiche Raster haben." -#: src/Model/Timeframe.php:896 +#: src/Model/Timeframe.php:897 msgid "Overlapping bookable timeframes are not allowed to have the same weekdays." msgstr "Mehrere buchbare Zeiträume überschneiden sich in den definierten Wochentagen." -#: src/Model/Timeframe.php:908 +#: src/Model/Timeframe.php:909 msgid "Overlapping bookable timeframes are not allowed to have the same dates." msgstr "Mehrere buchbare Zeiträume überschneiden sich in dem definierten Datumsbereich." -#: src/Model/Timeframe.php:915 -#: src/Model/Timeframe.php:922 +#: src/Model/Timeframe.php:916 +#: src/Model/Timeframe.php:923 msgid "The other timeframe is overlapping with your weekly configuration." msgstr "Der andere Zeitrahmen überschneidet sich mit einer wöchentlichen Konfiguration." @@ -3168,7 +3168,7 @@ msgstr "Feiertage importieren" msgid "Select the year and state to import holidays for (as of now only German holidays are supported)" msgstr "Wählen Sie das Jahr und das Bundesland, für das Sie Feiertage importieren möchten (derzeit werden Feiertage in Deutschland unterstützt)" -#: src/Model/Timeframe.php:882 +#: src/Model/Timeframe.php:883 msgid "Daily repeated time periods are not allowed to overlap." msgstr "Täglich wiederholende Zeiträume dürfen sich nicht überschneiden." @@ -3867,23 +3867,23 @@ msgstr "Bitte passe das Start- oder Enddatum an." msgid "Affected Bookings: %s" msgstr "Betroffene Buchungen: %s" -#: src/Model/Timeframe.php:631 +#: src/Model/Timeframe.php:632 msgid "Could not get item or location. Please set a valid item and location." msgstr "Artikel oder Standort konnte nicht gefunden werden. Bitte wähle einen gültigen Artikel oder Standort." -#: src/Model/Timeframe.php:640 +#: src/Model/Timeframe.php:641 msgid "Item or location is missing. Please set item and location." msgstr "Artikel oder Standort fehlen. Bitte Artikel und Standort festlegen." -#: src/Model/Timeframe.php:653 +#: src/Model/Timeframe.php:654 msgid "No dates selected. Please select at least one date." msgstr "Kein Datum ausgewählt. Bitte mindestens ein Datum auswählen." -#: src/Model/Timeframe.php:663 +#: src/Model/Timeframe.php:664 msgid "The same date was selected multiple times. Please select each date only once." msgstr "Das gleiche Datum wurde mehrere Male ausgewählt. Bitte ein Datum nur einmal auswählen." -#: src/Model/Timeframe.php:672 +#: src/Model/Timeframe.php:673 msgid "Startdate is missing. Please enter a start date to publish this timeframe." msgstr "Das Startdatum fehlt. Ein Startdatum muss eingegeben werden, damit der Zeitrahmen veröffentlicht werden kann." diff --git a/languages/commonsbooking.pot b/languages/commonsbooking.pot index 488291bb6..8ea745181 100644 --- a/languages/commonsbooking.pot +++ b/languages/commonsbooking.pot @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2026-07-09T12:57:50+00:00\n" +"POT-Creation-Date: 2026-07-18T08:20:28+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.12.0\n" "X-Domain: commonsbooking\n" @@ -1476,7 +1476,7 @@ msgstr "" #. translators: %s = date in WordPress defined format #: src/Model/Booking.php:437 -#: src/Model/Timeframe.php:336 +#: src/Model/Timeframe.php:347 #, php-format msgid "on %s" msgstr "" @@ -1484,7 +1484,7 @@ msgstr "" #. translators: %1 = startdate, %2 = enddate in WordPress defined format #. translators: %1$s = startdate, second %2$s = enddate in WordPress defined format #: src/Model/Booking.php:440 -#: src/Model/Timeframe.php:351 +#: src/Model/Timeframe.php:352 #, php-format msgid "from %1$s until %2$s" msgstr "" @@ -1569,83 +1569,83 @@ msgid "Available here" msgstr "" #. translators: %s = date in WordPress defined format -#: src/Model/Timeframe.php:341 +#: src/Model/Timeframe.php:339 #, php-format msgid "from %s" msgstr "" -#: src/Model/Timeframe.php:345 +#: src/Model/Timeframe.php:343 msgid "permanently" msgstr "" #. translators: %s = enddate in WordPress defined format -#: src/Model/Timeframe.php:358 +#: src/Model/Timeframe.php:359 #, php-format msgid "until %s" msgstr "" -#: src/Model/Timeframe.php:631 +#: src/Model/Timeframe.php:632 msgid "Could not get item or location. Please set a valid item and location." msgstr "" -#: src/Model/Timeframe.php:640 +#: src/Model/Timeframe.php:641 msgid "Item or location is missing. Please set item and location." msgstr "" -#: src/Model/Timeframe.php:653 +#: src/Model/Timeframe.php:654 msgid "No dates selected. Please select at least one date." msgstr "" -#: src/Model/Timeframe.php:663 +#: src/Model/Timeframe.php:664 msgid "The same date was selected multiple times. Please select each date only once." msgstr "" -#: src/Model/Timeframe.php:672 +#: src/Model/Timeframe.php:673 msgid "Startdate is missing. Please enter a start date to publish this timeframe." msgstr "" -#: src/Model/Timeframe.php:686 +#: src/Model/Timeframe.php:687 msgid "A pickup time but no return time has been set. Please set the return time." msgstr "" -#: src/Model/Timeframe.php:696 +#: src/Model/Timeframe.php:697 msgid "End date is before start date. Please set a valid end date." msgstr "" -#: src/Model/Timeframe.php:706 +#: src/Model/Timeframe.php:707 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 "" #. translators: %1$s = timeframe-ID, %2$s is timeframe post_title -#: src/Model/Timeframe.php:731 +#: src/Model/Timeframe.php:732 #, php-format msgid "Item is already bookable at another location within the same date range. See other timeframe ID: %1$s: %2$s" msgstr "" #. translators: first %s = timeframe-ID, second %s is timeframe post_title -#: src/Model/Timeframe.php:767 +#: src/Model/Timeframe.php:768 #, php-format msgid "See overlapping timeframe ID: %1$s %2$s" msgstr "" -#: src/Model/Timeframe.php:866 +#: src/Model/Timeframe.php:867 msgid "Overlapping bookable timeframes are only allowed to have the same grid." msgstr "" -#: src/Model/Timeframe.php:882 +#: src/Model/Timeframe.php:883 msgid "Daily repeated time periods are not allowed to overlap." msgstr "" -#: src/Model/Timeframe.php:896 +#: src/Model/Timeframe.php:897 msgid "Overlapping bookable timeframes are not allowed to have the same weekdays." msgstr "" -#: src/Model/Timeframe.php:908 +#: src/Model/Timeframe.php:909 msgid "Overlapping bookable timeframes are not allowed to have the same dates." msgstr "" -#: src/Model/Timeframe.php:915 -#: src/Model/Timeframe.php:922 +#: src/Model/Timeframe.php:916 +#: src/Model/Timeframe.php:923 msgid "The other timeframe is overlapping with your weekly configuration." msgstr "" From 924fee026ecaa6d7b42127249614849b33b1d5e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 28 Jun 2026 15:52:33 +0000 Subject: [PATCH 129/148] composer(deps): bump symfony/service-contracts from 3.7.0 to 3.7.1 Bumps [symfony/service-contracts](https://github.com/symfony/service-contracts) from 3.7.0 to 3.7.1. - [Release notes](https://github.com/symfony/service-contracts/releases) - [Changelog](https://github.com/symfony/service-contracts/blob/main/CHANGELOG.md) - [Commits](https://github.com/symfony/service-contracts/compare/v3.7.0...v3.7.1) --- updated-dependencies: - dependency-name: symfony/service-contracts dependency-version: 3.7.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/composer.lock b/composer.lock index 10d95e474..6dc25b136 100644 --- a/composer.lock +++ b/composer.lock @@ -1629,16 +1629,16 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v3.7.0", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b" + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/50f59d1f3ca46d41ac911f97a78626b6756af35b", - "reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/f3202fa1b5097b0af062dc978b32ecf63404e31d", + "reference": "f3202fa1b5097b0af062dc978b32ecf63404e31d", "shasum": "" }, "require": { @@ -1676,7 +1676,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.0" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.1" }, "funding": [ { @@ -1696,7 +1696,7 @@ "type": "tidelift" } ], - "time": "2026-04-13T15:52:40+00:00" + "time": "2026-06-05T06:23:12+00:00" }, { "name": "symfony/http-client", @@ -2191,16 +2191,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.7.0", + "version": "v3.7.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a" + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d25d82433a80eba6aa0e6c24b61d7370d99e444a", - "reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/c0a284bab1ed8aa0417e3d69250ab437739563a0", + "reference": "c0a284bab1ed8aa0417e3d69250ab437739563a0", "shasum": "" }, "require": { @@ -2254,7 +2254,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.7.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.7.1" }, "funding": [ { @@ -2274,7 +2274,7 @@ "type": "tidelift" } ], - "time": "2026-03-28T09:44:51+00:00" + "time": "2026-06-16T09:55:08+00:00" }, { "name": "symfony/var-exporter", From 7660f6063c9fe6f719b8f676f8b628c185c80263 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 12 Jul 2026 15:53:13 +0000 Subject: [PATCH 130/148] npm(deps-dev): bump prettier from 3.8.4 to 3.9.5 Bumps [prettier](https://github.com/prettier/prettier) from 3.8.4 to 3.9.5. - [Release notes](https://github.com/prettier/prettier/releases) - [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md) - [Commits](https://github.com/prettier/prettier/compare/3.8.4...3.9.5) --- updated-dependencies: - dependency-name: prettier dependency-version: 3.9.5 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index ad17d1fbb..b752472e0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ "grunt-dart-sass": "^2.0.1", "matchdep": "^2.0.0", "medium-zoom": "^1.1.0", - "prettier": "^3.8.4", + "prettier": "^3.9.5", "sass": "^1.101.0", "vitepress": "^1.6.4" } @@ -13951,9 +13951,9 @@ } }, "node_modules/prettier": { - "version": "3.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.4.tgz", - "integrity": "sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==", + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.5.tgz", + "integrity": "sha512-/FVl766LpUfB5vXgCYOYa0MeV/441Ia99AeICQIQFTY/Nw0roZwULcXpku5i1/m5kt/baz+s4Zogspd839HSMg==", "dev": true, "license": "MIT", "bin": { diff --git a/package.json b/package.json index 7e7c6e742..79ef1cd74 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "medium-zoom": "^1.1.0", "sass": "^1.101.0", "vitepress": "^1.6.4", - "prettier": "^3.8.4" + "prettier": "^3.9.5" }, "scripts": { "start": "composer install --ignore-platform-reqs && npm install && npm run dist", From 572d5066fafd7801c97a4d57ab07275d914ec736 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 18 Jul 2026 19:51:43 +0000 Subject: [PATCH 131/148] npm(deps-dev): bump fast-xml-parser from 5.3.6 to 5.10.1 Bumps [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) from 5.3.6 to 5.10.1. - [Release notes](https://github.com/NaturalIntelligence/fast-xml-parser/releases) - [Changelog](https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md) - [Commits](https://github.com/NaturalIntelligence/fast-xml-parser/compare/v5.3.6...v5.10.1) --- updated-dependencies: - dependency-name: fast-xml-parser dependency-version: 5.7.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 116 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 106 insertions(+), 10 deletions(-) diff --git a/package-lock.json b/package-lock.json index b752472e0..cb638ae42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "commonsbooking", - "version": "2.10.10", + "version": "2.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "commonsbooking", - "version": "2.10.10", + "version": "2.11", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@commonsbooking/frontend": "^0.1.0-beta.7", @@ -2912,6 +2912,19 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@nodable/entities": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-3.0.0.tgz", + "integrity": "sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/nodable" + } + ], + "license": "MIT" + }, "node_modules/@octokit/app": { "version": "14.1.0", "resolved": "https://registry.npmjs.org/@octokit/app/-/app-14.1.0.tgz", @@ -6335,6 +6348,19 @@ "node": ">= 8" } }, + "node_modules/anynum": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/anynum/-/anynum-1.0.1.tgz", + "integrity": "sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, "node_modules/append-transform": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", @@ -9033,10 +9059,27 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-xml-builder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.3.0.tgz", + "integrity": "sha512-F74cZEdCvuw9P41GAC3rod4X04jjWGM1JPEv/GWSqFTWLsdyMSBMBMlm9Hk3GLBgLBbdBNY8yee0pQh2RBVESQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "path-expression-matcher": "^1.6.2", + "xml-naming": "^0.3.0" + } + }, "node_modules/fast-xml-parser": { - "version": "5.3.6", - "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.3.6.tgz", - "integrity": "sha512-QNI3sAvSvaOiaMl8FYU4trnEzCwiRr8XMWgAHzlrWpTSj+QaCSvOf1h82OEP1s4hiAXhnbXSyFWCf4ldZzZRVA==", + "version": "5.10.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.10.1.tgz", + "integrity": "sha512-IEMIf7298kXuZSRFoGfMYrl7is8LpavODgbNz1cwIudv7KwVFnuU+UsMporfq6PD6aXSlawZlARiA3UywCTfMw==", "dev": true, "funding": [ { @@ -9046,7 +9089,12 @@ ], "license": "MIT", "dependencies": { - "strnum": "^2.1.2" + "@nodable/entities": "^3.0.0", + "fast-xml-builder": "^1.2.0", + "is-unsafe": "^2.0.0", + "path-expression-matcher": "^1.6.2", + "strnum": "^2.4.1", + "xml-naming": "^0.3.0" }, "bin": { "fxparser": "src/cli/cli.js" @@ -11191,6 +11239,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-unsafe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-unsafe/-/is-unsafe-2.0.0.tgz", + "integrity": "sha512-2LdV822R+wmI86unXA93WCFpL6g+av8ynWk0nrHyJqGop5VoocYsSLFgN8jrfalT6iGeLNM4KXuVSsULP53kEA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT" + }, "node_modules/is-what": { "version": "4.1.16", "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz", @@ -13734,6 +13795,22 @@ "node": ">=8" } }, + "node_modules/path-expression-matcher": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.6.2.tgz", + "integrity": "sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -15465,9 +15542,9 @@ } }, "node_modules/strnum": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.1.2.tgz", - "integrity": "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-2.4.1.tgz", + "integrity": "sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg==", "dev": true, "funding": [ { @@ -15475,7 +15552,10 @@ "url": "https://github.com/sponsors/NaturalIntelligence" } ], - "license": "MIT" + "license": "MIT", + "dependencies": { + "anynum": "^1.0.1" + } }, "node_modules/superjson": { "version": "2.2.2", @@ -18775,6 +18855,22 @@ } } }, + "node_modules/xml-naming": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.3.0.tgz", + "integrity": "sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/xml2js": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz", From f5140bc9c0c66b55105c4c33074e8a8e22620e1b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 08:57:16 +0000 Subject: [PATCH 132/148] npm(deps): bump qs and @wp-playground/cli Bumps [qs](https://github.com/ljharb/qs) and [@wp-playground/cli](https://github.com/WordPress/wordpress-playground). These dependencies needed to be updated together. Updates `qs` from 6.14.2 to 6.15.3 - [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md) - [Commits](https://github.com/ljharb/qs/compare/v6.14.2...v6.15.3) Updates `@wp-playground/cli` from 3.0.52 to 3.1.45 - [Release notes](https://github.com/WordPress/wordpress-playground/releases) - [Changelog](https://github.com/WordPress/wordpress-playground/blob/trunk/CHANGELOG.md) - [Commits](https://github.com/WordPress/wordpress-playground/compare/v3.0.52...v3.1.45) --- updated-dependencies: - dependency-name: "@wp-playground/cli" dependency-version: 3.1.44 dependency-type: indirect - dependency-name: qs dependency-version: 6.15.3 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 1841 +++++++++++---------------------------------- 1 file changed, 454 insertions(+), 1387 deletions(-) diff --git a/package-lock.json b/package-lock.json index cb638ae42..6216164be 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1884,22 +1884,6 @@ "node": ">= 14.17.0" } }, - "node_modules/@cypress/request/node_modules/qs": { - "version": "6.15.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", - "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/@cypress/xvfb": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", @@ -2899,19 +2883,6 @@ "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", "dev": true }, - "node_modules/@noble/hashes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", - "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@nodable/entities": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-3.0.0.tgz", @@ -3810,819 +3781,235 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@peculiar/asn1-cms": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.6.1.tgz", - "integrity": "sha512-vdG4fBF6Lkirkcl53q6eOdn3XYKt+kJTG59edgRZORlg/3atWWEReRCx5rYE1ZzTTX6vLK5zDMjHh7vbrcXGtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", - "@peculiar/asn1-x509-attr": "^2.6.1", - "asn1js": "^3.0.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-csr": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.6.1.tgz", - "integrity": "sha512-WRWnKfIocHyzFYQTka8O/tXCiBquAPSrRjXbOkHbO4qdmS6loffCEGs+rby6WxxGdJCuunnhS2duHURhjyio6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", - "asn1js": "^3.0.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-ecc": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.6.1.tgz", - "integrity": "sha512-+Vqw8WFxrtDIN5ehUdvlN2m73exS2JVG0UAyfVB31gIfor3zWEAQPD+K9ydCxaj3MLen9k0JhKpu9LqviuCE1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", - "asn1js": "^3.0.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-pfx": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.6.1.tgz", - "integrity": "sha512-nB5jVQy3MAAWvq0KY0R2JUZG8bO/bTLpnwyOzXyEh/e54ynGTatAR+csOnXkkVD9AFZ2uL8Z7EV918+qB1qDvw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-cms": "^2.6.1", - "@peculiar/asn1-pkcs8": "^2.6.1", - "@peculiar/asn1-rsa": "^2.6.1", - "@peculiar/asn1-schema": "^2.6.0", - "asn1js": "^3.0.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-pkcs8": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.6.1.tgz", - "integrity": "sha512-JB5iQ9Izn5yGMw3ZG4Nw3Xn/hb/G38GYF3lf7WmJb8JZUydhVGEjK/ZlFSWhnlB7K/4oqEs8HnfFIKklhR58Tw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", - "asn1js": "^3.0.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-pkcs9": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.6.1.tgz", - "integrity": "sha512-5EV8nZoMSxeWmcxWmmcolg22ojZRgJg+Y9MX2fnE2bGRo5KQLqV5IL9kdSQDZxlHz95tHvIq9F//bvL1OeNILw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-cms": "^2.6.1", - "@peculiar/asn1-pfx": "^2.6.1", - "@peculiar/asn1-pkcs8": "^2.6.1", - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", - "@peculiar/asn1-x509-attr": "^2.6.1", - "asn1js": "^3.0.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-rsa": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.6.1.tgz", - "integrity": "sha512-1nVMEh46SElUt5CB3RUTV4EG/z7iYc7EoaDY5ECwganibQPkZ/Y2eMsTKB/LeyrUJ+W/tKoD9WUqIy8vB+CEdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", - "asn1js": "^3.0.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-schema": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.6.0.tgz", - "integrity": "sha512-xNLYLBFTBKkCzEZIw842BxytQQATQv+lDTCEMZ8C196iJcJJMBUZxrhSTxLaohMyKK8QlzRNTRkUmanucnDSqg==", - "dev": true, - "license": "MIT", - "dependencies": { - "asn1js": "^3.0.6", - "pvtsutils": "^1.3.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-x509": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.6.1.tgz", - "integrity": "sha512-O9jT5F1A2+t3r7C4VT7LYGXqkGLK7Kj1xFpz7U0isPrubwU5PbDoyYtx6MiGst29yq7pXN5vZbQFKRCP+lLZlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "asn1js": "^3.0.6", - "pvtsutils": "^1.3.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/asn1-x509-attr": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.6.1.tgz", - "integrity": "sha512-tlW6cxoHwgcQghnJwv3YS+9OO1737zgPogZ+CgWRUK4roEwIPzRH4JEiG770xe5HX2ATfCpmX60gurfWIF9dcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.1", - "asn1js": "^3.0.6", - "tslib": "^2.8.1" - } - }, - "node_modules/@peculiar/x509": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz", - "integrity": "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/asn1-cms": "^2.6.0", - "@peculiar/asn1-csr": "^2.6.0", - "@peculiar/asn1-ecc": "^2.6.0", - "@peculiar/asn1-pkcs9": "^2.6.0", - "@peculiar/asn1-rsa": "^2.6.0", - "@peculiar/asn1-schema": "^2.6.0", - "@peculiar/asn1-x509": "^2.6.0", - "pvtsutils": "^1.3.6", - "reflect-metadata": "^0.2.2", - "tslib": "^2.8.1", - "tsyringe": "^4.10.0" - }, - "engines": { - "node": ">=20.0.0" - } - }, "node_modules/@php-wasm/cli-util": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/cli-util/-/cli-util-3.0.52.tgz", - "integrity": "sha512-znW/+lDWIqlCxe4vhaNuT7Cw3PkTwCFZ0raiivjvYtlHmQc0nSKGMY+8gH3bBkpxEnjXrR0RSmU2UuzQFUM5JA==", + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/cli-util/-/cli-util-3.1.45.tgz", + "integrity": "sha512-+ht22B6KPUsn5ORtApE5xYq+uIb7/Qv/NSOxYgNGSWf3O1rpxkbOMeCxtE7H3dvazJIlSF+/nsVHpHkcTZGOpA==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/util": "3.0.52", - "fast-xml-parser": "^5.3.4", + "@php-wasm/util": "3.1.45", + "fast-xml-parser": "^5.8.0", "jsonc-parser": "3.3.1" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/fs-journal": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/fs-journal/-/fs-journal-3.0.52.tgz", - "integrity": "sha512-OaG1VAIvG2c/7IXfM4Q7tSETq116kXsf+EPzqtWev4oNGU/fMlAEDByRmHC7DYI4Da0tT9YwpVYPiByj4zae1g==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/logger": "3.0.52", - "@php-wasm/node": "3.0.52", - "@php-wasm/universal": "3.0.52", - "@php-wasm/util": "3.0.52", - "express": "4.22.0", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3", - "yargs": "17.7.2" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/fs-journal/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, "node_modules/@php-wasm/logger": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/logger/-/logger-3.0.52.tgz", - "integrity": "sha512-9NlGe5sV0SC1Zb6UfuNJ4XO3HT9pr0NKjv5PRAHlaF2yNCJ3T6O+LCGJiaojWjs2nKqw293LMeHEKFEwe+Pfgg==", + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/logger/-/logger-3.1.45.tgz", + "integrity": "sha512-FYWGxaRZTM+aiRQ6/LlnFAdsixJ7VWQpM8Fe/61yWgpBamb1w3NEDRhYVR5DNjYWJVI5ha6pVxIsHtw018iA7g==", "dev": true, "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/node-polyfills": "3.0.52" - }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, "node_modules/@php-wasm/node": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/node/-/node-3.0.52.tgz", - "integrity": "sha512-V+ds3PtPrzuSCDHnrDahZdTZbGXynLH1SEH+dSny1taF9WDyp/7Gc73s3E/pCn/8iAB6kSut25dpc1gkzmktOQ==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/logger": "3.0.52", - "@php-wasm/node-7-4": "3.0.52", - "@php-wasm/node-8-0": "3.0.52", - "@php-wasm/node-8-1": "3.0.52", - "@php-wasm/node-8-2": "3.0.52", - "@php-wasm/node-8-3": "3.0.52", - "@php-wasm/node-8-4": "3.0.52", - "@php-wasm/node-8-5": "3.0.52", - "@php-wasm/node-polyfills": "3.0.52", - "@php-wasm/universal": "3.0.52", - "@php-wasm/util": "3.0.52", - "@wp-playground/common": "3.0.52", - "express": "4.22.0", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3", - "yargs": "17.7.2" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/node-7-4": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/node-7-4/-/node-7-4-3.0.52.tgz", - "integrity": "sha512-P30l0/lleRLnhob9p3L3o4h2EDH76Fd9fQ+fFvGH8N3aYaNJysug3lKR6hnbQzTQab/xU2JFFUg5Faw3cJfT1w==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/node-7-4/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@php-wasm/node-8-0": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/node-8-0/-/node-8-0-3.0.52.tgz", - "integrity": "sha512-sm3zsGyGDLd6+b5/VsMxfHJvaREOlYcqPI7WqyrieQCVAg5IckQzeYdVpbQjMhfiAHRprSqyvEV6bz+iQCFiwg==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/node-8-0/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@php-wasm/node-8-1": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/node-8-1/-/node-8-1-3.0.52.tgz", - "integrity": "sha512-6jnMLEsGH6JNHst52Wv9/UHEL5BJb+IOhMW4cG+OwcaqHb5cXq16j9Ak2djwnGgxOJ6geg2wqr1dVXR6fLeXXw==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/node-8-1/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@php-wasm/node-8-2": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/node-8-2/-/node-8-2-3.0.52.tgz", - "integrity": "sha512-fjGd/J2vUApLgQbviCpnqAZ6dxhVy6faBxL3Rg3ZCajH/NASd+Tn+z9GacnLjQms0zlphk/SbFLZdAU2WY6x8A==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/node-8-2/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@php-wasm/node-8-3": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/node-8-3/-/node-8-3-3.0.52.tgz", - "integrity": "sha512-88q2+OoQ0Zq1DVC+LFhc+F/bG9QnoRRDBZUgFSAOV0GB055F+oU9YXbM9du8OSuUDQ1OEVe+L0VM5sgDfDStIw==", + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/node/-/node-3.1.45.tgz", + "integrity": "sha512-IFnGdNsQ0g8RwpFzg3gAt8VckFwshQ7g2Izwt+i+wi2Rtnj54DcPZpfMwliiq+c1XU1//jtXHBdczbwR75yW7A==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", + "@php-wasm/cli-util": "3.1.45", + "@php-wasm/logger": "3.1.45", + "@php-wasm/node-5-2": "3.1.45", + "@php-wasm/node-7-4": "3.1.45", + "@php-wasm/node-8-0": "3.1.45", + "@php-wasm/node-8-1": "3.1.45", + "@php-wasm/node-8-2": "3.1.45", + "@php-wasm/node-8-3": "3.1.45", + "@php-wasm/node-8-4": "3.1.45", + "@php-wasm/node-8-5": "3.1.45", + "@php-wasm/universal": "3.1.45", + "@php-wasm/util": "3.1.45", + "fs-ext-extra-prebuilt": "2.2.7", "wasm-feature-detect": "1.8.0", - "ws": "8.18.3" + "ws": "8.21.0" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/node-8-3/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/node-8-4": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/node-8-4/-/node-8-4-3.0.52.tgz", - "integrity": "sha512-8B38E1yZQV/8fy9wkQHj23n/uW+2UhZIfcwoBcnRTztONeVKHzPl6rOLBylzJwpg3CXwJ7YJam/MhVkQEfP28g==", + "node_modules/@php-wasm/node-5-2": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/node-5-2/-/node-5-2-3.1.45.tgz", + "integrity": "sha512-mKYOI8/eWE7Gu9wOOwtcxGrhOfCfGlIqT3Jr1RK0qCsZ/GkiW2/EalsNC5wSWbaL9qdh4JUbXUoF7mE3dc+KRQ==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/node-8-4/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@php-wasm/node-8-5": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/node-8-5/-/node-8-5-3.0.52.tgz", - "integrity": "sha512-4UawC56VhV6m2YHuxsY0e/Je9F7JWAvFppJo3aBGUWEqQsOvD5lmiZZF/DgyfWJacfvimw3/eeqo1U63+G3e5Q==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/node-8-5/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@php-wasm/node-polyfills": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/node-polyfills/-/node-polyfills-3.0.52.tgz", - "integrity": "sha512-lMvGe+SHQVROSfAGpX/w8bCQukmBrS21TAOdoMUoFwUmxKwp1Ztfw+oYqm5maBR1jVoporog3F/KomtUcgab5Q==", - "dev": true, - "license": "GPL-2.0-or-later", - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/node/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@php-wasm/progress": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/progress/-/progress-3.0.52.tgz", - "integrity": "sha512-v41iBYG4nDNWdfQCZDbrn2Tmh0JnPQ1ElFl9kUXX/GExvM8LLXycVOp3O5y3+0i/tXuciJoKWj+9NF/PEuLDvw==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/logger": "3.0.52", - "@php-wasm/node-polyfills": "3.0.52" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/scopes": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/scopes/-/scopes-3.0.52.tgz", - "integrity": "sha512-AMb8RcVqIyqGe2wS7Lp4i3lDwsQlKXkqwarRCxJpgWCUP2CkYELOXTJqrR2SvLUf8HOYO5suH69CvAq+N15zeg==", - "dev": true, - "license": "GPL-2.0-or-later", - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/stream-compression": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/stream-compression/-/stream-compression-3.0.52.tgz", - "integrity": "sha512-BF4RzHm4kwaAIuL6SZG4V9YxtmDkEHWg4+nOOooM7KEzwc63V6lbujeAq/HwM/mqNBO2J+LW9ZJ+k4yCF7okSg==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/node-polyfills": "3.0.52", - "@php-wasm/util": "3.0.52" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/universal": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/universal/-/universal-3.0.52.tgz", - "integrity": "sha512-P88tyWsOjr35MSNOvQPono2bzkuorjXvQ3RFUV6yGHhRZXOMe+dzPcJ7EsJ5AOxxvhvshB4VLwxpyUAcFtj6Ww==", - "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/logger": "3.0.52", - "@php-wasm/node-polyfills": "3.0.52", - "@php-wasm/progress": "3.0.52", - "@php-wasm/stream-compression": "3.0.52", - "@php-wasm/util": "3.0.52", - "ini": "4.1.2" + "@php-wasm/universal": "3.1.45", + "wasm-feature-detect": "1.8.0" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/universal/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@php-wasm/util": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/util/-/util-3.0.52.tgz", - "integrity": "sha512-82u4Q13IPcL91CusRDy8k9L38zQrqqRO04pnTBJ3uMH1wZy4pAYZ305mKxce1EIU7QqPay/S69VdnWh+K4tOvA==", - "dev": true, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/web": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/web/-/web-3.0.52.tgz", - "integrity": "sha512-fjSgAOMo2dX5yknN8nAM6Ctd/sovZGIf6dEQeDzXoJm+dHlop6AMUa7FSj4/KXyENim6xcDRpAgf5yMcGiRyFw==", + "node_modules/@php-wasm/node-7-4": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/node-7-4/-/node-7-4-3.1.45.tgz", + "integrity": "sha512-3+VgXIL4y4Acb/OyNQAsIfz5I5GYlFmjw4M8l2Xx8TNBrixuOEO5vHmMoTssynZlmjoTLxBBzL2SaRHoubwi6g==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/fs-journal": "3.0.52", - "@php-wasm/logger": "3.0.52", - "@php-wasm/universal": "3.0.52", - "@php-wasm/util": "3.0.52", - "@php-wasm/web-7-4": "3.0.52", - "@php-wasm/web-8-0": "3.0.52", - "@php-wasm/web-8-1": "3.0.52", - "@php-wasm/web-8-2": "3.0.52", - "@php-wasm/web-8-3": "3.0.52", - "@php-wasm/web-8-4": "3.0.52", - "@php-wasm/web-8-5": "3.0.52", - "@php-wasm/web-service-worker": "3.0.52", - "@wp-playground/common": "3.0.52", - "express": "4.22.0", - "ini": "4.1.2", - "selfsigned": "5.5.0", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3", - "yargs": "17.7.2" + "@php-wasm/universal": "3.1.45", + "wasm-feature-detect": "1.8.0" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-7-4": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/web-7-4/-/web-7-4-3.0.52.tgz", - "integrity": "sha512-t+y8GXOl5WkaD7LeRfOn6iatgFy5ntc2X480FyoJoZmhDVj8e+wsMfZ/aAWDrkrV84tVLWj1GKTVAcBSGmuS2w==", + "node_modules/@php-wasm/node-8-0": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/node-8-0/-/node-8-0-3.1.45.tgz", + "integrity": "sha512-6yJaW+mxgBWAy80IYRU41bh1LH4WsuDgqEWiHSumJcKOcNljSedUbm+YuLTY+Pnsov7u5yzkaBskslxGXcOlIQ==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", + "@php-wasm/universal": "3.1.45", "wasm-feature-detect": "1.8.0" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/web-7-4/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-0": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/web-8-0/-/web-8-0-3.0.52.tgz", - "integrity": "sha512-iJlCd8cwk2GbKiTtUE1VmUzv4Z5yiJDmHgcNVdRh2tu1zVxLO4pLlG938bx7UPo6mm6L9SmgBx2kdgjOCmCcWQ==", + "node_modules/@php-wasm/node-8-1": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/node-8-1/-/node-8-1-3.1.45.tgz", + "integrity": "sha512-/5haLrmCySu40aDGtVAOukDBNYzCJ0JTXslXs36Rh8P9V2nlctVGO+Kp1m/74yCtdoJrZsRrBnVqKBCliVQjdg==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", + "@php-wasm/universal": "3.1.45", "wasm-feature-detect": "1.8.0" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-0/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@php-wasm/web-8-1": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/web-8-1/-/web-8-1-3.0.52.tgz", - "integrity": "sha512-0XfiFIOBIpYAb9zVuyOpXCQn/2g6OgIDAX/u2M3a3x4NxeLg2txvazU+cWRzhGRsSRFgptpqO69ojmhF1JaG7w==", + "node_modules/@php-wasm/node-8-2": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/node-8-2/-/node-8-2-3.1.45.tgz", + "integrity": "sha512-fGsSHw6OTnNyjr6k87OqV8SYqRZlDrWYVSXFkOywXUbBvyAYeuttxHffYC4VoRZdRz+Ygu+2k2aPE06jpTTBFw==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", + "@php-wasm/universal": "3.1.45", "wasm-feature-detect": "1.8.0" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/web-8-1/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-2": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/web-8-2/-/web-8-2-3.0.52.tgz", - "integrity": "sha512-btSMCor5I3735zudkQ0fKthfUxjx+KUgqf6ZHxjSkZ/baKXMpzVH7hTMhh1HjWWOmjQhqNBQ2KyeHzzAlm9+KQ==", + "node_modules/@php-wasm/node-8-3": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/node-8-3/-/node-8-3-3.1.45.tgz", + "integrity": "sha512-dq22w7k6zxSgRKEjFej2k2etHpWA/f6UZFQCwi0qPFTejlVRfGqJoY+6gwtF4PCCGXGD7J36XyRuSFuZz833MA==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", + "@php-wasm/universal": "3.1.45", "wasm-feature-detect": "1.8.0" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/web-8-2/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-3": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/web-8-3/-/web-8-3-3.0.52.tgz", - "integrity": "sha512-ahmusrtgmi/TIsWlHCfHX0GXxI0RdeCYGzrIYxQeFH3eEchX7J5ssqImL7sPFvP6tT/bluwn9rLef0Z2hki8bg==", + "node_modules/@php-wasm/node-8-4": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/node-8-4/-/node-8-4-3.1.45.tgz", + "integrity": "sha512-QElunKrFEpVa11Fdr6Afmw/gI/bCf5rxzAuXLBYfgghJP2w8sTT0M1ku1pocPEvMGeONbQgvHA06sDdKXhHEMA==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", + "@php-wasm/universal": "3.1.45", "wasm-feature-detect": "1.8.0" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-3/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "node_modules/@php-wasm/node-8-5": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/node-8-5/-/node-8-5-3.1.45.tgz", + "integrity": "sha512-FeKtaRMZorN1uRFbC6DILfv+Y9ImEMLjcpNVyT7zZ4WHPEf1yN0Q0Jo8VH9NNwCmkmiDAQN2gAIn3nKL8vsz+g==", "dev": true, - "license": "ISC", + "license": "GPL-2.0-or-later", + "dependencies": { + "@php-wasm/universal": "3.1.45", + "wasm-feature-detect": "1.8.0" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-4": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/web-8-4/-/web-8-4-3.0.52.tgz", - "integrity": "sha512-/5Ah8+tIhnO4RQbQZdkwasJ1NCubKlIfOTWi1N/uQlk0OrQ2KmVj5wB4PGDeYoP41FY2Qawffa8DYf4pdypM4w==", + "node_modules/@php-wasm/progress": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/progress/-/progress-3.1.45.tgz", + "integrity": "sha512-rc/I9MSoqAPLRmrgArpWMrSq6s7R16ulrMjG3Ti5T4hfu+j2oxfBCHbrwzR57ITsgecjKZ+G9j/w+saQj9cgpQ==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0" + "@php-wasm/logger": "3.1.45" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-4/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "node_modules/@php-wasm/scopes": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/scopes/-/scopes-3.1.45.tgz", + "integrity": "sha512-7efo3IvGLMOcUuywB40avWz1c6c7YurmRW/hM44iPlhr72x9Wpth9eHjI+Gsn+qFISmUqjW+G2KHx9BD7BTQBA==", "dev": true, - "license": "ISC", + "license": "GPL-2.0-or-later", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-5": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/web-8-5/-/web-8-5-3.0.52.tgz", - "integrity": "sha512-DlEhsPKFxXRaTXeuikrl8/de3Ru2putx6iWqPe8qaGNW4mKXQKjBNcwgR5NK83BzNa8ajnxDtl8tTYcTRY1iVg==", + "node_modules/@php-wasm/stream-compression": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/stream-compression/-/stream-compression-3.1.45.tgz", + "integrity": "sha512-zLU1AGNEg1tuwm93LHrL8OcV24LyNglTg/CXV5CVZiMPpg1wfIDHJy11qqjZM8iCIJk87qYQhkKOjTnGinAVDg==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/universal": "3.0.52", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0" + "@php-wasm/util": "3.1.45" + } + }, + "node_modules/@php-wasm/universal": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/universal/-/universal-3.1.45.tgz", + "integrity": "sha512-3x0TWQg6NEeO+M/oPA3rAP0hJB2gnsqwkb2sUipz0RQQXRkWEJjdrT20UVmGN/dXILDWeQg/VGxZhCktoWZGkA==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@php-wasm/logger": "3.1.45", + "@php-wasm/progress": "3.1.45", + "@php-wasm/stream-compression": "3.1.45", + "@php-wasm/util": "3.1.45", + "ini": "4.1.2" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web-8-5/node_modules/ini": { + "node_modules/@php-wasm/universal/node_modules/ini": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", @@ -4632,48 +4019,41 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/@php-wasm/web-service-worker": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/web-service-worker/-/web-service-worker-3.0.52.tgz", - "integrity": "sha512-eKOLRvXexO5XyiY9wsy8DGXKOnGcovLqxhJeez2eTZ7uQ95k5oOV0Vf9w9OUkLNOWpGg4/qts6Yh4BOgEABLOw==", + "node_modules/@php-wasm/util": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/util/-/util-3.1.45.tgz", + "integrity": "sha512-czXqXd2NJWkapV/zTr3WPSPdcgyI5KN7xSUusYpgkfljSovfvHOKKrTMQtbfPXRa9+MD8LmPQt+XStKPRp76Tg==", "dev": true, - "license": "GPL-2.0-or-later", - "dependencies": { - "@php-wasm/scopes": "3.0.52" - }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, - "node_modules/@php-wasm/web/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "node_modules/@php-wasm/web-service-worker": { + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/web-service-worker/-/web-service-worker-3.1.45.tgz", + "integrity": "sha512-L8spIluLVlaOZ8CnNPfJ5IEM/e1YouQ9kB8GJL+NVm27Pci/pxBE5Hi7nsmau/oQJ6JTA6rXMuDh3wyicFU0Xg==", "dev": true, - "license": "ISC", + "license": "GPL-2.0-or-later", + "dependencies": { + "@php-wasm/scopes": "3.1.45", + "@php-wasm/universal": "3.1.45" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, "node_modules/@php-wasm/xdebug-bridge": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@php-wasm/xdebug-bridge/-/xdebug-bridge-3.0.52.tgz", - "integrity": "sha512-lqVwXpjMuD4niKU3cmAiqTnTg6tk6gRqI7PLbMlmDDXJ7g59HebYkBd5NCXRCphGSj47ge44Fy/itoa0EOiluw==", + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@php-wasm/xdebug-bridge/-/xdebug-bridge-3.1.45.tgz", + "integrity": "sha512-InIWrSl9ULFEyIYbIK+uh2TK3N7VhQuycx3tRSaRY7YNpUGS2xxfNSt4BeJgBgUNmslKsQojSjCcmvumJW1mgg==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/logger": "3.0.52", - "@php-wasm/node": "3.0.52", - "@php-wasm/universal": "3.0.52", - "@wp-playground/common": "3.0.52", - "express": "4.22.0", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3", + "@php-wasm/logger": "3.1.45", + "@php-wasm/universal": "3.1.45", + "ws": "8.21.0", "xml2js": "0.6.2", "yargs": "17.7.2" }, @@ -4681,21 +4061,8 @@ "xdebug-bridge": "xdebug-bridge.js" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@php-wasm/xdebug-bridge/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, "node_modules/@pkgjs/parseargs": { @@ -5117,9 +4484,9 @@ } }, "node_modules/@types/aws-lambda": { - "version": "8.10.160", - "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.160.tgz", - "integrity": "sha512-uoO4QVQNWFPJMh26pXtmtrRfGshPUSpMZGUyUQY20FhfHEElEBOPKgVmFs1z+kbpyBsRs2JnoOPT7++Z4GA9pA==", + "version": "8.10.162", + "resolved": "https://registry.npmjs.org/@types/aws-lambda/-/aws-lambda-8.10.162.tgz", + "integrity": "sha512-Fn658grtLOci1oxi1391vvDWJRKNGWRSqfxRkmN/Iy3c0tQH1USMKEXcPYHLvope+ZgTFocx9FRQJx1muBL6qw==", "dev": true, "license": "MIT" }, @@ -5835,128 +5202,54 @@ } }, "node_modules/@wp-playground/blueprints": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@wp-playground/blueprints/-/blueprints-3.0.52.tgz", - "integrity": "sha512-WQ11urt2O6YItvwwwOYYFqw5wqDPwc5qgaYDsI8cp3hQqH/8bn6xIAwPR55ITNiZYhxl39+aOW1fqRzmymCkyA==", - "dev": true, - "dependencies": { - "@php-wasm/logger": "3.0.52", - "@php-wasm/node": "3.0.52", - "@php-wasm/node-polyfills": "3.0.52", - "@php-wasm/progress": "3.0.52", - "@php-wasm/scopes": "3.0.52", - "@php-wasm/stream-compression": "3.0.52", - "@php-wasm/universal": "3.0.52", - "@php-wasm/util": "3.0.52", - "@php-wasm/web-service-worker": "3.0.52", - "@wp-playground/common": "3.0.52", - "@wp-playground/storage": "3.0.52", - "@wp-playground/wordpress": "3.0.52", - "@zip.js/zip.js": "2.7.57", - "ajv": "8.12.0", - "async-lock": "1.4.1", - "clean-git-ref": "2.0.1", - "crc-32": "1.2.2", - "diff3": "0.0.4", - "express": "4.22.0", - "ignore": "5.3.2", - "ini": "4.1.2", - "minimisted": "2.0.1", - "octokit": "3.1.2", - "pako": "1.0.10", - "pify": "2.3.0", - "readable-stream": "3.6.2", - "selfsigned": "5.5.0", - "sha.js": "2.4.12", - "simple-get": "4.0.1", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3", - "yargs": "17.7.2" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@wp-playground/blueprints/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@wp-playground/blueprints/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@wp-playground/blueprints/-/blueprints-3.1.45.tgz", + "integrity": "sha512-q7jEN5w6dgwpzk26mkSGLLPEsTQsRfily0wPolAwueyhq2bnY7Nil7r1k+JHTR2XpTSg3Y3rFyp3j1biOpbsDA==", "dev": true, - "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "@php-wasm/logger": "3.1.45", + "@php-wasm/progress": "3.1.45", + "@php-wasm/stream-compression": "3.1.45", + "@php-wasm/universal": "3.1.45", + "@php-wasm/util": "3.1.45", + "@php-wasm/web-service-worker": "3.1.45", + "@wp-playground/common": "3.1.45", + "@wp-playground/storage": "3.1.45", + "@wp-playground/wordpress": "3.1.45", + "ajv": "8.18.0" }, "engines": { - "node": ">= 6" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, "node_modules/@wp-playground/cli": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@wp-playground/cli/-/cli-3.0.52.tgz", - "integrity": "sha512-IU3JnEetWQUyewnB3a8I9o3r+9D2nEqoisQje6Fs5kO4QfVgCluiP4ek6HmKEd0pBSaby9Qt2OAdRrKaPQBwIQ==", + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@wp-playground/cli/-/cli-3.1.45.tgz", + "integrity": "sha512-9cSDXOJoSdZSVrNBOraLlkiBMnvxy0EyaUrkr/8kBkNhWgNv2WhoPxMY25B0eh8nocH2mLVFHg9s4thuFghhug==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/cli-util": "3.0.52", - "@php-wasm/logger": "3.0.52", - "@php-wasm/node": "3.0.52", - "@php-wasm/progress": "3.0.52", - "@php-wasm/universal": "3.0.52", - "@php-wasm/util": "3.0.52", - "@php-wasm/xdebug-bridge": "3.0.52", - "@wp-playground/blueprints": "3.0.52", - "@wp-playground/common": "3.0.52", - "@wp-playground/storage": "3.0.52", - "@wp-playground/tools": "3.0.52", - "@wp-playground/wordpress": "3.0.52", - "@zip.js/zip.js": "2.7.57", - "ajv": "8.12.0", - "async-lock": "1.4.1", - "clean-git-ref": "2.0.1", - "crc-32": "1.2.2", - "diff3": "0.0.4", - "express": "4.22.0", - "fast-xml-parser": "^5.3.4", + "@php-wasm/cli-util": "3.1.45", + "@php-wasm/logger": "3.1.45", + "@php-wasm/node": "3.1.45", + "@php-wasm/progress": "3.1.45", + "@php-wasm/universal": "3.1.45", + "@php-wasm/util": "3.1.45", + "@php-wasm/xdebug-bridge": "3.1.45", + "@wp-playground/blueprints": "3.1.45", + "@wp-playground/common": "3.1.45", + "@wp-playground/storage": "3.1.45", + "@wp-playground/tools": "3.1.45", + "@wp-playground/wordpress": "3.1.45", + "express": "4.22.2", "fs-extra": "11.1.1", - "ignore": "5.3.2", - "ini": "4.1.2", - "jsonc-parser": "3.3.1", - "minimisted": "2.0.1", - "octokit": "3.1.2", - "pako": "1.0.10", - "pify": "2.3.0", - "ps-man": "1.1.8", - "readable-stream": "3.6.2", - "selfsigned": "5.5.0", - "sha.js": "2.4.12", - "simple-get": "4.0.1", "tmp-promise": "3.0.3", "wasm-feature-detect": "1.8.0", - "ws": "8.18.3", - "xml2js": "0.6.2", "yargs": "17.7.2" }, "bin": { "wp-playground-cli": "wp-playground.js" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" } }, "node_modules/@wp-playground/cli/node_modules/fs-extra": { @@ -5974,233 +5267,68 @@ "node": ">=14.14" } }, - "node_modules/@wp-playground/cli/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@wp-playground/cli/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/@wp-playground/common": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@wp-playground/common/-/common-3.0.52.tgz", - "integrity": "sha512-umfP5lCzjAWqJ3woSrlff+SGDal5y4QHftSk/w5L8SuwlZ0Rq8Q9X5CC2jA0adl8dfyb8auJPqpDbTf4+wWP8A==", + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@wp-playground/common/-/common-3.1.45.tgz", + "integrity": "sha512-dhVGdPqp4D0RhodW9sxdI3gdKPI98ue0oyXX4AeL4toLvjzKF1nz3AwniojsuHbJr0RV0QhA/Z2rYcTjynLD8A==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/universal": "3.0.52", - "@php-wasm/util": "3.0.52", - "ini": "4.1.2" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" + "@php-wasm/universal": "3.1.45", + "@php-wasm/util": "3.1.45" }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@wp-playground/common/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, "node_modules/@wp-playground/storage": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@wp-playground/storage/-/storage-3.0.52.tgz", - "integrity": "sha512-/oZeM5GIELessrzhLFJJscKXtLn34FT2IgqKLg4Vi2uqQ1gdYWx9A24tnLs59MeHa8Mvu0jEAPcAd6AM/ze1yQ==", + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@wp-playground/storage/-/storage-3.1.45.tgz", + "integrity": "sha512-c9iWgHHhwEElroXqWBi8B7rSsvAbSYjCDA1m5zTmg+jpscbT8zLrIohJ3WANbWljeSxG4sWA87PLqARdchyl3A==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/stream-compression": "3.0.52", - "@php-wasm/universal": "3.0.52", - "@php-wasm/util": "3.0.52", - "@php-wasm/web": "3.0.52", + "@php-wasm/stream-compression": "3.1.45", + "@php-wasm/universal": "3.1.45", + "@php-wasm/util": "3.1.45", "@zip.js/zip.js": "2.7.57", - "async-lock": "^1.4.1", - "clean-git-ref": "^2.0.1", - "crc-32": "^1.2.0", - "diff3": "0.0.3", - "express": "4.22.0", - "ignore": "^5.1.4", - "ini": "4.1.2", - "minimisted": "^2.0.0", + "isomorphic-git": "1.37.6", "octokit": "3.1.2", "pako": "^1.0.10", - "pify": "^4.0.1", - "readable-stream": "^3.4.0", - "selfsigned": "5.5.0", - "sha.js": "^2.4.9", - "simple-get": "^4.0.1", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3", - "yargs": "17.7.2" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@wp-playground/storage/node_modules/diff3": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz", - "integrity": "sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@wp-playground/storage/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@wp-playground/storage/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/@wp-playground/storage/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "sha.js": "2.4.12" } }, "node_modules/@wp-playground/tools": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@wp-playground/tools/-/tools-3.0.52.tgz", - "integrity": "sha512-uBCbO5rztC1cObHy+ehlDGXiFeZOuqHMCYgZJSUX4q7oqXa+AMua1IMc33AVkfSVjPFnp3f+/oR24hM2nYAWCg==", + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@wp-playground/tools/-/tools-3.1.45.tgz", + "integrity": "sha512-nhGuCsVgd0VIe+nQgrKKsVXCu2XHHSnj7+GiH4qIThYUpXLMZo/s+w1bI0ANGOCgpUTOv89Q2JOFPrn37+b3tA==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@wp-playground/blueprints": "3.0.52", - "@zip.js/zip.js": "2.7.57", - "ajv": "8.12.0", - "async-lock": "1.4.1", - "clean-git-ref": "2.0.1", - "crc-32": "1.2.2", - "diff3": "0.0.4", - "express": "4.22.0", - "ignore": "5.3.2", - "ini": "4.1.2", - "minimisted": "2.0.1", - "octokit": "3.1.2", - "pako": "1.0.10", - "pify": "2.3.0", - "readable-stream": "3.6.2", - "selfsigned": "5.5.0", - "sha.js": "2.4.12", - "simple-get": "4.0.1", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3", - "yargs": "17.7.2" - }, - "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@wp-playground/tools/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/@wp-playground/tools/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "@wp-playground/blueprints": "3.1.45" }, "engines": { - "node": ">= 6" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, "node_modules/@wp-playground/wordpress": { - "version": "3.0.52", - "resolved": "https://registry.npmjs.org/@wp-playground/wordpress/-/wordpress-3.0.52.tgz", - "integrity": "sha512-P37YCxJuDSBCi0JIL4mkYUJsCSW1GrnL2LWTgups/NKWf1MCODEhmCSFfixfbMb7BFOvlC6Tb8RXw+O2dG1Ouw==", + "version": "3.1.45", + "resolved": "https://registry.npmjs.org/@wp-playground/wordpress/-/wordpress-3.1.45.tgz", + "integrity": "sha512-kQqx7m4oKRnSmTxiwdwVnUGetJINHVULMURff2+JZ4EGLqAUVscyCQ4YvQMnIho6gASyzt8TYLr3GqxU+1n6AA==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@php-wasm/logger": "3.0.52", - "@php-wasm/node": "3.0.52", - "@php-wasm/universal": "3.0.52", - "@php-wasm/util": "3.0.52", - "@wp-playground/common": "3.0.52", - "express": "4.22.0", - "ini": "4.1.2", - "wasm-feature-detect": "1.8.0", - "ws": "8.18.3", - "yargs": "17.7.2" + "@php-wasm/logger": "3.1.45", + "@php-wasm/universal": "3.1.45", + "@php-wasm/util": "3.1.45", + "@wp-playground/common": "3.1.45", + "zstddec": "^0.2.0" }, "engines": { - "node": ">=20.18.3", - "npm": ">=10.1.0" - }, - "optionalDependencies": { - "fs-ext": "2.1.1" - } - }, - "node_modules/@wp-playground/wordpress/node_modules/ini": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", - "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=20.10.0", + "npm": ">=10.2.3" } }, "node_modules/@zip.js/zip.js": { @@ -6221,6 +5349,19 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -6259,16 +5400,16 @@ } }, "node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" + "require-from-string": "^2.0.2" }, "funding": { "type": "github", @@ -6484,21 +5625,6 @@ "safer-buffer": "~2.1.0" } }, - "node_modules/asn1js": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.7.tgz", - "integrity": "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "pvtsutils": "^1.3.6", - "pvutils": "^1.1.3", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", @@ -6816,9 +5942,9 @@ } }, "node_modules/body-parser": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", - "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "version": "1.20.6", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.6.tgz", + "integrity": "sha512-p5tAzS57i5MV9fZFDj9LeIiTZEufbSe2eDozP+ElheSUq1m74CRq1jI4mYNDdVs9vQztXFLuk/Gd6BWTdwRJ5g==", "dev": true, "license": "MIT", "dependencies": { @@ -6830,7 +5956,7 @@ "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "on-finished": "~2.4.1", - "qs": "~6.14.0", + "qs": "~6.15.1", "raw-body": "~2.5.3", "type-is": "~1.6.18", "unpipe": "~1.0.0" @@ -7009,16 +6135,6 @@ "integrity": "sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ==", "dev": true }, - "node_modules/bytestreamjs": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/bytestreamjs/-/bytestreamjs-2.0.1.tgz", - "integrity": "sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", @@ -7091,15 +6207,15 @@ } }, "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", + "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", "dev": true, "license": "MIT", "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "get-intrinsic": "^1.3.0", "set-function-length": "^1.2.2" }, "engines": { @@ -7616,36 +6732,15 @@ "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-disposition/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } }, "node_modules/content-type": { "version": "1.0.5", @@ -8255,9 +7350,9 @@ } }, "node_modules/diff3": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.4.tgz", - "integrity": "sha512-f1rQ7jXDn/3i37hdwRk9ohqcvLRH3+gEIgmA6qEM280WUOh7cOr3GXV8Jm5sPwUs46Nzl48SE8YNLGJoaLuodg==", + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz", + "integrity": "sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==", "dev": true, "license": "MIT" }, @@ -8713,6 +7808,16 @@ "node": ">= 0.6" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/eventemitter2": { "version": "6.4.7", "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz", @@ -8726,6 +7831,16 @@ "dev": true, "license": "MIT" }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/events-to-array": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/events-to-array/-/events-to-array-1.1.2.tgz", @@ -8846,15 +7961,15 @@ } }, "node_modules/express": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.0.tgz", - "integrity": "sha512-c2iPh3xp5vvCLgaHK03+mWLFPhox7j1LwyxcZwFVApEv5i0X+IjPpbT50SJJwwLpdBVfp45AkK/v+AFgv/XlfQ==", + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz", + "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==", "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "~1.20.3", + "body-parser": "~1.20.5", "content-disposition": "~0.5.4", "content-type": "~1.0.4", "cookie": "~0.7.1", @@ -8873,7 +7988,7 @@ "parseurl": "~1.3.3", "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", - "qs": "~6.14.0", + "qs": "~6.15.1", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "~0.19.0", @@ -8909,27 +8024,6 @@ "dev": true, "license": "MIT" }, - "node_modules/express/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -9059,6 +8153,23 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-uri": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", + "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/fast-xml-builder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.3.0.tgz", @@ -9440,15 +8551,15 @@ "integrity": "sha512-kSxoARUDn4F2RPXX48UXnaFKwVU7Ivd/6qpzZL29MCDmr9sTvybv4gFCp+qaI4fM9m0z9fgz/yJvi56GAz+BZg==", "dev": true }, - "node_modules/fs-ext": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/fs-ext/-/fs-ext-2.1.1.tgz", - "integrity": "sha512-/TrISPOFhCkbgIRWK9lzscRzwPCu0PqtCcvMc9jsHKBgZGoqA0VzhspVht5Zu8lxaXjIYIBWILHpRotYkCCcQA==", + "node_modules/fs-ext-extra-prebuilt": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/fs-ext-extra-prebuilt/-/fs-ext-extra-prebuilt-2.2.7.tgz", + "integrity": "sha512-Q7rayYRBDIvDF01HWOwSSjoaP+05N1g+o3BXL1Zf8Frw2JkjSmi4EtvCBITuW30l6hB2m2TW1pehdh8wyU/+gw==", "dev": true, "hasInstallScript": true, - "optional": true, + "license": "MIT", "dependencies": { - "nan": "^2.21.0" + "nan": "^2.24.0" }, "engines": { "node": ">= 8.0.0" @@ -11294,6 +10405,42 @@ "node": ">=0.10.0" } }, + "node_modules/isomorphic-git": { + "version": "1.37.6", + "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.37.6.tgz", + "integrity": "sha512-qr1NFCPsVTZ6YGqTXw0CzamnsHyH9QQ1OTEfeXIweSljRUMzuHFCJdUn0wc6OcjtTDns6knxjPb7N6LmJeftOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-lock": "^1.4.1", + "clean-git-ref": "^2.0.1", + "crc-32": "^1.2.0", + "diff3": "0.0.3", + "ignore": "^5.1.4", + "minimisted": "^2.0.0", + "pako": "^1.0.10", + "pify": "^4.0.1", + "readable-stream": "^4.0.0", + "sha.js": "^2.4.12", + "simple-get": "^4.0.1" + }, + "bin": { + "isogit": "cli.cjs" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/isomorphic-git/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", @@ -11747,9 +10894,9 @@ } }, "node_modules/jsonwebtoken/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, "license": "ISC", "bin": { @@ -13063,12 +12210,11 @@ "dev": true }, "node_modules/nan": { - "version": "2.25.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.25.0.tgz", - "integrity": "sha512-0M90Ag7Xn5KMLLZ7zliPWP3rT90P6PN+IzVFS0VqmnPktBk3700xUVv8Ikm9EUaUE5SDWdp/BIxdENzVznpm1g==", + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.28.0.tgz", + "integrity": "sha512-fTsDz99OTq2sVePhGdp4qQhggZFtKr64ZNVyVajRKtMOkJxYekplBh577PiJB12v/D3s2E5cGtOI45LWp6rnLQ==", "dev": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/nanoid": { "version": "3.3.12", @@ -13728,9 +12874,9 @@ "dev": true }, "node_modules/pako": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", - "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true, "license": "(MIT AND Zlib)" }, @@ -13888,9 +13034,9 @@ } }, "node_modules/path-to-regexp": { - "version": "0.1.12", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", - "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz", + "integrity": "sha512-A/AGNMFN3c8bOlvV9RreMdrv7jsmF9XIfDeCd87+I8RNg6s78BhJxMu69NEMHBSJFxKidViTEdruRwEk/WIKqA==", "dev": true, "license": "MIT" }, @@ -13951,24 +13097,6 @@ "node": ">=8" } }, - "node_modules/pkijs": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/pkijs/-/pkijs-3.3.3.tgz", - "integrity": "sha512-+KD8hJtqQMYoTuL1bbGOqxb4z+nZkTAwVdNtWwe8Tc2xNbEmdJYIYoc6Qt0uF55e6YW6KuTHw1DjQ18gMhzepw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@noble/hashes": "1.4.0", - "asn1js": "^3.0.6", - "bytestreamjs": "^2.0.1", - "pvtsutils": "^1.3.6", - "pvutils": "^1.1.3", - "tslib": "^2.8.1" - }, - "engines": { - "node": ">=16.0.0" - } - }, "node_modules/posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -14106,13 +13234,6 @@ "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", "dev": true }, - "node_modules/ps-man": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ps-man/-/ps-man-1.1.8.tgz", - "integrity": "sha512-ZKDPZwHLYVWIk/Q75N7jCFbuQyokSg2+3WBlt8l35S/uBvxoc+LiRUbb3RUt83pwW82dzwiCpoQIHd9PAxUzHg==", - "dev": true, - "license": "MIT" - }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -14132,34 +13253,15 @@ "node": ">=6" } }, - "node_modules/pvtsutils": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", - "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.8.1" - } - }, - "node_modules/pvutils": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", - "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16.0.0" - } - }, "node_modules/qs": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", - "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.1.0" + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" }, "engines": { "node": ">=0.6" @@ -14209,6 +13311,48 @@ "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", "dev": true }, + "node_modules/readable-stream": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz", + "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==", + "dev": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/readable-stream/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -14233,13 +13377,6 @@ "node": ">= 0.10" } }, - "node_modules/reflect-metadata": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", - "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -14555,10 +13692,25 @@ } }, "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" }, "node_modules/safe-json-parse": { "version": "1.0.1", @@ -14633,9 +13785,9 @@ } }, "node_modules/sax": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz", - "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -14657,20 +13809,6 @@ "node": ">=24" } }, - "node_modules/selfsigned": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-5.5.0.tgz", - "integrity": "sha512-ftnu3TW4+3eBfLRFnDEkzGxSF/10BJBkaLJuBHZX0kiPS7bRdlpZGu6YGt4KngMkdTwJE6MbjavFpqHvqVt+Ew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@peculiar/x509": "^1.14.2", - "pkijs": "^3.3.3" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -14817,27 +13955,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/sha.js/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -14885,15 +14002,15 @@ } }, "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" }, @@ -14905,14 +14022,14 @@ } }, "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "object-inspect": "^1.13.4" }, "engines": { "node": ">= 0.4" @@ -15429,12 +14546,13 @@ } }, "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "license": "MIT", "dependencies": { - "safe-buffer": "~5.1.0" + "safe-buffer": "~5.2.0" } }, "node_modules/string-template": { @@ -17795,27 +16913,6 @@ "dev": true, "license": "MIT" }, - "node_modules/to-buffer/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -17918,33 +17015,6 @@ "node": ">= 8" } }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD" - }, - "node_modules/tsyringe": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz", - "integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^1.9.3" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/tsyringe/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, - "license": "0BSD" - }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -18323,16 +17393,6 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, "node_modules/uri-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", @@ -18693,14 +17753,14 @@ "dev": true }, "node_modules/which-typed-array": { - "version": "1.1.20", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", - "integrity": "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==", + "version": "1.1.22", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.22.tgz", + "integrity": "sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==", "dev": true, "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", + "call-bind": "^1.0.9", "call-bound": "^1.0.4", "for-each": "^0.3.5", "get-proto": "^1.0.1", @@ -18834,9 +17894,9 @@ } }, "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", "dev": true, "license": "MIT", "engines": { @@ -18958,6 +18018,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zstddec": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/zstddec/-/zstddec-0.2.0.tgz", + "integrity": "sha512-oyPnDa1X5c13+Y7mA/FDMNJrn4S8UNBe0KCqtDmor40Re7ALrPN6npFwyYVRRh+PqozZQdeg23QtbcamZnG5rA==", + "dev": true, + "license": "MIT AND BSD-3-Clause" + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", From 1062691668197b0b07553fcf7836cd12745278d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 28 Jun 2026 15:53:33 +0000 Subject: [PATCH 133/148] npm(deps): bump vue from 3.5.38 to 3.5.39 Bumps [vue](https://github.com/vuejs/core) from 3.5.38 to 3.5.39. - [Release notes](https://github.com/vuejs/core/releases) - [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md) - [Commits](https://github.com/vuejs/core/compare/v3.5.38...v3.5.39) --- updated-dependencies: - dependency-name: vue dependency-version: 3.5.39 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 108 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 55 insertions(+), 55 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6216164be..8323c9dc9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "select2": "^4.1.0", "shufflejs": "^6.1.1", "spin.js": "^2.3.2", - "vue": "^3.5.38" + "vue": "^3.5.39" }, "devDependencies": { "@babel/preset-env": "^7.29.7", @@ -4656,13 +4656,13 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.38.tgz", - "integrity": "sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ==", + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.39.tgz", + "integrity": "sha512-16KBTEXAJCpDr0mwlw+AZyhu8iyC7R3S2vBwsI7QnWJU6X3WKc9VKeNEZpiMdZ569qWhz9574L3vV55qRL0Vtw==", "license": "MIT", "dependencies": { "@babel/parser": "^7.29.7", - "@vue/shared": "3.5.38", + "@vue/shared": "3.5.39", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" @@ -4681,26 +4681,26 @@ } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.38.tgz", - "integrity": "sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw==", + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.39.tgz", + "integrity": "sha512-oQPigALqYbNxTNPvNgSOe+czwVExfbVF02lz8jP0S3AXJiu3jxYDygNUiqSep4ezzW8XgnubqH63My2A7JR/vg==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.38", - "@vue/shared": "3.5.38" + "@vue/compiler-core": "3.5.39", + "@vue/shared": "3.5.39" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.38.tgz", - "integrity": "sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg==", + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.39.tgz", + "integrity": "sha512-d0ki86iOyN8LoZPBmk5SJWNwHP19CnDDCfuo//+2WJa2g5Ke0Jay983PIBIcSSzldC68I8DrD5GrHV3OSDfodg==", "license": "MIT", "dependencies": { "@babel/parser": "^7.29.7", - "@vue/compiler-core": "3.5.38", - "@vue/compiler-dom": "3.5.38", - "@vue/compiler-ssr": "3.5.38", - "@vue/shared": "3.5.38", + "@vue/compiler-core": "3.5.39", + "@vue/compiler-dom": "3.5.39", + "@vue/compiler-ssr": "3.5.39", + "@vue/shared": "3.5.39", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", "postcss": "^8.5.15", @@ -4708,13 +4708,13 @@ } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.38.tgz", - "integrity": "sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA==", + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.39.tgz", + "integrity": "sha512-Ce7/wvwMHai74bdszfXExdazFigYnlF9zgCmEQUcM1j0fOymlouZ7XilTYNo8oUjhlnjYOZbGrcYKuqjz89Ucw==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.38", - "@vue/shared": "3.5.38" + "@vue/compiler-dom": "3.5.39", + "@vue/shared": "3.5.39" } }, "node_modules/@vue/devtools-api": { @@ -4751,53 +4751,53 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.38.tgz", - "integrity": "sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==", + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.39.tgz", + "integrity": "sha512-TpsuBJ9gGlZa5d23XcM2y8EXanz9dZeVDQBXRwzy46ItgvM+rWpzs+UVM0wcRLxGvcav0HE5jz2gNL53xlRAog==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.38" + "@vue/shared": "3.5.39" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.38.tgz", - "integrity": "sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw==", + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.39.tgz", + "integrity": "sha512-9GLtNyRvPAUMbX+7ono0RC2j0guo2LXVi8LvcmAooImACUKm0oFf0jjwbX8/H0AE/t1nxhAkn8RSl9PMCzzxZw==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.38", - "@vue/shared": "3.5.38" + "@vue/reactivity": "3.5.39", + "@vue/shared": "3.5.39" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.38.tgz", - "integrity": "sha512-apX2wt9sdfDshS+a2xueFZLVpt0GkRJZSoPmrW/SA4yzXTznhfcMVW59gr7h4YQeY0vJhdJkk2rsIDwgfFgC5A==", + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.39.tgz", + "integrity": "sha512-7Y6aAGboKcXAZ3ECuUy7RrS5yy2r47dhTp2SKaJmYxjopImaVFaNa5Ne66NwGovsrxVAl5S5rwc7m22UG7Lmww==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.38", - "@vue/runtime-core": "3.5.38", - "@vue/shared": "3.5.38", + "@vue/reactivity": "3.5.39", + "@vue/runtime-core": "3.5.39", + "@vue/shared": "3.5.39", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.38.tgz", - "integrity": "sha512-vue8vbf2QlV4quHqzwmJy6dWfmRhP1J8l4wtZg60CL6VoKqcPY2oe7may3+1d9qfpedjK5PRLFqd5k3Isj9mUw==", + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.39.tgz", + "integrity": "sha512-yZSakiAGw85rZfG7UM8akMnIF+FmeiNk47uvHf2nVBBSe+dIKUhZuZq9+XgJhbV3nS5Z4ALH23/MpXofW+mbcw==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.38", - "@vue/shared": "3.5.38" + "@vue/compiler-ssr": "3.5.39", + "@vue/shared": "3.5.39" }, "peerDependencies": { - "vue": "3.5.38" + "vue": "3.5.39" } }, "node_modules/@vue/shared": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.38.tgz", - "integrity": "sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==", + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.39.tgz", + "integrity": "sha512-l1rrBtBfTnmxvtsvdQDXltUUy8S1Y+ZaqdfUzmAnJkTd8Z8rv5v/ytW+TKiqEOWyHPoqtPlNFSs0lhRmYVSHVA==", "license": "MIT" }, "node_modules/@vueuse/core": { @@ -17672,16 +17672,16 @@ } }, "node_modules/vue": { - "version": "3.5.38", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.38.tgz", - "integrity": "sha512-vAMKHfImQlYSy0C+PBue4s3ERZ2xGKfgZg5GXAsLInq1dyh2H78ILVP5sK0KPFPVW4kv+OGCIvBEondcjpZp7A==", + "version": "3.5.39", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.39.tgz", + "integrity": "sha512-xmZCYabFGcirU8r0fTuvl/LICc1OU620rnqepaJDL/a141ZigkG7AyaxQLdqJ02ZRYzWe6YPaDHeQx7MfknQfA==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.38", - "@vue/compiler-sfc": "3.5.38", - "@vue/runtime-dom": "3.5.38", - "@vue/server-renderer": "3.5.38", - "@vue/shared": "3.5.38" + "@vue/compiler-dom": "3.5.39", + "@vue/compiler-sfc": "3.5.39", + "@vue/runtime-dom": "3.5.39", + "@vue/server-renderer": "3.5.39", + "@vue/shared": "3.5.39" }, "peerDependencies": { "typescript": "*" diff --git a/package.json b/package.json index 79ef1cd74..24b66c95e 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,6 @@ "select2": "^4.1.0", "shufflejs": "^6.1.1", "spin.js": "^2.3.2", - "vue": "^3.5.38" + "vue": "^3.5.39" } } From 8286b3999b92b8c6f79c6fbcc2007cb45553de60 Mon Sep 17 00:00:00 2001 From: hansmorb Date: Sun, 19 Jul 2026 12:42:32 +0000 Subject: [PATCH 134/148] Ran wp i18n make-pot --- languages/commonsbooking-de_DE.po | 88 +++++++++++++++--------------- languages/commonsbooking.pot | 90 +++++++++++++++---------------- 2 files changed, 89 insertions(+), 89 deletions(-) diff --git a/languages/commonsbooking-de_DE.po b/languages/commonsbooking-de_DE.po index 44baa27bf..396c05a88 100644 --- a/languages/commonsbooking-de_DE.po +++ b/languages/commonsbooking-de_DE.po @@ -510,8 +510,8 @@ msgid "The color used for dark text on light backgrounds" msgstr "Die Farbe, die für dunklen Text auf hellem Hintergrund verwendet wird" #: includes/OptionsArray.php:644 -#: src/Wordpress/CustomPostType/Restriction.php:305 -#: src/Wordpress/CustomPostType/Restriction.php:326 +#: src/Wordpress/CustomPostType/Restriction.php:287 +#: src/Wordpress/CustomPostType/Restriction.php:308 #: templates/dashboard-index.php:47 msgid "Restrictions" msgstr "Einschränkungen" @@ -809,7 +809,7 @@ msgstr "Zeitrahmen-Export herunterladen" #: includes/OptionsArray.php:1321 #: src/Wordpress/CustomPostType/Map.php:557 #: src/Wordpress/CustomPostType/Restriction.php:47 -#: src/Wordpress/CustomPostType/Restriction.php:415 +#: src/Wordpress/CustomPostType/Restriction.php:397 #: src/Wordpress/CustomPostType/Timeframe.php:98 #: src/Wordpress/CustomPostType/Timeframe.php:455 msgid "Type" @@ -1276,14 +1276,14 @@ msgstr "Der Ordner %s ist nicht beschreibbar." #: src/View/Admin/Filter.php:58 #: src/Wordpress/CustomPostType/Booking.php:792 -#: src/Wordpress/CustomPostType/Restriction.php:451 +#: src/Wordpress/CustomPostType/Restriction.php:433 #: src/Wordpress/CustomPostType/Timeframe.php:678 msgid "Start date" msgstr "Startdatum" #: src/View/Admin/Filter.php:62 #: src/Wordpress/CustomPostType/Booking.php:809 -#: src/Wordpress/CustomPostType/Restriction.php:461 +#: src/Wordpress/CustomPostType/Restriction.php:443 #: src/Wordpress/CustomPostType/Timeframe.php:702 msgid "End date" msgstr "Enddatum" @@ -1316,7 +1316,7 @@ msgstr "Nutzende*r" #: src/View/Booking.php:200 #: src/View/MassOperations.php:42 #: src/Wordpress/CustomPostType/Booking.php:986 -#: src/Wordpress/CustomPostType/Restriction.php:477 +#: src/Wordpress/CustomPostType/Restriction.php:459 msgid "Status" msgstr "Status" @@ -1338,7 +1338,7 @@ msgstr "Liste der Buchungscodes" #: src/Wordpress/CustomPostType/Booking.php:1002 #: src/Wordpress/CustomPostType/Item.php:117 #: src/Wordpress/CustomPostType/Restriction.php:48 -#: src/Wordpress/CustomPostType/Restriction.php:438 +#: src/Wordpress/CustomPostType/Restriction.php:420 #: src/Wordpress/CustomPostType/Timeframe.php:99 #: templates/shortcode-bookings.php:73 msgid "Item" @@ -1354,7 +1354,7 @@ msgstr "Keine Artikel gefunden." #: src/Wordpress/CustomPostType/Booking.php:998 #: src/Wordpress/CustomPostType/Location.php:139 #: src/Wordpress/CustomPostType/Restriction.php:49 -#: src/Wordpress/CustomPostType/Restriction.php:431 +#: src/Wordpress/CustomPostType/Restriction.php:413 #: src/Wordpress/CustomPostType/Timeframe.php:100 #: src/Wordpress/CustomPostType/Timeframe.php:463 #: templates/shortcode-bookings.php:75 @@ -1562,7 +1562,7 @@ msgstr "Buchungen" #: src/Wordpress/CustomPostType/Booking.php:538 #: src/Wordpress/CustomPostType/Item.php:118 #: src/Wordpress/CustomPostType/Location.php:140 -#: src/Wordpress/CustomPostType/Restriction.php:307 +#: src/Wordpress/CustomPostType/Restriction.php:289 #: src/Wordpress/CustomPostType/Timeframe.php:1153 msgid "Add new" msgstr "Neu hinzufügen" @@ -2031,104 +2031,104 @@ msgstr "Filtern nach Standort " msgid "Filter By Status " msgstr "Filtern nach Status " -#: src/Wordpress/CustomPostType/Restriction.php:306 -#: src/Wordpress/CustomPostType/Restriction.php:387 +#: src/Wordpress/CustomPostType/Restriction.php:288 +#: src/Wordpress/CustomPostType/Restriction.php:369 msgid "Restriction" msgstr "Einschränkung" -#: src/Wordpress/CustomPostType/Restriction.php:308 -#: src/Wordpress/CustomPostType/Restriction.php:310 +#: src/Wordpress/CustomPostType/Restriction.php:290 +#: src/Wordpress/CustomPostType/Restriction.php:292 msgid "Add new Restriction" msgstr "Neue Einschränkung hinzufügen" -#: src/Wordpress/CustomPostType/Restriction.php:309 +#: src/Wordpress/CustomPostType/Restriction.php:291 msgid "Edit Restriction" msgstr "Einschränkung bearbeiten" -#: src/Wordpress/CustomPostType/Restriction.php:311 +#: src/Wordpress/CustomPostType/Restriction.php:293 msgid "Show Restriction" msgstr "Einschränkung anzeigen" -#: src/Wordpress/CustomPostType/Restriction.php:312 +#: src/Wordpress/CustomPostType/Restriction.php:294 msgid "Show Restrictions" msgstr "Einschränkungen anzeigen" -#: src/Wordpress/CustomPostType/Restriction.php:313 +#: src/Wordpress/CustomPostType/Restriction.php:295 msgid "Search Restrictions" msgstr "Einschränkungen suchen" -#: src/Wordpress/CustomPostType/Restriction.php:314 +#: src/Wordpress/CustomPostType/Restriction.php:296 msgid "Restrictions not found" msgstr "Einschränkungen nicht gefunden" -#: src/Wordpress/CustomPostType/Restriction.php:315 +#: src/Wordpress/CustomPostType/Restriction.php:297 msgid "No Restrictions found in trash" msgstr "Keine Einschränkungen im Papierkorb gefunden" -#: src/Wordpress/CustomPostType/Restriction.php:316 +#: src/Wordpress/CustomPostType/Restriction.php:298 msgid "Parent Restrictions:" msgstr "Übergeordnete Einschränkungen:" -#: src/Wordpress/CustomPostType/Restriction.php:317 +#: src/Wordpress/CustomPostType/Restriction.php:299 msgid "All Restrictions" msgstr "Alle Einschränkungen" -#: src/Wordpress/CustomPostType/Restriction.php:318 +#: src/Wordpress/CustomPostType/Restriction.php:300 msgid "Restriction archive" msgstr "Einschränkungsarchiv" -#: src/Wordpress/CustomPostType/Restriction.php:319 +#: src/Wordpress/CustomPostType/Restriction.php:301 msgid "Restriction attributes" msgstr "Einschränkungsattribute" -#: src/Wordpress/CustomPostType/Restriction.php:320 +#: src/Wordpress/CustomPostType/Restriction.php:302 msgid "Add to Restriction" msgstr "Zur Einschränkung hinzufügen" -#: src/Wordpress/CustomPostType/Restriction.php:321 +#: src/Wordpress/CustomPostType/Restriction.php:303 msgid "Added to Restriction" msgstr "Zur Einschränkung hinzugefügt" -#: src/Wordpress/CustomPostType/Restriction.php:322 +#: src/Wordpress/CustomPostType/Restriction.php:304 msgid "Restriction image" msgstr "Einschränkungs-Bild" -#: src/Wordpress/CustomPostType/Restriction.php:323 +#: src/Wordpress/CustomPostType/Restriction.php:305 msgid "set Restriction image" msgstr "Festlegen des Einschränkungsbilds" -#: src/Wordpress/CustomPostType/Restriction.php:324 +#: src/Wordpress/CustomPostType/Restriction.php:306 msgid "remove Restriction image" msgstr "Einschränkungsbild entfernen" -#: src/Wordpress/CustomPostType/Restriction.php:325 +#: src/Wordpress/CustomPostType/Restriction.php:307 msgid "use as Restriction image" msgstr "Verwendung als Einschränkungsbild" -#: src/Wordpress/CustomPostType/Restriction.php:434 -#: src/Wordpress/CustomPostType/Restriction.php:441 +#: src/Wordpress/CustomPostType/Restriction.php:416 +#: src/Wordpress/CustomPostType/Restriction.php:423 #: src/Wordpress/CustomPostType/Timeframe.php:815 #: templates/shortcode-bookings.php:55 msgid "All" msgstr "Alle" -#: src/Wordpress/CustomPostType/Restriction.php:445 +#: src/Wordpress/CustomPostType/Restriction.php:427 msgid "Hint" msgstr "Erläuterung" -#: src/Wordpress/CustomPostType/Restriction.php:447 +#: src/Wordpress/CustomPostType/Restriction.php:429 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 "Bitte gib hier eine kurze Information über den Grund und mögliche Auswirkungen der Nutzungsbeschränkung ein.
      Die Erklärung wird auf der Artikelseite und in der Benachrichtigungs-E-Mail angezeigt." -#: src/Wordpress/CustomPostType/Restriction.php:452 +#: src/Wordpress/CustomPostType/Restriction.php:434 msgid "Set the start date and time" msgstr "Startdatums und der Startzeit festlegen" -#: src/Wordpress/CustomPostType/Restriction.php:462 +#: src/Wordpress/CustomPostType/Restriction.php:444 msgid "Set the estimated end date and time" msgstr "Das geschätzte Enddatum und die geschätzten Endzeit festlegen" -#: src/Wordpress/CustomPostType/Restriction.php:480 +#: src/Wordpress/CustomPostType/Restriction.php:462 msgid "" "Choose status of this restriction.
      \n" "\t\t\t\tSet to None if you want to deactivate the restriction.
      \n" @@ -2140,31 +2140,31 @@ msgstr "" "Wähle den Status dieser Einschränkung aus.
      Wähle Keine wenn du die Einschränkung deaktivieren möchtest.
      Wähle Aktiv, wenn die Einschränkung aktiv ist.
      Wähle Problem gelöst, wenn die Einschränkung nicht mehr besteht.
      Je nach ausgewähltem Status erhalten betroffene Nutzende entsprechende Benachrichtigungs-E-Mails.\n" "Wähle den gewünschten Status aus und klicke dann auf die Schaltfläche \"Senden\", um die E-Mail zu senden. Commonsbooking -> Tab Restrictions" 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:514 +#: src/Wordpress/CustomPostType/Restriction.php:496 msgid "Total breakdown" msgstr "Totalausfall" -#: src/Wordpress/CustomPostType/Restriction.php:515 +#: src/Wordpress/CustomPostType/Restriction.php:497 msgid "Notice" msgstr "Hinweis" -#: src/Wordpress/CustomPostType/Restriction.php:525 +#: src/Wordpress/CustomPostType/Restriction.php:507 msgid "Not active" msgstr "Nicht aktiv" -#: src/Wordpress/CustomPostType/Restriction.php:526 +#: src/Wordpress/CustomPostType/Restriction.php:508 msgid "Active" msgstr "Aktiv" -#: src/Wordpress/CustomPostType/Restriction.php:527 +#: src/Wordpress/CustomPostType/Restriction.php:509 msgid "Problem solved" msgstr "Problem gelöst" @@ -4272,7 +4272,7 @@ msgstr "Maximal %1$s Tage hintereinander buchbar." msgid "Bookings have to be made at least %1$s days in advance." msgstr "Buchungen müssen mindestens %1$s Tage im Voraus getätigt werden." -#: src/Wordpress/CustomPostType/Restriction.php:417 +#: src/Wordpress/CustomPostType/Restriction.php:399 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" diff --git a/languages/commonsbooking.pot b/languages/commonsbooking.pot index 8ea745181..f4dc42332 100644 --- a/languages/commonsbooking.pot +++ b/languages/commonsbooking.pot @@ -9,7 +9,7 @@ msgstr "" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2026-07-18T08:20:28+00:00\n" +"POT-Creation-Date: 2026-07-19T12:42:29+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.12.0\n" "X-Domain: commonsbooking\n" @@ -596,8 +596,8 @@ msgid "The color used for dark text on light backgrounds" msgstr "" #: includes/OptionsArray.php:644 -#: src/Wordpress/CustomPostType/Restriction.php:305 -#: src/Wordpress/CustomPostType/Restriction.php:326 +#: src/Wordpress/CustomPostType/Restriction.php:287 +#: src/Wordpress/CustomPostType/Restriction.php:308 #: templates/dashboard-index.php:47 msgid "Restrictions" msgstr "" @@ -1025,7 +1025,7 @@ msgstr "" #: includes/OptionsArray.php:1321 #: src/Wordpress/CustomPostType/Map.php:557 #: src/Wordpress/CustomPostType/Restriction.php:47 -#: src/Wordpress/CustomPostType/Restriction.php:415 +#: src/Wordpress/CustomPostType/Restriction.php:397 #: src/Wordpress/CustomPostType/Timeframe.php:98 #: src/Wordpress/CustomPostType/Timeframe.php:455 msgid "Type" @@ -1993,14 +1993,14 @@ msgstr "" #: src/View/Admin/Filter.php:58 #: src/Wordpress/CustomPostType/Booking.php:792 -#: src/Wordpress/CustomPostType/Restriction.php:451 +#: src/Wordpress/CustomPostType/Restriction.php:433 #: src/Wordpress/CustomPostType/Timeframe.php:678 msgid "Start date" msgstr "" #: src/View/Admin/Filter.php:62 #: src/Wordpress/CustomPostType/Booking.php:809 -#: src/Wordpress/CustomPostType/Restriction.php:461 +#: src/Wordpress/CustomPostType/Restriction.php:443 #: src/Wordpress/CustomPostType/Timeframe.php:702 msgid "End date" msgstr "" @@ -2033,7 +2033,7 @@ msgstr "" #: src/View/Booking.php:200 #: src/View/MassOperations.php:42 #: src/Wordpress/CustomPostType/Booking.php:986 -#: src/Wordpress/CustomPostType/Restriction.php:477 +#: src/Wordpress/CustomPostType/Restriction.php:459 msgid "Status" msgstr "" @@ -2153,7 +2153,7 @@ msgstr "" #: src/Wordpress/CustomPostType/Booking.php:1002 #: src/Wordpress/CustomPostType/Item.php:117 #: src/Wordpress/CustomPostType/Restriction.php:48 -#: src/Wordpress/CustomPostType/Restriction.php:438 +#: src/Wordpress/CustomPostType/Restriction.php:420 #: src/Wordpress/CustomPostType/Timeframe.php:99 #: templates/shortcode-bookings.php:73 msgid "Item" @@ -2165,7 +2165,7 @@ msgstr "" #: src/Wordpress/CustomPostType/Booking.php:998 #: src/Wordpress/CustomPostType/Location.php:139 #: src/Wordpress/CustomPostType/Restriction.php:49 -#: src/Wordpress/CustomPostType/Restriction.php:431 +#: src/Wordpress/CustomPostType/Restriction.php:413 #: src/Wordpress/CustomPostType/Timeframe.php:100 #: src/Wordpress/CustomPostType/Timeframe.php:463 #: templates/shortcode-bookings.php:75 @@ -2424,7 +2424,7 @@ msgstr "" #: src/Wordpress/CustomPostType/Booking.php:538 #: src/Wordpress/CustomPostType/Item.php:118 #: src/Wordpress/CustomPostType/Location.php:140 -#: src/Wordpress/CustomPostType/Restriction.php:307 +#: src/Wordpress/CustomPostType/Restriction.php:289 #: src/Wordpress/CustomPostType/Timeframe.php:1153 msgid "Add new" msgstr "" @@ -3486,81 +3486,81 @@ msgstr "" msgid "Filter By Status " msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:306 -#: src/Wordpress/CustomPostType/Restriction.php:387 +#: src/Wordpress/CustomPostType/Restriction.php:288 +#: src/Wordpress/CustomPostType/Restriction.php:369 msgid "Restriction" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:308 -#: src/Wordpress/CustomPostType/Restriction.php:310 +#: src/Wordpress/CustomPostType/Restriction.php:290 +#: src/Wordpress/CustomPostType/Restriction.php:292 msgid "Add new Restriction" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:309 +#: src/Wordpress/CustomPostType/Restriction.php:291 msgid "Edit Restriction" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:311 +#: src/Wordpress/CustomPostType/Restriction.php:293 msgid "Show Restriction" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:312 +#: src/Wordpress/CustomPostType/Restriction.php:294 msgid "Show Restrictions" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:313 +#: src/Wordpress/CustomPostType/Restriction.php:295 msgid "Search Restrictions" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:314 +#: src/Wordpress/CustomPostType/Restriction.php:296 msgid "Restrictions not found" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:315 +#: src/Wordpress/CustomPostType/Restriction.php:297 msgid "No Restrictions found in trash" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:316 +#: src/Wordpress/CustomPostType/Restriction.php:298 msgid "Parent Restrictions:" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:317 +#: src/Wordpress/CustomPostType/Restriction.php:299 msgid "All Restrictions" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:318 +#: src/Wordpress/CustomPostType/Restriction.php:300 msgid "Restriction archive" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:319 +#: src/Wordpress/CustomPostType/Restriction.php:301 msgid "Restriction attributes" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:320 +#: src/Wordpress/CustomPostType/Restriction.php:302 msgid "Add to Restriction" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:321 +#: src/Wordpress/CustomPostType/Restriction.php:303 msgid "Added to Restriction" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:322 +#: src/Wordpress/CustomPostType/Restriction.php:304 msgid "Restriction image" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:323 +#: src/Wordpress/CustomPostType/Restriction.php:305 msgid "set Restriction image" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:324 +#: src/Wordpress/CustomPostType/Restriction.php:306 msgid "remove Restriction image" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:325 +#: src/Wordpress/CustomPostType/Restriction.php:307 msgid "use as Restriction image" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:417 +#: src/Wordpress/CustomPostType/Restriction.php:399 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" @@ -3569,30 +3569,30 @@ msgid "" "\t\t\t\t" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:434 -#: src/Wordpress/CustomPostType/Restriction.php:441 +#: src/Wordpress/CustomPostType/Restriction.php:416 +#: src/Wordpress/CustomPostType/Restriction.php:423 #: src/Wordpress/CustomPostType/Timeframe.php:815 #: templates/shortcode-bookings.php:55 msgid "All" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:445 +#: src/Wordpress/CustomPostType/Restriction.php:427 msgid "Hint" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:447 +#: src/Wordpress/CustomPostType/Restriction.php:429 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/CustomPostType/Restriction.php:452 +#: src/Wordpress/CustomPostType/Restriction.php:434 msgid "Set the start date and time" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:462 +#: src/Wordpress/CustomPostType/Restriction.php:444 msgid "Set the estimated end date and time" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:480 +#: src/Wordpress/CustomPostType/Restriction.php:462 msgid "" "Choose status of this restriction.
      \n" "\t\t\t\tSet to None if you want to deactivate the restriction.
      \n" @@ -3602,31 +3602,31 @@ msgid "" "Select the desired status and then click the \"Send\" button to send the e-mail.
      " msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:495 +#: src/Wordpress/CustomPostType/Restriction.php:477 msgid "Send notification emails to users" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:496 +#: src/Wordpress/CustomPostType/Restriction.php:478 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/CustomPostType/Restriction.php:514 +#: src/Wordpress/CustomPostType/Restriction.php:496 msgid "Total breakdown" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:515 +#: src/Wordpress/CustomPostType/Restriction.php:497 msgid "Notice" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:525 +#: src/Wordpress/CustomPostType/Restriction.php:507 msgid "Not active" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:526 +#: src/Wordpress/CustomPostType/Restriction.php:508 msgid "Active" msgstr "" -#: src/Wordpress/CustomPostType/Restriction.php:527 +#: src/Wordpress/CustomPostType/Restriction.php:509 msgid "Problem solved" msgstr "" From 460c96fb9a95fea3aec36eaf3ce7830f7c7b8a59 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:52:23 +0000 Subject: [PATCH 135/148] Bump actions/setup-node from 6 to 7 Bumps [actions/setup-node](https://github.com/actions/setup-node) from 6 to 7. - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/setup-node dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build-docs.yml | 2 +- .github/workflows/compile.yml | 2 +- .github/workflows/prettier.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index c06819ef9..2553ce09a 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -31,7 +31,7 @@ jobs: fetch-depth: 0 - name: Setup Node - uses: actions/setup-node@v6 + uses: actions/setup-node@v7 with: node-version: 22 cache: npm diff --git a/.github/workflows/compile.yml b/.github/workflows/compile.yml index 4935a41ed..1a20ea05a 100644 --- a/.github/workflows/compile.yml +++ b/.github/workflows/compile.yml @@ -55,7 +55,7 @@ jobs: with: php-version: '8.1' - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: '.nvmrc' cache: 'npm' diff --git a/.github/workflows/prettier.yml b/.github/workflows/prettier.yml index 9e5dbe541..ed89b122d 100644 --- a/.github/workflows/prettier.yml +++ b/.github/workflows/prettier.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v7 - - uses: actions/setup-node@v6 + - uses: actions/setup-node@v7 with: node-version-file: '.nvmrc' - run: | From 3c898676f7a7fe29a775aa33c603fa79439d3dda Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:52:24 +0000 Subject: [PATCH 136/148] composer(deps-dev): bump wp-coding-standards/wpcs from 3.2.0 to 3.4.0 Bumps [wp-coding-standards/wpcs](https://github.com/WordPress/WordPress-Coding-Standards) from 3.2.0 to 3.4.0. - [Release notes](https://github.com/WordPress/WordPress-Coding-Standards/releases) - [Changelog](https://github.com/WordPress/WordPress-Coding-Standards/blob/develop/CHANGELOG.md) - [Commits](https://github.com/WordPress/WordPress-Coding-Standards/compare/3.2.0...3.4.0) --- updated-dependencies: - dependency-name: wp-coding-standards/wpcs dependency-version: 3.4.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- composer.lock | 66 +++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/composer.lock b/composer.lock index 6dc25b136..c022f5da1 100644 --- a/composer.lock +++ b/composer.lock @@ -2423,29 +2423,29 @@ "packages-dev": [ { "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v1.1.2", + "version": "v1.2.1", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/composer-installer.git", - "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1" + "reference": "963f0c67bffde0eac41b56be71ac0e8ba132f0bd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", - "reference": "e9cf5e4bbf7eeaf9ef5db34938942602838fc2b1", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/963f0c67bffde0eac41b56be71ac0e8ba132f0bd", + "reference": "963f0c67bffde0eac41b56be71ac0e8ba132f0bd", "shasum": "" }, "require": { "composer-plugin-api": "^2.2", "php": ">=5.4", - "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" + "squizlabs/php_codesniffer": "^3.1.0 || ^4.0" }, "require-dev": { "composer/composer": "^2.2", "ext-json": "*", "ext-zip": "*", "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcompatibility/php-compatibility": "^9.0", + "phpcompatibility/php-compatibility": "^9.0 || ^10.0.0@dev", "yoast/phpunit-polyfills": "^1.0" }, "type": "composer-plugin", @@ -2515,7 +2515,7 @@ "type": "thanks_dev" } ], - "time": "2025-07-17T20:45:56+00:00" + "time": "2026-05-06T08:26:05+00:00" }, { "name": "doctrine/annotations", @@ -3526,27 +3526,27 @@ }, { "name": "phpcsstandards/phpcsextra", - "version": "1.4.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHPCSExtra.git", - "reference": "fa4b8d051e278072928e32d817456a7fdb57b6ca" + "reference": "b598aa890815b8df16363271b659d73280129101" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/fa4b8d051e278072928e32d817456a7fdb57b6ca", - "reference": "fa4b8d051e278072928e32d817456a7fdb57b6ca", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/b598aa890815b8df16363271b659d73280129101", + "reference": "b598aa890815b8df16363271b659d73280129101", "shasum": "" }, "require": { "php": ">=5.4", - "phpcsstandards/phpcsutils": "^1.1.0", - "squizlabs/php_codesniffer": "^3.13.0 || ^4.0" + "phpcsstandards/phpcsutils": "^1.2.0", + "squizlabs/php_codesniffer": "^3.13.5 || ^4.0.1" }, "require-dev": { "php-parallel-lint/php-console-highlighter": "^1.0", "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcsstandards/phpcsdevcs": "^1.1.6", + "phpcsstandards/phpcsdevcs": "^1.2.0", "phpcsstandards/phpcsdevtools": "^1.2.1", "phpunit/phpunit": "^4.5 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" }, @@ -3604,32 +3604,32 @@ "type": "thanks_dev" } ], - "time": "2025-06-14T07:40:39+00:00" + "time": "2025-11-12T23:06:57+00:00" }, { "name": "phpcsstandards/phpcsutils", - "version": "1.1.0", + "version": "1.2.2", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHPCSUtils.git", - "reference": "65355670ac17c34cd235cf9d3ceae1b9252c4dad" + "reference": "c216317e96c8b3f5932808f9b0f1f7a14e3bbf55" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/65355670ac17c34cd235cf9d3ceae1b9252c4dad", - "reference": "65355670ac17c34cd235cf9d3ceae1b9252c4dad", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/c216317e96c8b3f5932808f9b0f1f7a14e3bbf55", + "reference": "c216317e96c8b3f5932808f9b0f1f7a14e3bbf55", "shasum": "" }, "require": { "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7 || ^1.0", "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.13.0 || ^4.0" + "squizlabs/php_codesniffer": "^3.13.5 || ^4.0.1" }, "require-dev": { "ext-filter": "*", "php-parallel-lint/php-console-highlighter": "^1.0", "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcsstandards/phpcsdevcs": "^1.1.6", + "phpcsstandards/phpcsdevcs": "^1.2.0", "yoast/phpunit-polyfills": "^1.1.0 || ^2.0.0 || ^3.0.0" }, "type": "phpcodesniffer-standard", @@ -3697,7 +3697,7 @@ "type": "thanks_dev" } ], - "time": "2025-06-12T04:32:33+00:00" + "time": "2025-12-08T14:27:58+00:00" }, { "name": "phpstan/extension-installer", @@ -6338,16 +6338,16 @@ }, { "name": "wp-coding-standards/wpcs", - "version": "3.2.0", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", - "reference": "d2421de7cec3274ae622c22c744de9a62c7925af" + "reference": "469c18ceab4d642b15bad4c65ebf3b307bfd55ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/d2421de7cec3274ae622c22c744de9a62c7925af", - "reference": "d2421de7cec3274ae622c22c744de9a62c7925af", + "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/469c18ceab4d642b15bad4c65ebf3b307bfd55ab", + "reference": "469c18ceab4d642b15bad4c65ebf3b307bfd55ab", "shasum": "" }, "require": { @@ -6355,17 +6355,17 @@ "ext-libxml": "*", "ext-tokenizer": "*", "ext-xmlreader": "*", - "php": ">=5.4", - "phpcsstandards/phpcsextra": "^1.4.0", - "phpcsstandards/phpcsutils": "^1.1.0", - "squizlabs/php_codesniffer": "^3.13.0" + "php": ">=7.2", + "phpcsstandards/phpcsextra": "^1.5.0", + "phpcsstandards/phpcsutils": "^1.2.2", + "squizlabs/php_codesniffer": "^3.13.5" }, "require-dev": { "php-parallel-lint/php-console-highlighter": "^1.0.0", "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcompatibility/php-compatibility": "^9.0", + "phpcompatibility/php-compatibility": "^10.0.0@dev", "phpcsstandards/phpcsdevtools": "^1.2.0", - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^8.0 || ^9.0" }, "suggest": { "ext-iconv": "For improved results", @@ -6400,7 +6400,7 @@ "type": "custom" } ], - "time": "2025-07-24T20:08:31+00:00" + "time": "2026-07-16T13:05:29+00:00" }, { "name": "yoast/phpunit-polyfills", From 99ed221e3a15232c7841e96168841de9ad2f8ca4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:52:59 +0000 Subject: [PATCH 137/148] composer(deps-dev): bump phpstan/phpstan from 2.2.2 to 2.2.5 Bumps [phpstan/phpstan](https://github.com/phpstan/phpstan-phar-composer-source) from 2.2.2 to 2.2.5. - [Commits](https://github.com/phpstan/phpstan-phar-composer-source/commits) --- updated-dependencies: - dependency-name: phpstan/phpstan dependency-version: 2.2.5 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- composer.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/composer.lock b/composer.lock index c022f5da1..91928c57e 100644 --- a/composer.lock +++ b/composer.lock @@ -3749,11 +3749,11 @@ }, { "name": "phpstan/phpstan", - "version": "2.2.2", + "version": "2.2.5", "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/e5cc34d491a90e79c216d824f60fe21fd4d93bd6", - "reference": "e5cc34d491a90e79c216d824f60fe21fd4d93bd6", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/909c1e5fef7989ac0d0c1c5c42e32a5c4f6198a0", + "reference": "909c1e5fef7989ac0d0c1c5c42e32a5c4f6198a0", "shasum": "" }, "require": { @@ -3809,7 +3809,7 @@ "type": "github" } ], - "time": "2026-06-05T09:00:01+00:00" + "time": "2026-07-05T06:31:06+00:00" }, { "name": "phpunit/php-code-coverage", From e40e014d4abec874db030f6c3a9026b2d83f3253 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:53:13 +0000 Subject: [PATCH 138/148] npm(deps-dev): bump @wordpress/env from 11.10.0 to 11.11.0 Bumps [@wordpress/env](https://github.com/WordPress/gutenberg/tree/HEAD/packages/env) from 11.10.0 to 11.11.0. - [Release notes](https://github.com/WordPress/gutenberg/releases) - [Changelog](https://github.com/WordPress/gutenberg/blob/trunk/packages/env/CHANGELOG.md) - [Commits](https://github.com/WordPress/gutenberg/commits/@wordpress/env@11.11.0/packages/env) --- updated-dependencies: - dependency-name: "@wordpress/env" dependency-version: 11.11.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 24 +++++++++++++++++++----- package.json | 2 +- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8323c9dc9..47e97007e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ }, "devDependencies": { "@babel/preset-env": "^7.29.7", - "@wordpress/env": "^11.10.0", + "@wordpress/env": "^11.11.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", "cypress": "^15.18.1", "editorconfig": "^3.0.2", @@ -4992,9 +4992,9 @@ } }, "node_modules/@wordpress/env": { - "version": "11.10.0", - "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-11.10.0.tgz", - "integrity": "sha512-y0q2RLJ3PsWHrRPt7bQbJauF/23JvCkfjBHRefJlGDZ49x1ma+UYQCrhT07G/05CYYJH2Sw6qC3Q4XYBKe7ASA==", + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-11.11.0.tgz", + "integrity": "sha512-E4Riaan41uAcm70FFTD78Z1qtObQJwRlIyXdsr04X+mrg8XkBuHSqM1iSvgqnOpVzUuF9EYANYKF0CTm9tKW5w==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { @@ -5006,7 +5006,7 @@ "cross-spawn": "^7.0.6", "docker-compose": "^0.24.3", "got": "^11.8.5", - "js-yaml": "^3.13.1", + "js-yaml": "^3.15.0", "ora": "^4.0.2", "rimraf": "^5.0.10", "simple-git": "^3.24.0", @@ -5138,6 +5138,20 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/@wordpress/env/node_modules/js-yaml": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.0.tgz", + "integrity": "sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, "node_modules/@wordpress/env/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", diff --git a/package.json b/package.json index 24b66c95e..d5b71dd0f 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ }, "devDependencies": { "@babel/preset-env": "^7.29.7", - "@wordpress/env": "^11.10.0", + "@wordpress/env": "^11.11.0", "commons-api": "git+https://github.com/wielebenwir/commons-api.git", "cypress": "^15.18.1", "editorconfig": "^3.0.2", From 03ae66ec0cfd68c66e600495a22d9e2622373a25 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 19 Jul 2026 15:53:30 +0000 Subject: [PATCH 139/148] npm(deps): bump vue from 3.5.39 to 3.5.40 Bumps [vue](https://github.com/vuejs/core) from 3.5.39 to 3.5.40. - [Release notes](https://github.com/vuejs/core/releases) - [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md) - [Commits](https://github.com/vuejs/core/compare/v3.5.39...v3.5.40) --- updated-dependencies: - dependency-name: vue dependency-version: 3.5.40 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- package-lock.json | 126 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 63 insertions(+), 65 deletions(-) diff --git a/package-lock.json b/package-lock.json index 47e97007e..98f645279 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "select2": "^4.1.0", "shufflejs": "^6.1.1", "spin.js": "^2.3.2", - "vue": "^3.5.39" + "vue": "^3.5.40" }, "devDependencies": { "@babel/preset-env": "^7.29.7", @@ -4656,13 +4656,13 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.5.39", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.39.tgz", - "integrity": "sha512-16KBTEXAJCpDr0mwlw+AZyhu8iyC7R3S2vBwsI7QnWJU6X3WKc9VKeNEZpiMdZ569qWhz9574L3vV55qRL0Vtw==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.40.tgz", + "integrity": "sha512-39E8IgOhTbVDnoJFMKc2DvYnypcZwUqgUhQkccva/0m6FUwtIKSGV7n1hpVmYcFaoRAwf9pBcwnKlCEsN63ZEQ==", "license": "MIT", "dependencies": { "@babel/parser": "^7.29.7", - "@vue/shared": "3.5.39", + "@vue/shared": "3.5.40", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" @@ -4681,40 +4681,40 @@ } }, "node_modules/@vue/compiler-dom": { - "version": "3.5.39", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.39.tgz", - "integrity": "sha512-oQPigALqYbNxTNPvNgSOe+czwVExfbVF02lz8jP0S3AXJiu3jxYDygNUiqSep4ezzW8XgnubqH63My2A7JR/vg==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.40.tgz", + "integrity": "sha512-pwkx4vqlqOspFstrcmzwkKLePVMD3PT65imRzLhanU2V1Fj4K13g6OXjanOyzw3aTAuRk84BOmY8f3rEHqPaVA==", "license": "MIT", "dependencies": { - "@vue/compiler-core": "3.5.39", - "@vue/shared": "3.5.39" + "@vue/compiler-core": "3.5.40", + "@vue/shared": "3.5.40" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.5.39", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.39.tgz", - "integrity": "sha512-d0ki86iOyN8LoZPBmk5SJWNwHP19CnDDCfuo//+2WJa2g5Ke0Jay983PIBIcSSzldC68I8DrD5GrHV3OSDfodg==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.40.tgz", + "integrity": "sha512-gIf497P4kpuALcvs5n3AEg1Vdn0pSY4XbjASIfHNYF1/MP3T2Mf2STERTubysBxCRxzJGJYtF/O7vwJrxFB3Vw==", "license": "MIT", "dependencies": { "@babel/parser": "^7.29.7", - "@vue/compiler-core": "3.5.39", - "@vue/compiler-dom": "3.5.39", - "@vue/compiler-ssr": "3.5.39", - "@vue/shared": "3.5.39", + "@vue/compiler-core": "3.5.40", + "@vue/compiler-dom": "3.5.40", + "@vue/compiler-ssr": "3.5.40", + "@vue/shared": "3.5.40", "estree-walker": "^2.0.2", "magic-string": "^0.30.21", - "postcss": "^8.5.15", + "postcss": "^8.5.19", "source-map-js": "^1.2.1" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.5.39", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.39.tgz", - "integrity": "sha512-Ce7/wvwMHai74bdszfXExdazFigYnlF9zgCmEQUcM1j0fOymlouZ7XilTYNo8oUjhlnjYOZbGrcYKuqjz89Ucw==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.40.tgz", + "integrity": "sha512-rrE5xiXG663+vHCHa3J9p2z5OcBRjXmoqenprJxAFQxg5pSshzeBiCE6pu46axapRJ2Adk0YDA2BRZVjiHXnhg==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.39", - "@vue/shared": "3.5.39" + "@vue/compiler-dom": "3.5.40", + "@vue/shared": "3.5.40" } }, "node_modules/@vue/devtools-api": { @@ -4751,53 +4751,51 @@ } }, "node_modules/@vue/reactivity": { - "version": "3.5.39", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.39.tgz", - "integrity": "sha512-TpsuBJ9gGlZa5d23XcM2y8EXanz9dZeVDQBXRwzy46ItgvM+rWpzs+UVM0wcRLxGvcav0HE5jz2gNL53xlRAog==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.40.tgz", + "integrity": "sha512-B7ot9UlUZOi1zbq61/LvE88ZLTV8IlajTdiZTAEiDQgrnIMIZoPr9kGw0Zw46ObW62O9+H/Be3kMbfb7kYPQZA==", "license": "MIT", "dependencies": { - "@vue/shared": "3.5.39" + "@vue/shared": "3.5.40" } }, "node_modules/@vue/runtime-core": { - "version": "3.5.39", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.39.tgz", - "integrity": "sha512-9GLtNyRvPAUMbX+7ono0RC2j0guo2LXVi8LvcmAooImACUKm0oFf0jjwbX8/H0AE/t1nxhAkn8RSl9PMCzzxZw==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.40.tgz", + "integrity": "sha512-KAZLweuZ6uUJPK1PMSQPgBU5gCjgrrfjUhSglmU9NhH+Zjepa8cnwSydPWDWHDwOgY4g3VcZ+PljbiHlURNCbw==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.39", - "@vue/shared": "3.5.39" + "@vue/reactivity": "3.5.40", + "@vue/shared": "3.5.40" } }, "node_modules/@vue/runtime-dom": { - "version": "3.5.39", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.39.tgz", - "integrity": "sha512-7Y6aAGboKcXAZ3ECuUy7RrS5yy2r47dhTp2SKaJmYxjopImaVFaNa5Ne66NwGovsrxVAl5S5rwc7m22UG7Lmww==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.40.tgz", + "integrity": "sha512-ZfrX8ssZQds900L9pr8AuK05ddnMsR4MPMZr8cPN9GoqoPWcXLhjvvbIA2SMv+7a97sJ1vv9pj/zxK0Cq/eEFQ==", "license": "MIT", "dependencies": { - "@vue/reactivity": "3.5.39", - "@vue/runtime-core": "3.5.39", - "@vue/shared": "3.5.39", + "@vue/reactivity": "3.5.40", + "@vue/runtime-core": "3.5.40", + "@vue/shared": "3.5.40", "csstype": "^3.2.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.5.39", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.39.tgz", - "integrity": "sha512-yZSakiAGw85rZfG7UM8akMnIF+FmeiNk47uvHf2nVBBSe+dIKUhZuZq9+XgJhbV3nS5Z4ALH23/MpXofW+mbcw==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.40.tgz", + "integrity": "sha512-XNJym9WpevhTVt1HuwOrCRJ5Q+9z4BjTMrDtjTrvx74SmUll8spNTw6whWJa9mEkO4PKn5TihI/bm/8ds2QVJw==", "license": "MIT", "dependencies": { - "@vue/compiler-ssr": "3.5.39", - "@vue/shared": "3.5.39" - }, - "peerDependencies": { - "vue": "3.5.39" + "@vue/compiler-ssr": "3.5.40", + "@vue/runtime-dom": "3.5.40", + "@vue/shared": "3.5.40" } }, "node_modules/@vue/shared": { - "version": "3.5.39", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.39.tgz", - "integrity": "sha512-l1rrBtBfTnmxvtsvdQDXltUUy8S1Y+ZaqdfUzmAnJkTd8Z8rv5v/ytW+TKiqEOWyHPoqtPlNFSs0lhRmYVSHVA==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.40.tgz", + "integrity": "sha512-WxnBtruIqOoV3rA4jeKDWzrYI5h7Cp4+pjwDi8kWGHz+IslhiN+wguLVVhtv2l8VoU02rzDCVfDjgCl1lNpZVg==", "license": "MIT" }, "node_modules/@vueuse/core": { @@ -12231,9 +12229,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.12", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", - "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", "funding": [ { "type": "github", @@ -13131,9 +13129,9 @@ } }, "node_modules/postcss": { - "version": "8.5.15", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", - "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "version": "8.5.20", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.20.tgz", + "integrity": "sha512-lW616l85ucIQL+FocMmL7pQFPqBmwejrCMg+iPxyImlrANNJG9NHq/RkyCZopDhd8C3LA03PHRJDjkbGu8vvug==", "funding": [ { "type": "opencollective", @@ -13150,7 +13148,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.12", + "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -17686,16 +17684,16 @@ } }, "node_modules/vue": { - "version": "3.5.39", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.39.tgz", - "integrity": "sha512-xmZCYabFGcirU8r0fTuvl/LICc1OU620rnqepaJDL/a141ZigkG7AyaxQLdqJ02ZRYzWe6YPaDHeQx7MfknQfA==", + "version": "3.5.40", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.40.tgz", + "integrity": "sha512-+8PJ4SJXdn/cHGImF4CKdxlWHIN5Dkt7DoufRREM6h6uVCx2m7QxgcEQmmzyOK8A9mcafg7sFbJFYsdFVubTig==", "license": "MIT", "dependencies": { - "@vue/compiler-dom": "3.5.39", - "@vue/compiler-sfc": "3.5.39", - "@vue/runtime-dom": "3.5.39", - "@vue/server-renderer": "3.5.39", - "@vue/shared": "3.5.39" + "@vue/compiler-dom": "3.5.40", + "@vue/compiler-sfc": "3.5.40", + "@vue/runtime-dom": "3.5.40", + "@vue/server-renderer": "3.5.40", + "@vue/shared": "3.5.40" }, "peerDependencies": { "typescript": "*" diff --git a/package.json b/package.json index d5b71dd0f..704a24cca 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,6 @@ "select2": "^4.1.0", "shufflejs": "^6.1.1", "spin.js": "^2.3.2", - "vue": "^3.5.39" + "vue": "^3.5.40" } } From f8ff5a2f81c40e38982b4548d7d8ac5c0b529a79 Mon Sep 17 00:00:00 2001 From: Chris Date: Sun, 19 Jul 2026 21:34:42 +0200 Subject: [PATCH 140/148] fix hash in git blame ignore revs file --- .git-blame-ignore-revs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 82e1dab9a..d644768a1 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -12,4 +12,6 @@ f8bdfd6d5d595f22d7c0345a2eb35571343ed134 2deacd97716f5a1128b8e5b7cf6bb9bdd161b4f8 # Apply last time before automatic action -102673ed5e3e2969090ce754aa97dde88bc7377d3046b32d5fff876a4687b0896322c0a22eb4310b +102673ed5e3e2969090ce754aa97dde88bc7377d + +3046b32d5fff876a4687b0896322c0a22eb4310b From 6413c3a5adf83cdd83a1fdb15d06f0d3994578a5 Mon Sep 17 00:00:00 2001 From: Hans Morbach <6433480+hansmorb@users.noreply.github.com> Date: Mon, 20 Jul 2026 14:34:11 +0200 Subject: [PATCH 141/148] bump strauss from 0.27.3 to 0.28.1 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 3392478a0..ba48bef23 100644 --- a/composer.json +++ b/composer.json @@ -78,7 +78,7 @@ "@prefix-namespaces" ], "prefix-namespaces": [ - "sh -c 'test -f ./bin/strauss.phar || curl -o bin/strauss.phar -L -C - https://github.com/BrianHenryIE/strauss/releases/download/0.27.3/strauss.phar'", + "sh -c 'test -f ./bin/strauss.phar || curl -o bin/strauss.phar -L -C - https://github.com/BrianHenryIE/strauss/releases/download/0.28.1/strauss.phar'", "@php bin/strauss.phar --info", "@composer dump-autoload" ] From 11a21f2c900db205b572c3ef6f28a906d45bdd32 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Jul 2026 20:36:01 +0200 Subject: [PATCH 142/148] Merge pull request #2263 from wielebenwir/dependabot/npm_and_yarn/systeminformation-5.31.17 npm(deps-dev): bump systeminformation from 5.31.5 to 5.31.17 --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 98f645279..7961ca403 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14724,9 +14724,9 @@ } }, "node_modules/systeminformation": { - "version": "5.31.5", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.31.5.tgz", - "integrity": "sha512-5SyLdip4/3alxD4Kh+63bUQTJmu7YMfYQTC+koZy7X73HgNqZSD2P4wOZQWtUncvPvcEmnfIjCoygN4MRoEejQ==", + "version": "5.31.17", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.31.17.tgz", + "integrity": "sha512-TvFA9iwDWlMjqZVlKIJ0Cy+Zgm9ttlMx0SMRwJDMNKyhlEKWBMb3+WRwDi/3dvHdWbexpos4Osp4U49p5WjB5g==", "dev": true, "license": "MIT", "os": [ From 1e64f0a7455b5e781bc00f60b76863448fdaa19d Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 18 Jul 2026 10:23:23 +0200 Subject: [PATCH 143/148] tests: add regression test for #1510 --- tests/php/PluginTest.php | 77 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/tests/php/PluginTest.php b/tests/php/PluginTest.php index ce7bfd027..9587fed77 100644 --- a/tests/php/PluginTest.php +++ b/tests/php/PluginTest.php @@ -6,11 +6,88 @@ use CommonsBooking\Plugin; use CommonsBooking\Tests\Wordpress\CustomPostTypeTest; use CommonsBooking\Wordpress\CustomPostType\CustomPostType; +use CommonsBooking\Wordpress\CustomPostType\Item; +use CommonsBooking\Wordpress\CustomPostType\Location; class PluginTest extends CustomPostTypeTest { private $postIDs = []; + + /** + * Regression test for wielebenwir/commonsbooking#1510. + * + * The item/location category submenu pages linked to + * edit-tags.php?taxonomy= without passing the post_type. Because of + * that, the "Anzahl" (count) column on the category overview built its link + * with the default `post` post type, so clicking it listed no items at all. + * + * The category menu URLs must carry the matching post_type so the overview + * (and the count link WordPress derives from the screen) target the correct + * custom post type. + * + * @return void + */ + public function testCategoryMenuPagesPassPostType() { + // The category submenus are only registered for admins. + $this->createAdministrator(); + wp_set_current_user( $this->adminUserID ); + + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + + // Start from a clean menu state so we only inspect what addMenuPages() registers. + global $menu, $submenu; + $menu = []; + $submenu = []; + + Plugin::addMenuPages(); + + $this->assertArrayHasKey( + 'cb-dashboard', + $submenu, + 'Expected commonsbooking submenu pages to be registered under cb-dashboard.' + ); + + $cases = [ + Item::getTaxonomyName() => Item::getPostType(), + Location::getTaxonomyName() => Location::getPostType(), + ]; + + foreach ( $cases as $taxonomy => $postType ) { + $menuSlug = null; + foreach ( $submenu['cb-dashboard'] as $entry ) { + // Index 2 holds the menu slug / URL of the submenu page. + if ( isset( $entry[2] ) && strpos( $entry[2], 'taxonomy=' . $taxonomy ) !== false ) { + $menuSlug = $entry[2]; + break; + } + } + + $this->assertNotNull( + $menuSlug, + sprintf( 'Category menu page for taxonomy "%s" was not registered.', $taxonomy ) + ); + + // Parse the query string to compare the actual param value. + $query = wp_parse_url( $menuSlug, PHP_URL_QUERY ); + parse_str( (string) $query, $params ); + + $this->assertArrayHasKey( + 'post_type', + $params, + sprintf( + 'Category menu URL for taxonomy "%s" is missing the post_type param (#1510): %s', + $taxonomy, + $menuSlug + ) + ); + $this->assertSame( + $postType, + $params['post_type'], + sprintf( 'Category menu URL for taxonomy "%s" points at the wrong post_type.', $taxonomy ) + ); + } + } public function testGetCustomPostTypes() { $this->assertIsArray( Plugin::getCustomPostTypes() ); // make sure, that we also have a model for each custom post type From 602554f882ebace1ef2fa8d0bebed6dcf282a642 Mon Sep 17 00:00:00 2001 From: Chris Date: Sat, 18 Jul 2026 10:25:04 +0200 Subject: [PATCH 144/148] Admin: fixes #1510 by adding post_type as URL param for item and location posts --- docs/de/documentation/first-steps/create-item.md | 6 ++++++ docs/de/documentation/first-steps/create-location.md | 5 +++++ readme.txt | 2 ++ src/Plugin.php | 4 ++-- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/de/documentation/first-steps/create-item.md b/docs/de/documentation/first-steps/create-item.md index 1697a2426..8385c43a3 100644 --- a/docs/de/documentation/first-steps/create-item.md +++ b/docs/de/documentation/first-steps/create-item.md @@ -1,6 +1,11 @@ # Artikel anlegen +:::tip Wofür nutze ich Kategorien? +Dieser WordPress Post-Typ kann mit einer [Kategorie](https://wordpress.org/documentation/article/posts-categories-screen/) konfiguriert werden. +Innerhalb von CommonsBooking kannst du Kategorien eines Artikels in den [Shortcodes](../administration/shortcodes) verwenden. +::: + **Beschreibung des Artikels** Nutze den großen Texteditor oben auf der Artikelseite nur für die @@ -29,3 +34,4 @@ Ergänze hier die Kurzversion der Artikelbeschreibung, diese wird in der Artikel Es ist möglich einen Artikel mit einem Passwort zu versehen. Klicke dafür neben "Status" auf der rechten Seite des Artikels und füge ein Passwort hinzu. Jetzt können Nutzende diesen Artikel nur buchen, wenn das korrekte Passwort eingegeben wurde. ![](/img/item-password.png){width="400"} + diff --git a/docs/de/documentation/first-steps/create-location.md b/docs/de/documentation/first-steps/create-location.md index 73a2672e7..6caf2e2ef 100644 --- a/docs/de/documentation/first-steps/create-location.md +++ b/docs/de/documentation/first-steps/create-location.md @@ -1,5 +1,9 @@ # Station anlegen +:::tip Wofür nutze ich Kategorien? +Dieser WordPress Post-Typ kann mit einer [Kategorie](https://wordpress.org/documentation/article/posts-categories-screen/) konfiguriert werden. +Innerhalb von CommonsBooking kannst du Kategorien einer Station in den [Shortcodes](../administration/shortcodes) verwenden. +::: ## Stationsbeschreibung @@ -88,3 +92,4 @@ würde_ ) ![](/img/overbooking-countone.png){data-zoomable} _Nur der erste Tag wird bei der Überbuchung gezählt: Das Wochenende ist somit überbuchbar aber es kann nicht bis Dienstag gebucht werden._ + diff --git a/readme.txt b/readme.txt index a015a70f2..cc1911709 100644 --- a/readme.txt +++ b/readme.txt @@ -81,6 +81,8 @@ CommonsBooking was developed for the ["Commons Cargobike" movement](http://commo ## Changelog +FIXED: Admin list for items and locations are able to filter by their respective category + ### 2.11 (13.07.2026) ADDED: GBFS routes vehicle_availability.json, vehicle_types.json, vehicle_status.json ADDED: Multi-select now also available for timeframes of type repair diff --git a/src/Plugin.php b/src/Plugin.php index afabfc622..78d064041 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -384,7 +384,7 @@ public static function addMenuPages() { esc_html__( 'Item Categories', 'commonsbooking' ), esc_html__( 'Item Categories', 'commonsbooking' ), 'manage_' . COMMONSBOOKING_PLUGIN_SLUG, - admin_url( 'edit-tags.php' ) . '?taxonomy=' . Item::getTaxonomyName(), + admin_url( 'edit-tags.php' ) . '?taxonomy=' . Item::getTaxonomyName() . '&post_type=' . Item::getPostType(), '' ); @@ -394,7 +394,7 @@ public static function addMenuPages() { esc_html__( 'Location Categories', 'commonsbooking' ), esc_html__( 'Location Categories', 'commonsbooking' ), 'manage_' . COMMONSBOOKING_PLUGIN_SLUG, - admin_url( 'edit-tags.php' ) . '?taxonomy=' . Location::getTaxonomyName(), + admin_url( 'edit-tags.php' ) . '?taxonomy=' . Location::getTaxonomyName() . '&post_type=' . Location::getPostType(), '' ); From 4ec5d9e8a01d940005ffde3d82a6dc3636a9266f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Jul 2026 22:55:15 +0000 Subject: [PATCH 145/148] npm(deps-dev): bump websocket-driver from 0.7.4 to 0.7.5 Bumps [websocket-driver](https://github.com/faye/websocket-driver-node) from 0.7.4 to 0.7.5. - [Changelog](https://github.com/faye/websocket-driver-node/blob/main/CHANGELOG.md) - [Commits](https://github.com/faye/websocket-driver-node/compare/0.7.4...0.7.5) --- updated-dependencies: - dependency-name: websocket-driver dependency-version: 0.7.5 dependency-type: indirect ... Signed-off-by: dependabot[bot] --- package-lock.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7961ca403..1c5d199dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17721,10 +17721,11 @@ } }, "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.5.tgz", + "integrity": "sha512-ZL2+3c7kMBdIRCMz6l8jQMHyGVxj+UL+xVk74Ombiciboca8rHa15L86B19E5oh1pL9Ii/uj54gtsIrZGMo6zA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", From da9688c9282afe55cf69ccfbbeabdf28278605e3 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 28 Jul 2026 08:21:20 +0000 Subject: [PATCH 146/148] Show "Exclude from API" item field only when API is globally enabled The "Exclude from API" checkbox on items was always rendered for admins and CB managers, even on installations where the API is not activated, where the setting has no effect and only adds confusion. Use CMB2's per-field `show_on_cb` callback (the same mechanism already used elsewhere in the codebase) to render the field only when the global `api-activated` option is enabled. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_0141agmYhtt3qtArniEvevwj --- src/Wordpress/CustomPostType/Item.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Wordpress/CustomPostType/Item.php b/src/Wordpress/CustomPostType/Item.php index cea8b3d12..b964369c1 100644 --- a/src/Wordpress/CustomPostType/Item.php +++ b/src/Wordpress/CustomPostType/Item.php @@ -282,12 +282,16 @@ public function registerMetabox() { ); // checkbox if item should be excluded from API shares + // only shown when the API is globally activated in the settings $cmb->add_field( array( 'name' => esc_html__( 'Exclude from API', 'commonsbooking' ), 'desc' => esc_html__( 'When this box is checked, the item will not appear in any of the API shares.', 'commonsbooking' ), 'id' => COMMONSBOOKING_METABOX_PREFIX . 'api_exclude', 'type' => 'checkbox', + 'show_on_cb' => function () { + return Settings::getOption( 'commonsbooking_options_api', 'api-activated' ) === 'on'; + }, ) ); } From e9ff1cc43bfc5a17fe939199c646a2522dd3efc9 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 28 Jul 2026 12:30:22 +0000 Subject: [PATCH 147/148] Factor out API feature check and shared meta field key into abstractions Introduce two small abstractions to remove scattered raw setting/meta string literals around the API: - `Helper\Feature`: named boolean feature-flag methods (`isApiEnabled()`, `isApiAnonymousAccessAllowed()`) wrapping the `commonsbooking_options_api` option keys, so call sites express intent instead of comparing a raw option value to `'on'`. - `Wordpress\CustomPostType\MetaField`: a backed enum holding shared meta field keys; `getFieldId()` prepends COMMONSBOOKING_METABOX_PREFIX so the full key stays defined in one place. Refactor the existing call sites (Plugin route registration, API BaseRoute permission check, item metabox visibility, and the item API-exclude reads in ItemsRoute and the GBFS routes) to use these. Behavior is unchanged: the enum value resolves to the same `_cb_api_exclude` key and the feature methods match the previous truthiness checks. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_0141agmYhtt3qtArniEvevwj --- src/API/BaseRoute.php | 6 ++-- src/API/GBFS/BaseRoute.php | 3 +- src/API/GBFS/StationStatus.php | 3 +- src/API/ItemsRoute.php | 3 +- src/Helper/Feature.php | 35 ++++++++++++++++++++++ src/Plugin.php | 4 +-- src/Wordpress/CustomPostType/Item.php | 5 ++-- src/Wordpress/CustomPostType/MetaField.php | 29 ++++++++++++++++++ 8 files changed, 78 insertions(+), 10 deletions(-) create mode 100644 src/Helper/Feature.php create mode 100644 src/Wordpress/CustomPostType/MetaField.php diff --git a/src/API/BaseRoute.php b/src/API/BaseRoute.php index 8d9e16012..a9824fab3 100644 --- a/src/API/BaseRoute.php +++ b/src/API/BaseRoute.php @@ -6,8 +6,8 @@ use Exception; use RuntimeException; +use CommonsBooking\Helper\Feature; use CommonsBooking\Repository\ApiShares; -use CommonsBooking\Settings\Settings; use CommonsBooking\Opis\JsonSchema\Validator; use CommonsBooking\Opis\JsonSchema\Errors\ErrorFormatter; use WP_REST_Controller; @@ -199,8 +199,8 @@ protected function decodeApiTitle( string $title ): string { * @return bool */ public static function hasPermission(): bool { - $isApiActive = Settings::getOption( 'commonsbooking_options_api', 'api-activated' ); - $anonymousAccessAllowed = Settings::getOption( 'commonsbooking_options_api', 'apikey_not_required' ); + $isApiActive = Feature::isApiEnabled(); + $anonymousAccessAllowed = Feature::isApiAnonymousAccessAllowed(); $apiKey = array_key_exists( self::API_KEY_PARAM, $_REQUEST ) ? sanitize_text_field( $_REQUEST[ self::API_KEY_PARAM ] ) : false; if ( ! $apiKey ) { // get apikey from headers (#2251) diff --git a/src/API/GBFS/BaseRoute.php b/src/API/GBFS/BaseRoute.php index a708363f4..cc17cc5ba 100644 --- a/src/API/GBFS/BaseRoute.php +++ b/src/API/GBFS/BaseRoute.php @@ -5,6 +5,7 @@ use CommonsBooking\Repository\Location; use CommonsBooking\Repository\PostRepository; +use CommonsBooking\Wordpress\CustomPostType\MetaField; use Exception; use stdClass; use WP_REST_Request; @@ -54,7 +55,7 @@ public function getItemData( $request ): array { $items = static::getRepository()::get(); foreach ( $items as $item ) { - if ( $item->getMeta( COMMONSBOOKING_METABOX_PREFIX . 'api_exclude' ) == 'on' ) { + if ( $item->getMeta( MetaField::ItemApiExclude->getFieldId() ) == 'on' ) { continue; } try { diff --git a/src/API/GBFS/StationStatus.php b/src/API/GBFS/StationStatus.php index 6c0f8156e..b8badd899 100644 --- a/src/API/GBFS/StationStatus.php +++ b/src/API/GBFS/StationStatus.php @@ -5,6 +5,7 @@ use CommonsBooking\Model\Location; use CommonsBooking\Repository\Item; +use CommonsBooking\Wordpress\CustomPostType\MetaField; use stdClass; use WP_REST_Response; @@ -35,7 +36,7 @@ public function prepare_item_for_response( $location, $request ): WP_REST_Respon $availableItems = count( array_filter( Item::getByLocation( $location->ID, true ), - fn( $item ) => $item->isCurrentlyFreeAtLocation( $location->ID, true ) && $item->getMeta( COMMONSBOOKING_METABOX_PREFIX . 'api_exclude' ) != 'on' + fn( $item ) => $item->isCurrentlyFreeAtLocation( $location->ID, true ) && $item->getMeta( MetaField::ItemApiExclude->getFieldId() ) != 'on' ) ); diff --git a/src/API/ItemsRoute.php b/src/API/ItemsRoute.php index 410732222..83bac2f39 100644 --- a/src/API/ItemsRoute.php +++ b/src/API/ItemsRoute.php @@ -4,6 +4,7 @@ namespace CommonsBooking\API; use CommonsBooking\Repository\Item; +use CommonsBooking\Wordpress\CustomPostType\MetaField; use stdClass; use WP_Error; use WP_REST_Request; @@ -52,7 +53,7 @@ public function getItemData( $request ): stdClass { $items = Item::get( $args ); foreach ( $items as $item ) { $itemdata = $this->prepare_item_for_response( $item, $request ); - if ( $item->getMeta( COMMONSBOOKING_METABOX_PREFIX . 'api_exclude' ) == 'on' ) { + if ( $item->getMeta( MetaField::ItemApiExclude->getFieldId() ) == 'on' ) { continue; } $data->items[] = $itemdata->get_data(); diff --git a/src/Helper/Feature.php b/src/Helper/Feature.php new file mode 100644 index 000000000..ff4bff4ff --- /dev/null +++ b/src/Helper/Feature.php @@ -0,0 +1,35 @@ + esc_html__( 'Exclude from API', 'commonsbooking' ), 'desc' => esc_html__( 'When this box is checked, the item will not appear in any of the API shares.', 'commonsbooking' ), - 'id' => COMMONSBOOKING_METABOX_PREFIX . 'api_exclude', + 'id' => MetaField::ItemApiExclude->getFieldId(), 'type' => 'checkbox', 'show_on_cb' => function () { - return Settings::getOption( 'commonsbooking_options_api', 'api-activated' ) === 'on'; + return Feature::isApiEnabled(); }, ) ); diff --git a/src/Wordpress/CustomPostType/MetaField.php b/src/Wordpress/CustomPostType/MetaField.php new file mode 100644 index 000000000..58c644fff --- /dev/null +++ b/src/Wordpress/CustomPostType/MetaField.php @@ -0,0 +1,29 @@ +value; + } +} From f0694568287b269a5007635150350e6f1246c5fb Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 29 Jul 2026 07:19:34 +0000 Subject: [PATCH 148/148] Add separate enable flags for the Commons API and GBFS API The API was previously all-or-nothing: the single "Activate API" switch registered every route (Commons API and GBFS) together. Add per-API flags so each family can be turned off independently while the API stays active. - Two new settings on the API tab: "Disable Commons API" and "Disable GBFS API". - `Feature::isCommonsApiEnabled()` / `Feature::isGbfsEnabled()` gate the respective route groups in `Plugin::initRoutes()`. The flags are opt-out (disable) rather than opt-in on purpose: an unset value reads as "not disabled", so existing installations (and installs that predate the flags) keep both APIs registered without a migration. A positive "enable" checkbox would read as empty/off on upgrade and silently drop live endpoints. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_0141agmYhtt3qtArniEvevwj --- includes/OptionsArray.php | 12 ++++++++++ src/Helper/Feature.php | 30 +++++++++++++++++++++++++ src/Plugin.php | 47 ++++++++++++++++++++++++++------------- 3 files changed, 74 insertions(+), 15 deletions(-) diff --git a/includes/OptionsArray.php b/includes/OptionsArray.php index 0601828bc..75a9a814b 100644 --- a/includes/OptionsArray.php +++ b/includes/OptionsArray.php @@ -1451,6 +1451,18 @@ 'id' => 'apikey_not_required', 'type' => 'checkbox', ), + array( + 'name' => esc_html__( 'Disable Commons API', 'commonsbooking' ), + 'desc' => commonsbooking_sanitizeHTML( __( 'If selected, the Commons API endpoints (availability, items, locations, projects) are not registered, while the rest of the API stays active.', 'commonsbooking' ) ), + 'id' => 'commons-api-disabled', + 'type' => 'checkbox', + ), + array( + 'name' => esc_html__( 'Disable GBFS API', 'commonsbooking' ), + 'desc' => commonsbooking_sanitizeHTML( __( 'If selected, the GBFS API endpoints (gbfs.json, station and vehicle feeds) are not registered, while the rest of the API stays active.', 'commonsbooking' ) ), + 'id' => 'gbfs-api-disabled', + 'type' => 'checkbox', + ), array( // Repeatable group -> API Shares diff --git a/src/Helper/Feature.php b/src/Helper/Feature.php index ff4bff4ff..7e4947920 100644 --- a/src/Helper/Feature.php +++ b/src/Helper/Feature.php @@ -24,6 +24,36 @@ public static function isApiEnabled(): bool { return Settings::getOption( 'commonsbooking_options_api', 'api-activated' ) === 'on'; } + /** + * Whether the Commons API endpoints (availability, items, locations, + * projects) should be registered. + * + * Requires the API to be globally enabled and the Commons API not to be + * explicitly disabled. The disable flag is opt-out, so an unset value + * (e.g. on installations that predate the flag) keeps the endpoints active. + * + * @return bool + */ + public static function isCommonsApiEnabled(): bool { + return self::isApiEnabled() + && Settings::getOption( 'commonsbooking_options_api', 'commons-api-disabled' ) !== 'on'; + } + + /** + * Whether the GBFS API endpoints (gbfs.json, station and vehicle feeds) + * should be registered. + * + * Requires the API to be globally enabled and the GBFS API not to be + * explicitly disabled. The disable flag is opt-out, so an unset value + * (e.g. on installations that predate the flag) keeps the endpoints active. + * + * @return bool + */ + public static function isGbfsEnabled(): bool { + return self::isApiEnabled() + && Settings::getOption( 'commonsbooking_options_api', 'gbfs-api-disabled' ) !== 'on'; + } + /** * Whether the API may be accessed without a valid API key. * diff --git a/src/Plugin.php b/src/Plugin.php index 3f5da79e1..d835e617d 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -912,21 +912,38 @@ public function initRoutes() { add_action( 'rest_api_init', function () { - $routes = [ - new \CommonsBooking\API\AvailabilityRoute(), - new \CommonsBooking\API\ItemsRoute(), - new \CommonsBooking\API\LocationsRoute(), - // new \CommonsBooking\API\OwnersRoute(), - new \CommonsBooking\API\ProjectsRoute(), - new \CommonsBooking\API\GBFS\Discovery(), - new \CommonsBooking\API\GBFS\StationInformation(), - new \CommonsBooking\API\GBFS\StationStatus(), - new \CommonsBooking\API\GBFS\VehicleAvailability(), - new \CommonsBooking\API\GBFS\VehicleStatus(), - new \CommonsBooking\API\GBFS\VehicleTypes(), - new \CommonsBooking\API\GBFS\SystemInformation(), - - ]; + $routes = []; + + // Commons API routes + if ( Feature::isCommonsApiEnabled() ) { + $routes = array_merge( + $routes, + [ + new \CommonsBooking\API\AvailabilityRoute(), + new \CommonsBooking\API\ItemsRoute(), + new \CommonsBooking\API\LocationsRoute(), + // new \CommonsBooking\API\OwnersRoute(), + new \CommonsBooking\API\ProjectsRoute(), + ] + ); + } + + // GBFS API routes + if ( Feature::isGbfsEnabled() ) { + $routes = array_merge( + $routes, + [ + new \CommonsBooking\API\GBFS\Discovery(), + new \CommonsBooking\API\GBFS\StationInformation(), + new \CommonsBooking\API\GBFS\StationStatus(), + new \CommonsBooking\API\GBFS\VehicleAvailability(), + new \CommonsBooking\API\GBFS\VehicleStatus(), + new \CommonsBooking\API\GBFS\VehicleTypes(), + new \CommonsBooking\API\GBFS\SystemInformation(), + ] + ); + } + foreach ( $routes as $route ) { $route->register_routes(); }