summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Rehnelt <noreply@maennchen1.de>2026-10-03 17:56:56 +0200
committerRoger Rehnelt <noreply@maennchen1.de>2026-10-03 17:56:56 +0200
commitc5a04225526941059a15dc7e7af362882a07942c (patch)
tree482abdf6e0b43fc1039b18badd0efdcb2f0100ea
parent5c4bd30cf46b1bdbfdaed50c5d534bb8bfa1e143 (diff)
Produktfilter: filtert die Produktkacheln über alle Seiten
Sortiment und Kategorieseiten zeigen den Filter als Leiste über den Kacheln, am Handy zugeklappt; Seitenzahlen und Trefferzahl beziehen sich auf das gefilterte Ergebnis. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
-rw-r--r--views/css/wpsg-theme.css13
-rw-r--r--views/mods/mod_productview/productview.js22
-rw-r--r--views/mods/mod_productview/productview_filter.phtml12
3 files changed, 41 insertions, 6 deletions
diff --git a/views/css/wpsg-theme.css b/views/css/wpsg-theme.css
index e5d6727..4515211 100644
--- a/views/css/wpsg-theme.css
+++ b/views/css/wpsg-theme.css
@@ -649,6 +649,19 @@ html body .wpsg_product_garan_wrap a.wpsg_product_garan img { display:block; max
/* Blöcke: Produktliste, Mini-Warenkorb, Kundenkonto */
.wpsg-block-product-list :where(.wpsg-product-list__count) { margin:0 0 var(--wpsg-gap); }
.wpsg-block-product-list :where(.wpsg-product-list__count:empty) { display:none; }
+/* Produktkacheln (Abfrage-Schleife, Kategorievorlage): Statuszeile des Filters und Filter als Leiste über den Kacheln */
+.wpsg-product-tiles :where(.wpsg-product-list__count) { margin:0 0 var(--wpsg-gap); }
+.wpsg-product-tiles :where(.wpsg-product-list__count:empty) { display:none; }
+.wpsg-product-tiles :where(.wpsg-block-product-filter) { margin:0 0 calc(var(--wpsg-gap) * 2) 0; }
+.wpsg-product-tiles :where(.wpsg-pvf__fields) { display:flex; flex-wrap:wrap; align-items:flex-start; gap:var(--wpsg-gap) calc(var(--wpsg-gap) * 2); margin-top:var(--wpsg-gap); }
+.wpsg-product-tiles :where(.wpsg-pvf__fields > .wpsg-pvf__item) { margin:0; }
+.wpsg-product-tiles :where(.wpsg-pvf__fields > .wpsg-pvf__actions) { align-self:flex-end; }
+.wpsg-pvf__summary { display:inline-flex; list-style:none; cursor:pointer; }
+.wpsg-pvf__summary::-webkit-details-marker { display:none; }
+@media (min-width:782px) {
+ .wpsg-pvf__toggle > .wpsg-pvf__summary { display:none; }
+ .wpsg-product-tiles :where(.wpsg-pvf__fields) { margin-top:0; }
+}
.wpsg-block-product-list :where(.wpsg-product-list__items) { display:grid; grid-template-columns:repeat(var(--wpsg-columns, 3), minmax(0, 1fr)); gap:calc(var(--wpsg-gap) * 2) var(--wpsg-gap); list-style:none; margin:0; padding:0; }
.wpsg-block-product-list :where(.wpsg-product-list__item) { display:flex; flex-direction:column; gap:0.5em; min-width:0; margin:0; padding:0; }
.wpsg-block-product-list :where(.wpsg-product-list__image img) { display:block; width:100%; height:auto; }
diff --git a/views/mods/mod_productview/productview.js b/views/mods/mod_productview/productview.js
index 34c0df9..fc58ec8 100644
--- a/views/mods/mod_productview/productview.js
+++ b/views/mods/mod_productview/productview.js
@@ -4,8 +4,9 @@
* Ohne JavaScript funktionieren Links und Formulare über die Adresse. Mit JavaScript holt das Skript die Ansicht per
* Ajax (wpsg_mod=wpsg_mod_productview, wpsg_action=refresh) und schreibt den Zustand in die Adresse. Die Attribute des
* Shortcodes kommen signiert aus dem Feld wpsg_atts; der Server übernimmt nur Seite, Sortierung, Ansicht und Filter.
- * Produktlisten mit data-wpsg-filter (Block Produktliste) holt es mit der neuen Adresse als ganze Seite, wie ohne
- * JavaScript, und tauscht ihren Inhalt; die Statuszeile bleibt stehen und sagt die neue Anzahl an.
+ * Produktlisten mit data-wpsg-filter (Block Produktliste, Produktkacheln) holt es mit der neuen Adresse als ganze Seite,
+ * wie ohne JavaScript, und tauscht ihren Inhalt; die Statuszeile und ein Filter darin bleiben stehen, damit Ansage und
+ * Fokus erhalten bleiben.
*/
( function() {
@@ -156,12 +157,13 @@
lists.forEach( function( list, i ) {
- const status = list.querySelector( '.wpsg-product-list__count' );
+ const status = list.querySelector( ':scope > .wpsg-product-list__count' );
+ const keep = function( child ) { return child.classList.contains( 'wpsg-product-list__count' ) || child.classList.contains( 'wpsg-block-product-filter' ); };
- Array.prototype.slice.call( list.children ).forEach( function( child ) { if ( child !== status ) child.remove(); } );
- Array.prototype.slice.call( fresh[ i ].children ).forEach( function( child ) { if ( !child.classList.contains( 'wpsg-product-list__count' ) ) list.appendChild( document.importNode( child, true ) ); } );
+ Array.prototype.slice.call( list.children ).forEach( function( child ) { if ( !keep( child ) ) child.remove(); } );
+ Array.prototype.slice.call( fresh[ i ].children ).forEach( function( child ) { if ( !keep( child ) ) list.appendChild( document.importNode( child, true ) ); } );
- const freshStatus = fresh[ i ].querySelector( '.wpsg-product-list__count' );
+ const freshStatus = fresh[ i ].querySelector( ':scope > .wpsg-product-list__count' );
if ( status && freshStatus ) status.textContent = freshStatus.textContent;
list.removeAttribute( 'aria-busy' );
@@ -204,4 +206,12 @@
// Mit JavaScript sortiert die Auswahl sofort
document.querySelectorAll( '.wpsg-pv__order-submit' ).forEach( function( b ) { b.hidden = true; } );
+ // Filterleiste der Produktkacheln: am Handy zugeklappt, breit immer offen (Grenze wie WordPress, 782 px)
+ const narrow = window.matchMedia( '(max-width: 781px)' );
+
+ function toggleBar() { document.querySelectorAll( '.wpsg-pvf__toggle' ).forEach( function( d ) { d.open = !narrow.matches; } ); }
+
+ toggleBar();
+ narrow.addEventListener( 'change', toggleBar );
+
} )();
diff --git a/views/mods/mod_productview/productview_filter.phtml b/views/mods/mod_productview/productview_filter.phtml
index 121159a..1cf98da 100644
--- a/views/mods/mod_productview/productview_filter.phtml
+++ b/views/mods/mod_productview/productview_filter.phtml
@@ -25,6 +25,13 @@
<input type="hidden" name="<?php echo esc_attr($param); ?>" value="<?php echo esc_attr($value); ?>" />
<?php } ?>
+ <?php /* Leiste über den Produktkacheln: am Handy unter „Filter“ zugeklappt (productview.js), breit offen */ $bBar = (($this->view['wpsg_mod_productview_filter']['bar']??false) === true); ?>
+ <?php if ($bBar) { ?>
+ <details class="wpsg-pvf__toggle" open>
+ <summary class="wpsg-pvf__summary wpsg_button<?php echo wpsg_button_class(); ?>"><?php echo esc_html__('Filter', 'wpsg'); ?></summary>
+ <div class="wpsg-pvf__fields">
+ <?php } ?>
+
<?php foreach ($this->view['showFilter'] as $filter) { ?>
<?php if ($filter['type'] === 'catfilter') { ?>
@@ -81,4 +88,9 @@
<?php } ?>
</div>
+ <?php if ($bBar) { ?>
+ </div>
+ </details>
+ <?php } ?>
+
</form>