2, 'title' => __( 'AddSynapse Search — Product filter', 'addsynapse-search-filter' ), 'category' => 'widgets', 'icon' => 'filter', 'description' => __( 'One filter: pick the attribute, the title and how it looks. Add one block per attribute.', 'addsynapse-search-filter' ), 'attributes' => array( 'attribute' => array( 'type' => 'string', 'default' => '', ), 'title' => array( 'type' => 'string', 'default' => '', ), 'style' => array( 'type' => 'string', 'default' => 'checkbox', ), 'limit' => array( 'type' => 'number', 'default' => 12, ), 'counts' => array( 'type' => 'boolean', 'default' => true, ), 'search' => array( 'type' => 'boolean', 'default' => false, ), 'match' => array( 'type' => 'string', 'default' => 'any', ), 'activeFilters' => array( 'type' => 'boolean', 'default' => false, ), 'categoryDisplay' => array( 'type' => 'string', 'default' => 'list', ), 'categoryDepth' => array( 'type' => 'string', 'default' => 'all', ), 'className' => array( 'type' => 'string', 'default' => '', ), ), 'editor_script' => 'addsynapse-search-filters-block-editor', 'render_callback' => array( __CLASS__, 'render' ), ) ); } /** {value,label} ζεύγη, όπως τα θέλει το SelectControl. */ private static function options( $map ) { $out = array(); foreach ( $map as $value => $label ) { $out[] = array( 'value' => (string) $value, 'label' => (string) $label, ); } return $out; } /** * Server-side render — ανακατευθύνει στο shortcode ώστε να υπάρχει μία * μόνο πηγή αλήθειας για το markup. * * @param array $attributes Block attributes. * @return string */ public static function render( $attributes ) { if ( ! class_exists( 'Addsynapse_Search_Filters' ) || empty( $attributes['attribute'] ) ) { return ''; } return Addsynapse_Search_Filters::render_filter( array( 'attribute' => sanitize_text_field( $attributes['attribute'] ), 'auto_hide' => 'yes', 'title' => isset( $attributes['title'] ) ? sanitize_text_field( $attributes['title'] ) : '', 'style' => isset( $attributes['style'] ) ? sanitize_key( $attributes['style'] ) : 'checkbox', 'limit' => isset( $attributes['limit'] ) ? absint( $attributes['limit'] ) : 12, 'counts' => empty( $attributes['counts'] ) ? 'no' : 'yes', 'search' => empty( $attributes['search'] ) ? 'no' : 'yes', 'match' => isset( $attributes['match'] ) ? sanitize_key( $attributes['match'] ) : 'any', 'active_filters' => empty( $attributes['activeFilters'] ) ? 'no' : 'yes', 'category_display' => isset( $attributes['categoryDisplay'] ) ? sanitize_key( $attributes['categoryDisplay'] ) : 'list', 'category_depth' => isset( $attributes['categoryDepth'] ) ? sanitize_key( $attributes['categoryDepth'] ) : 'all', // Το `className` το γράφει ο ίδιος ο editor (Advanced -> // Additional CSS class(es)) — δεν χρειάζεται δικό μας πεδίο. 'class' => isset( $attributes['className'] ) ? $attributes['className'] : '', ) ); } /** * Inline editor script. Δεν αγγίζει το frontend· τρέχει μόνο μέσα στον * block editor. * * @return string */ protected static function editor_script() { $title = esc_js( __( 'AddSynapse Search — Product filter', 'addsynapse-search-filter' ) ); $desc = esc_js( __( 'One filter: pick the attribute, the title and how it looks.', 'addsynapse-search-filter' ) ); $panel = esc_js( __( 'Filter settings', 'addsynapse-search-filter' ) ); $l_attr = esc_js( __( 'Filter by', 'addsynapse-search-filter' ) ); $l_title = esc_js( __( 'Title (leave empty to use the attribute name)', 'addsynapse-search-filter' ) ); $l_style = esc_js( __( 'Display as', 'addsynapse-search-filter' ) ); $l_limit = esc_js( __( 'Values to show', 'addsynapse-search-filter' ) ); $l_counts = esc_js( __( 'Show how many products each value has', 'addsynapse-search-filter' ) ); $l_search = esc_js( __( 'Add a search box (useful when the attribute has many values)', 'addsynapse-search-filter' ) ); $l_active = esc_js( __( 'Show the active filters above the products, each with ✕ to remove it', 'addsynapse-search-filter' ) ); $l_match = esc_js( __( 'When several values are ticked', 'addsynapse-search-filter' ) ); $m_any = esc_js( __( 'Match any of them (red or blue)', 'addsynapse-search-filter' ) ); $m_all = esc_js( __( 'Match all of them (waterproof and windproof)', 'addsynapse-search-filter' ) ); $m_help = esc_js( __( 'Different filters are always combined: red AND size 39.', 'addsynapse-search-filter' ) ); $l_cdisp = esc_js( __( 'Categories shown as', 'addsynapse-search-filter' ) ); $l_cdepth = esc_js( __( 'Category levels', 'addsynapse-search-filter' ) ); $h_cdepth = esc_js( __( 'On a category page, the first level is the subcategories of that category.', 'addsynapse-search-filter' ) ); $choose = esc_js( __( '— Choose —', 'addsynapse-search-filter' ) ); $preview = esc_js( __( 'Product filter', 'addsynapse-search-filter' ) ); $unset_msg = esc_js( __( 'Pick what to filter by in the sidebar.', 'addsynapse-search-filter' ) ); return " ( function( blocks, element, blockEditor, components ) { if ( ! blocks || ! element || ! blockEditor ) { return; } var el = element.createElement; var InspectorControls = blockEditor.InspectorControls; var useBlockProps = blockEditor.useBlockProps; var PanelBody = components.PanelBody; var SelectControl = components.SelectControl; var TextControl = components.TextControl; var ToggleControl = components.ToggleControl; var RangeControl = components.RangeControl; var choices = [ { value: '', label: '{$choose}' } ].concat( window.addsynapseSearchFilterChoices || [] ); var styles = window.addsynapseSearchFilterStyles || []; var catDisplays = window.addsynapseSearchFilterCatDisplays || []; var catDepths = window.addsynapseSearchFilterCatDepths || []; blocks.registerBlockType( 'addsynapse-search/filter', { title: '{$title}', description: '{$desc}', icon: 'filter', category: 'widgets', attributes: { attribute: { type: 'string', default: '' }, title: { type: 'string', default: '' }, style: { type: 'string', default: 'checkbox' }, limit: { type: 'number', default: 12 }, counts: { type: 'boolean', default: true }, search: { type: 'boolean', default: false }, match: { type: 'string', default: 'any' }, activeFilters: { type: 'boolean', default: false }, categoryDisplay: { type: 'string', default: 'list' }, categoryDepth: { type: 'string', default: 'all' } }, edit: function( props ) { var a = props.attributes; var set = props.setAttributes; var blockProps = useBlockProps ? useBlockProps() : {}; var label = ''; choices.forEach( function ( c ) { if ( c.value === a.attribute ) { label = c.label; } } ); return el( 'div', blockProps, el( InspectorControls, {}, el( PanelBody, { title: '{$panel}' }, el( SelectControl, { label: '{$l_attr}', value: a.attribute, options: choices, onChange: function( v ) { set( { attribute: v } ); } } ), el( TextControl, { label: '{$l_title}', value: a.title || '', onChange: function( v ) { set( { title: v } ); } } ), el( SelectControl, { label: '{$l_style}', value: a.style, options: styles, onChange: function( v ) { set( { style: v } ); } } ), 'categories' === a.attribute ? el( SelectControl, { label: '{$l_cdisp}', value: a.categoryDisplay || 'list', options: catDisplays, onChange: function( v ) { set( { categoryDisplay: v } ); } } ) : null, 'categories' === a.attribute ? el( SelectControl, { label: '{$l_cdepth}', value: a.categoryDepth || 'all', options: catDepths, help: '{$h_cdepth}', onChange: function( v ) { set( { categoryDepth: v } ); } } ) : null, el( RangeControl, { label: '{$l_limit}', value: a.limit, min: 1, max: 100, onChange: function( v ) { set( { limit: v } ); } } ), el( ToggleControl, { label: '{$l_counts}', checked: !! a.counts, onChange: function( v ) { set( { counts: v } ); } } ), el( ToggleControl, { label: '{$l_search}', checked: !! a.search, onChange: function( v ) { set( { search: v } ); } } ), el( SelectControl, { label: '{$l_match}', value: a.match || 'any', options: [ { value: 'any', label: '{$m_any}' }, { value: 'all', label: '{$m_all}' } ], help: '{$m_help}', onChange: function( v ) { set( { match: v } ); } } ), el( ToggleControl, { label: '{$l_active}', checked: !! a.activeFilters, onChange: function( v ) { set( { activeFilters: v } ); } } ) ) ), el( 'div', { className: 'wosearch-block-editor-placeholder' }, el( 'span', { className: 'dashicons dashicons-filter' } ), el( 'span', {}, ' ' + ( a.title || label || '{$preview}' ) ), a.attribute ? null : el( 'em', {}, ' — {$unset_msg}' ) ) ); }, save: function() { return null; } } ); } )( window.wp && window.wp.blocks, window.wp && window.wp.element, window.wp && window.wp.blockEditor, window.wp && window.wp.components ); "; } }