From 22d0b9c46c8c826503d339f9165c9ecb543abe86 Mon Sep 17 00:00:00 2001 From: Paul NGOUAH MAVIANE Date: Tue, 24 Mar 2026 17:05:01 +0100 Subject: [PATCH] Add display mode to choose between select or checkboxes --- classes/monthly.php | 270 +++++++++++++++++++++++++++++++++++++++----- facetwp-monthly.php | 6 +- 2 files changed, 247 insertions(+), 29 deletions(-) diff --git a/classes/monthly.php b/classes/monthly.php index 73bbf01..6147fec 100644 --- a/classes/monthly.php +++ b/classes/monthly.php @@ -1,11 +1,49 @@ 'checkboxes', + ); function __construct() { $this->label = __( 'Monthly Archive', 'fwp' ); } + /** + * FacetWP admin passes facet types through json_encode() as FWP.facet_types. + * + * The parent FacetWP_Facet declares public $fields = array(). That empty array makes the + * FacetWP 3.9+ Vue admin treat this type as using registered field groups only: it never + * injects settings_html() (FWP.clone), and it Vue.delete()s every facet key not in the + * combined whitelist — so label_any, orderby, count, display_mode disappear. + * + * Serializing without a `fields` key restores the legacy behaviour (same as pre-extend + * FacetWP_Facet_Monthly on master): facet-settings falls back to FWP.clone + v-model parsing. + * + * @return array + */ + public function jsonSerialize() { + return array( + 'label' => $this->label, + ); + } + + /** + * Whether the facet uses checkbox (multi) UI. + * + * @param array $facet Facet settings. + * @return bool + */ + protected function is_checkbox_display_mode( $facet ) { + return empty( $facet['display_mode'] ) || 'select' !== $facet['display_mode']; + } + /** * Load the available choices */ @@ -14,10 +52,15 @@ function load_values( $params ) { $facet = $params['facet']; - // Where - $where_clause = $params['where_clause']; + if ( $this->is_checkbox_display_mode( $facet ) ) { + // Same as FacetWP checkboxes in OR mode: drop this facet's selection from the + // post_id constraint so every month stays listed while selecting several. + $where_clause = $this->get_where_clause( $facet ); + } else { + // Select / dropdown: standard constraint (historical behaviour on master). + $where_clause = $params['where_clause']; + } - // Orderby $orderby = 'f.facet_display_value DESC'; if ( ! empty( $facet['orderby'] ) && 'asc' === $facet['orderby'] ) { $orderby = 'f.facet_display_value ASC'; @@ -48,32 +91,94 @@ function load_values( $params ) { */ function render( $params ) { + $facet = $params['facet']; + + if ( $this->is_checkbox_display_mode( $facet ) ) { + return $this->render_checkboxes( $params ); + } + + return $this->render_select( $params ); + } + + /** + * Checkbox markup (multi-select, OR filter). + * + * @param array $params Render params. + * @return string + */ + protected function render_checkboxes( $params ) { + $output = ''; + $facet = $params['facet']; + $values = (array) $params['values']; + $selected_values = (array) $params['selected_values']; + + foreach ( $values as $result ) { + $is_selected = in_array( $result['facet_value'], $selected_values, true ); + $classes = 'facetwp-checkbox'; + if ( $is_selected ) { + $classes .= ' checked'; + } + + $label = ucfirst( date_i18n( 'F Y', strtotime( $result['facet_display_value'] ) ) ); + $label = apply_filters( + 'facetwp_facet_display_value', + $label, + array( + 'selected' => $is_selected, + 'facet' => $facet, + 'row' => $result, + ) + ); + + $output .= ''; + } + + return $output; + } + + /** + * Select markup (single choice), same behaviour as legacy master branch. + * + * @param array $params Render params. + * @return string + */ + protected function render_select( $params ) { $output = ''; $facet = $params['facet']; $values = (array) $params['values']; $selected_values = (array) $params['selected_values']; - $label_any = empty( $facet['label_any'] ) ? __( 'Any', 'fwp' ) : sprintf( __( '%s', 'fwp' ), $facet['label_any'] ); + $label_any = empty( $facet['label_any'] ) ? __( 'Any', 'fwp' ) : $facet['label_any']; - // Setting classes for the select element. $select_classes = empty( $selected_values ) ? 'facetwp-monthly facetwp-monthly-default' : 'facetwp-monthly'; - // Building select HTML element for the facet backend. - $output .= ''; $output .= sprintf( '', esc_html( $label_any ) ); foreach ( $values as $result ) { - $selected = in_array( $result['facet_value'], $selected_values ) ? ' selected' : ''; + $selected = in_array( $result['facet_value'], $selected_values, true ) ? ' selected' : ''; $display_value = date_i18n( 'F Y', strtotime( $result['facet_display_value'] ) ); - // Determine whether to show counts + $display_value = apply_filters( + 'facetwp_facet_display_value', + $display_value, + array( + 'selected' => ( '' !== $selected ), + 'facet' => $facet, + 'row' => $result, + ) + ); + $show_counts = apply_filters( 'facetwp_facet_dropdown_show_counts', true, $params ); if ( $show_counts ) { $display_value .= sprintf( ' (%s)', $result['counter'] ); } $output .= sprintf( - '', + '', esc_attr( $result['facet_value'] ), $selected, esc_html( $display_value ) @@ -91,10 +196,63 @@ function render( $params ) { function filter_posts( $params ) { global $wpdb; - $output = array(); $facet = $params['facet']; $selected_values = $params['selected_values']; + if ( $this->is_checkbox_display_mode( $facet ) ) { + return $this->filter_posts_checkboxes( $facet, $selected_values ); + } + + return $this->filter_posts_select( $facet, $selected_values ); + } + + /** + * OR filter across multiple months (checkbox mode). + * + * @param array $facet Facet settings. + * @param array $selected_values Selected values. + * @return array|string + */ + protected function filter_posts_checkboxes( $facet, $selected_values ) { + global $wpdb; + + $sql_parts = array(); + foreach ( $selected_values as $val ) { + $dates = explode( '-', $val ); + if ( count( $dates ) === 2 ) { + $sql_parts[] = $wpdb->prepare( + '(YEAR(facet_value) = %d AND MONTH(facet_value) = %d)', + absint( $dates[0] ), + absint( $dates[1] ) + ); + } + } + + if ( empty( $sql_parts ) ) { + return 'continue'; + } + + $where = implode( ' OR ', $sql_parts ); + + $sql = " + SELECT DISTINCT post_id + FROM {$wpdb->prefix}facetwp_index + WHERE facet_name = %s AND ($where) + ORDER BY facet_value DESC"; + + return $wpdb->get_col( $wpdb->prepare( $sql, $facet['name'] ) ); + } + + /** + * Single month filter (select mode, legacy master). + * + * @param array $facet Facet settings. + * @param array $selected_values Selected values. + * @return array|string + */ + protected function filter_posts_select( $facet, $selected_values ) { + global $wpdb; + // Convert the selected value into an array // "0000-00" => array( year, month ); $dates = explode( '-', reset( $selected_values ) ); @@ -103,7 +261,8 @@ function filter_posts( $params ) { $dates = array( date( 'Y' ), date( 'm' ) ); } - $sql = $wpdb->prepare( "SELECT DISTINCT post_id + $sql = $wpdb->prepare( + "SELECT DISTINCT post_id FROM {$wpdb->prefix}facetwp_index WHERE facet_name = %s AND YEAR(facet_value) = %d @@ -114,15 +273,31 @@ function filter_posts( $params ) { absint( $dates[1] ) ); - $output = $wpdb->get_col( $sql ); - - return $output; + return $wpdb->get_col( $sql ); } /** * Output admin settings HTML */ - function settings_html() { ?> + function settings_html() { + ?> +
+
+ : +
+ ? +
+ +
+
+
+
+ +
+
: @@ -164,16 +339,20 @@ function settings_html() { ?>
- + function admin_scripts() { + + ?> - + function front_scripts() { + + ?> -