169 lines
5.9 KiB
PHP
169 lines
5.9 KiB
PHP
<?php
|
|
if ( ! defined( 'ABSPATH' ) ) exit;
|
|
|
|
class WMW_Search {
|
|
|
|
public function init() {
|
|
add_action( 'save_post_wmw_article', array( $this, 'index_article' ), 10, 2 );
|
|
add_action( 'delete_post', array( $this, 'remove_from_index' ) );
|
|
}
|
|
|
|
/**
|
|
* Einen Artikel in den Suchindex schreiben.
|
|
*/
|
|
public function index_article( $post_id, $post ) {
|
|
global $wpdb;
|
|
if ( $post->post_status !== 'publish' ) return;
|
|
|
|
$wiki_id = (int) get_post_meta( $post_id, '_wmw_wiki_id', true );
|
|
$keywords = wp_strip_all_tags( $post->post_title . ' ' . $post->post_content . ' ' . $post->post_excerpt );
|
|
|
|
$wpdb->replace(
|
|
$wpdb->prefix . 'wmw_search_index',
|
|
array(
|
|
'article_id' => $post_id,
|
|
'wiki_id' => $wiki_id,
|
|
'keywords' => $keywords,
|
|
),
|
|
array( '%d', '%d', '%s' )
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Artikel aus dem Index entfernen.
|
|
*/
|
|
public function remove_from_index( $post_id ) {
|
|
global $wpdb;
|
|
$wpdb->delete( $wpdb->prefix . 'wmw_search_index', array( 'article_id' => $post_id ), array( '%d' ) );
|
|
}
|
|
|
|
/**
|
|
* Alle vorhandenen Artikel in den Index aufnehmen.
|
|
* Wird aufgerufen wenn der Index leer ist (z.B. nach Gitea-Import).
|
|
*/
|
|
public static function reindex_all() {
|
|
global $wpdb;
|
|
|
|
$articles = get_posts( array(
|
|
'post_type' => 'wmw_article',
|
|
'post_status' => 'publish',
|
|
'posts_per_page' => -1,
|
|
) );
|
|
|
|
foreach ( $articles as $post ) {
|
|
$wiki_id = (int) get_post_meta( $post->ID, '_wmw_wiki_id', true );
|
|
$keywords = wp_strip_all_tags( $post->post_title . ' ' . $post->post_content . ' ' . $post->post_excerpt );
|
|
|
|
$wpdb->replace(
|
|
$wpdb->prefix . 'wmw_search_index',
|
|
array(
|
|
'article_id' => $post->ID,
|
|
'wiki_id' => $wiki_id,
|
|
'keywords' => $keywords,
|
|
),
|
|
array( '%d', '%d', '%s' )
|
|
);
|
|
}
|
|
|
|
return count( $articles );
|
|
}
|
|
|
|
/**
|
|
* Artikel suchen.
|
|
* 1. Versucht den schnellen Custom-Index.
|
|
* 2. Fällt auf WP_Query zurück, wenn der Index leer ist (z.B. nach Gitea-Import).
|
|
* 3. Baut den Index automatisch auf, wenn er leer war.
|
|
*/
|
|
public static function search( $query, $wiki_id = 0, $limit = 20 ) {
|
|
global $wpdb;
|
|
|
|
$table = $wpdb->prefix . 'wmw_search_index';
|
|
$like = '%' . $wpdb->esc_like( $query ) . '%';
|
|
|
|
// ── Prüfen ob der Index überhaupt Einträge hat ────────────────────
|
|
$index_count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM $table" );
|
|
|
|
$ids = array();
|
|
|
|
if ( $index_count > 0 ) {
|
|
// ── Custom-Index nutzen ───────────────────────────────────────
|
|
if ( $wiki_id ) {
|
|
$rows = $wpdb->get_results( $wpdb->prepare(
|
|
"SELECT article_id FROM $table WHERE wiki_id = %d AND keywords LIKE %s LIMIT %d",
|
|
$wiki_id, $like, $limit
|
|
) );
|
|
} else {
|
|
$rows = $wpdb->get_results( $wpdb->prepare(
|
|
"SELECT article_id FROM $table WHERE keywords LIKE %s LIMIT %d",
|
|
$like, $limit
|
|
) );
|
|
}
|
|
$ids = wp_list_pluck( $rows, 'article_id' );
|
|
}
|
|
|
|
// ── Fallback: WP_Query (wenn Index leer oder keine Treffer) ───────
|
|
if ( empty( $ids ) ) {
|
|
$args = array(
|
|
'post_type' => 'wmw_article',
|
|
'post_status' => 'publish',
|
|
'posts_per_page' => $limit,
|
|
's' => $query,
|
|
'orderby' => 'relevance',
|
|
);
|
|
|
|
if ( $wiki_id ) {
|
|
$args['meta_query'] = array(
|
|
array(
|
|
'key' => '_wmw_wiki_id',
|
|
'value' => $wiki_id,
|
|
),
|
|
);
|
|
}
|
|
|
|
$fallback = get_posts( $args );
|
|
|
|
// Index war leer → jetzt automatisch aufbauen (im Hintergrund)
|
|
if ( $index_count === 0 ) {
|
|
self::reindex_all();
|
|
}
|
|
|
|
foreach ( $fallback as &$post ) {
|
|
$excerpt = $post->post_excerpt ?: wp_trim_words( $post->post_content, 25 );
|
|
$post->wmw_excerpt = self::highlight( $excerpt, $query );
|
|
$post->wmw_title = self::highlight( $post->post_title, $query );
|
|
}
|
|
|
|
return $fallback;
|
|
}
|
|
|
|
// ── Artikel-Objekte aus IDs laden ─────────────────────────────────
|
|
$posts = get_posts( array(
|
|
'post_type' => 'wmw_article',
|
|
'post_status' => 'publish',
|
|
'post__in' => $ids,
|
|
'posts_per_page' => $limit,
|
|
'orderby' => 'post_title',
|
|
'order' => 'ASC',
|
|
) );
|
|
|
|
foreach ( $posts as &$post ) {
|
|
$excerpt = $post->post_excerpt ?: wp_trim_words( $post->post_content, 25 );
|
|
$post->wmw_excerpt = self::highlight( $excerpt, $query );
|
|
$post->wmw_title = self::highlight( $post->post_title, $query );
|
|
}
|
|
|
|
return $posts;
|
|
}
|
|
|
|
/**
|
|
* Suchtreffer hervorheben.
|
|
*/
|
|
public static function highlight( $text, $query ) {
|
|
$words = explode( ' ', preg_quote( trim( $query ), '/' ) );
|
|
foreach ( $words as $word ) {
|
|
if ( strlen( $word ) < 2 ) continue;
|
|
$text = preg_replace( '/(' . $word . ')/iu', '<mark class="wmw-highlight">$1</mark>', $text );
|
|
}
|
|
return $text;
|
|
}
|
|
} |