get( self::QV_ACTIVE ) || $query->get( self::QV_SKIP ) ) { return ''; } $s = $query->get( 's' ); if ( ! is_string( $s ) || '' === trim( $s ) ) { return ''; } $post_types = array_values( array_filter( (array) $query->get( 'post_type' ) ) ); if ( array( 'product' ) !== $post_types ) { return ''; } if ( $query->is_feed() || ( function_exists( 'wp_doing_cron' ) && wp_doing_cron() ) ) { return ''; } $context = ''; if ( ( defined( 'REST_REQUEST' ) && REST_REQUEST ) || ( function_exists( 'wp_is_serving_rest_request' ) && wp_is_serving_rest_request() ) ) { $context = ''; } elseif ( wp_doing_ajax() ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- μόνο ανάγνωση του ονόματος action (δημόσιο live search του θέματος). $action = isset( $_REQUEST['action'] ) ? sanitize_key( wp_unslash( $_REQUEST['action'] ) ) : ''; $context = in_array( $action, self::ajax_actions(), true ) ? 'ajax' : ''; } elseif ( ! is_admin() ) { $context = $query->is_main_query() ? 'page' : 'query'; } /** * Filters whether a product search query uses our engine in «theme» mode. * * Return a context string ('page', 'ajax' or 'query') to handle it, '' to leave it to WordPress. * * @param string $context Detected context or ''. * @param WP_Query $query The query. */ $context = apply_filters( 'addsynapse_search_theme_handle_query', $context, $query ); return in_array( $context, array( 'page', 'ajax', 'query' ), true ) ? $context : ''; } /** * pre_get_posts: αντικαθιστά τη LIKE αναζήτηση με τα ids της μηχανής μας. * * @param WP_Query $query Το ερώτημα. * @return void */ public static function pre_get_posts( $query ) { $context = self::context_for( $query ); if ( '' === $context ) { return; } $raw = trim( preg_replace( '/\s+/u', ' ', wp_unslash( (string) $query->get( 's' ) ) ) ); $per_page = (int) $query->get( 'posts_per_page' ); if ( 'ajax' === $context ) { // Live search: ό,τι χωράει στο dropdown (+4 για το «sink», όπως το JS). $limit = min( 100, max( 1, $per_page > 0 ? $per_page : 10 ) + 4 ); } else { $limit = self::MAX_IDS; } /** * Filters how many product ids are requested from the engine for a theme search. * * @param int $limit Number of ids. * @param string $context page|ajax|query. */ $limit = max( 1, min( self::MAX_IDS, (int) apply_filters( 'addsynapse_search_theme_limit', $limit, $context ) ) ); $result = self::search( $raw, $limit ); self::$last = array( 'context' => $context, 'raw' => $raw, 'fallback' => null === $result, 'result' => $result, ); if ( null === $result ) { return; // Σιωπηλή επιστροφή στη native αναζήτηση του WordPress. } $ids = $result['ids']; $existing = $query->get( 'post__in' ); if ( is_array( $existing ) && ! empty( $existing ) ) { $allowed = array_flip( array_map( 'intval', $existing ) ); $ids = array_values( array_filter( $ids, function ( $id ) use ( $allowed ) { return isset( $allowed[ $id ] ); } ) ); } // 🔴 Μερική κάλυψη καταλόγου (0.8.0, Addsynapse_Search_Coverage): τα προϊόντα // εκτός δείκτη ΔΕΝ εξαφανίζονται — η κανονική αναζήτηση του WordPress συμπληρώνει // έως N ΜΕΤΑ τα δικά μας. Μόνο τότε· σε πλήρη κάλυψη το «0 = 0» παρακάτω ισχύει. $extra = self::native_extras( $context, $limit, $ids, $result, $existing ); if ( ! empty( $extra ) ) { if ( ! empty( $result['semantic'] ) ) { // Κυριολεκτικό ταίριασμα εκτός δείκτη > «Σχετικά αποτελέσματα» του νοήματος. $ids = $extra; $result['semantic'] = false; } else { $ids = array_merge( $ids, $extra ); } self::$last['native'] = $extra; } // 0 αποτελέσματα από τη μηχανή = 0 (όχι native LIKE): «λάμπα» σε // κατάστημα κοσμημάτων ΔΕΝ πρέπει να ξαναβρεί «λαμπερό» από την πίσω πόρτα. $query->set( 'post__in', empty( $ids ) ? array( 0 ) : $ids ); $query->set( self::QV_ACTIVE, 1 ); if ( self::wants_relevance_order( $query ) ) { $query->set( 'orderby', 'post__in' ); } if ( $query->get( 'suppress_filters' ) ) { // Το posts_search δεν θα τρέξει — η LIKE θα έκοβε τα greeklish/typos. $query->set( 's', '' ); } if ( 'page' === $context ) { self::maybe_track( $query, $raw, $result ); if ( ! empty( $result['semantic'] ) && $query->is_main_query() ) { add_action( 'woocommerce_before_shop_loop', array( __CLASS__, 'related_notice' ), 5 ); // Builders (Woodmart/Elementor layouts, κ.ά.) δεν καλούν το woocommerce_before_shop_loop — // το loop-start του κύριου καταλόγου όμως το καλούν σχεδόν όλοι. add_filter( 'woocommerce_product_loop_start', array( __CLASS__, 'related_notice_loop_start' ), 5 ); } } } /** * Native συμπλήρωμα σε μερική κάλυψη (0.8.0): ids της κανονικής αναζήτησης του * WordPress που δεν έδωσε ήδη η μηχανή μας. Live search (ajax): μόνο όσα χωράνε. * * @param string $context page|ajax|query. * @param int $limit Πόσα ζητήθηκαν από τη μηχανή. * @param int[] $ids Ids της μηχανής (μετά το post__in του ερωτήματος). * @param array $result Αποτέλεσμα search(). * @param array|null $existing post__in του ερωτήματος (περιορισμός). * @return int[] */ private static function native_extras( $context, $limit, array $ids, array $result, $existing ) { if ( ! class_exists( 'Addsynapse_Search_Coverage' ) || ! Addsynapse_Search_Coverage::is_partial() ) { return array(); } if ( 'ajax' === $context ) { $max = min( Addsynapse_Search_Coverage::native_max(), max( 0, $limit - count( $ids ) ) ); } else { $max = Addsynapse_Search_Coverage::native_page_max(); } if ( $max <= 0 ) { return array(); } $query = isset( $result['query'] ) && '' !== (string) $result['query'] ? (string) $result['query'] : ''; $extra = Addsynapse_Search_Coverage::native_extras( $query, empty( $result['semantic'] ) ? $ids : array(), $max ); if ( is_array( $existing ) && ! empty( $existing ) ) { $allowed = array_flip( array_map( 'intval', $existing ) ); $extra = array_values( array_filter( $extra, function ( $id ) use ( $allowed ) { return isset( $allowed[ $id ] ); } ) ); } return $extra; } /** Τυπώθηκε ήδη η ετικέτα «Related results» σε αυτό το αίτημα; */ private static $notice_printed = false; /** * Ετικέτα πάνω από τη λίστα προϊόντων του θέματος όταν τα αποτελέσματα * ήρθαν από το σημασιολογικό fallback (ειλικρίνεια: δεν ταίριαξαν οι λέξεις). * * @return void */ public static function related_notice() { if ( self::$notice_printed ) { return; } self::$notice_printed = true; echo ''; } /** * Ίδια ετικέτα πριν από το `