Extension du contexte de recherche dans l'écran de publication de la liste d'administration

34

J'ai créé un type d'article personnalisé auquel j'ai attaché des champs personnalisés. J'aimerais maintenant que la recherche que les auteurs puissent effectuer sur l'écran de liste de publication personnalisée (dans le backend de l'administrateur) soit également effectuée sur les champs méta et non seulement dans le titre et le contenu, comme d'habitude.

Où puis-je m'accrocher et quel code je dois utiliser?

Exemple d'image entrez la description de l'image ici

Stefano

Stefano
la source
1
Une vieille question, mais ... je voudrais suggérer de masquer les adresses électroniques et les noms des captures d'écran ...
Erenor Paz

Réponses:

37

J'ai résolu le filtrage de la requête en ajoutant la jointure sur la table postmeta et en modifiant la clause where. des astuces sur le filtrage de la clause WHERE (qui nécessitent souvent une expression régulière, rechercher et remplacer) figurent ici dans le codex :

add_filter( 'posts_join', 'segnalazioni_search_join' );
function segnalazioni_search_join ( $join ) {
    global $pagenow, $wpdb;

    // I want the filter only when performing a search on edit page of Custom Post Type named "segnalazioni".
    if ( is_admin() && 'edit.php' === $pagenow && 'segnalazioni' === $_GET['post_type'] && ! empty( $_GET['s'] ) ) {    
        $join .= 'LEFT JOIN ' . $wpdb->postmeta . ' ON ' . $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id ';
    }
    return $join;
}

add_filter( 'posts_where', 'segnalazioni_search_where' );
function segnalazioni_search_where( $where ) {
    global $pagenow, $wpdb;

    // I want the filter only when performing a search on edit page of Custom Post Type named "segnalazioni".
    if ( is_admin() && 'edit.php' === $pagenow && 'segnalazioni' === $_GET['post_type'] && ! empty( $_GET['s'] ) ) {
        $where = preg_replace(
            "/\(\s*" . $wpdb->posts . ".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
            "(" . $wpdb->posts . ".post_title LIKE $1) OR (" . $wpdb->postmeta . ".meta_value LIKE $1)", $where );
    }
    return $where;
}
Stefano
la source
1
Hou la la! Juste ce que je cherchais. Cependant, je pense que j'ai peut-être trouvé un bug, lors de la recherche sur le titre du message, j'obtiens un résultat qui est ensuite dupliqué dans les résultats 5 fois!?! imgur.com/eE52gIA
jnthnclrk Le
Voici une autre capture avec le code SQL imprimé: tinypic.com/view.php?pic=124tqb6&s=5 Vous ne pouvez pas comprendre pourquoi je reçois 5 éléments!?!
Jnthnclrk
1
A publié une question distincte sur la correction du bogue de dupe: wordpress.stackexchange.com/questions/111185/…
jnthnclrk
Ceci et le post ci-dessous m'ont été utiles. Maintenant, cherchez un moyen d’inclure la recherche de l’auteur du post et d’afficher les posts qu’il a créés.
Shawn Rebelo
@ Stefano, le résultat de la recherche fonctionne. Avoir un problème, champ par défaut "Titre du poste", l'enregistrement de recherche se répète à plusieurs reprises et du côté de l'administrateur. Voir: imgur.com/a/W4wmXhO
Super Model
10

Stefano répond que c'est génial mais qu'il manque une clause distincte:

function segnalazioni_search_distinct( $where ){
    global $pagenow, $wpdb;

    if ( is_admin() && $pagenow=='edit.php' && $_GET['post_type']=='segnalazioni' && $_GET['s'] != '') {
    return "DISTINCT";

    }
    return $where;
}
add_filter( 'posts_distinct', 'segnalazioni_search_distinct' );

Ajoutez le code ci-dessus, mettez-le à jour et cela fonctionnera sans doublons.

Calara Ionut
la source
7

Cela fonctionnera

function custom_search_query( $query ) {
    $custom_fields = array(
        // put all the meta fields you want to search for here
        "rg_first_name",
        "rg_1job_designation"
    );
    $searchterm = $query->query_vars['s'];

    // we have to remove the "s" parameter from the query, because it will prevent the posts from being found
    $query->query_vars['s'] = "";

    if ($searchterm != "") {
        $meta_query = array('relation' => 'OR');
        foreach($custom_fields as $cf) {
            array_push($meta_query, array(
                'key' => $cf,
                'value' => $searchterm,
                'compare' => 'LIKE'
            ));
        }
        $query->set("meta_query", $meta_query);
    };
}
add_filter( "pre_get_posts", "custom_search_query");
Vin_fugen
la source
1
Veuillez bien indenter votre code et inclure une explication expliquant pourquoi et comment cela fonctionnera .
Le
Bien que je l’ai voté pour la première fois, j’ai réalisé que cela fonctionnerait malheureusement à chaque recherche, même si elle risquait d’être dépassée.
Maciej Paprocki
Ajouter une vérification en if ( $query->query['post_type'] != 'your_custom_post_type' ){ return; }haut en haut de la fonction empêchera l'exécution de cette recherche sur d'autres recherches. Notez que la technique dans cette réponse ne cherche plus le post_title et l'ajouter n'est pas trivial.
Jwinn
Un autre problème - L’indicateur Résultats de la recherche de «<mot-clé>» appelle get_search_query()les appels suivants get_query_var( 's' ). Puisque "s" est défini sur une chaîne vide, les résultats de la recherche pour "" auront toujours une valeur vide entre les guillemets. Y at-il un ajustement à cette solution qui contourne cela?
Jschrab
1

Réponse 1: Ajoutez ce code dans le fichier de fonction, puis changez et ajoutez d'autres noms de colonnes, que vous avez utilisés dans votre type d'article personnalisé

function extend_admin_search( $query ) {

    // use your post type
    $post_type = 'document';
    // Use your Custom fields/column name to search for
    $custom_fields = array(
        "_file_name",
    );

    if( ! is_admin() )
        return;

    if ( $query->query['post_type'] != $post_type )
        return;

    $search_term = $query->query_vars['s'];

    // Set to empty, otherwise it won't find anything
    $query->query_vars['s'] = '';

    if ( $search_term != '' ) {
        $meta_query = array( 'relation' => 'OR' );

        foreach( $custom_fields as $custom_field ) {
            array_push( $meta_query, array(
                'key' => $custom_field,
                'value' => $search_term,
                'compare' => 'LIKE'
            ));
        }

        $query->set( 'meta_query', $meta_query );
    };
}

add_action( 'pre_get_posts', 'extend_admin_search' );

Réponse 2: Recommandé Utilisez ce code dans le fichier de fonction sans aucune modification

function cf_search_join( $join ) {
    global $wpdb;

    if ( is_search() ) {    
        $join .=' LEFT JOIN '.$wpdb->postmeta. ' ON '. $wpdb->posts . '.ID = ' . $wpdb->postmeta . '.post_id ';
    }

    return $join;
}
add_filter('posts_join', 'cf_search_join' );
function cf_search_where( $where ) {
    global $pagenow, $wpdb;

    if ( is_search() ) {
        $where = preg_replace(
            "/\(\s*".$wpdb->posts.".post_title\s+LIKE\s*(\'[^\']+\')\s*\)/",
            "(".$wpdb->posts.".post_title LIKE $1) OR (".$wpdb->postmeta.".meta_value LIKE $1)", $where );
    }

    return $where;
}
add_filter( 'posts_where', 'cf_search_where' );

function cf_search_distinct( $where ) {
    global $wpdb;

    if ( is_search() ) {
        return "DISTINCT";
    }

    return $where;
}
add_filter( 'posts_distinct', 'cf_search_distinct' );
Super modèle
la source
0

Ce n'est pas une recherche, mais certains "sélectionnent" par valeur distincte.

Dans le fichier functions-iworks-posts-filter.zip, vous avez un exemple qui explique comment ajouter un filtre pour les messages normaux avec une méta_key. Je pense que c'est facile à convertir.

Marcin
la source
merci pour l'aide ... Je vais regarder votre attachmend tout de suite. Je vous ferai savoir les résultats de mon enquête ;-) Stefano
Stefano Le
Marcin, je pense que vous vous référez aux filtres tels que "par date", etc., mais je dois utiliser le champ "recherche libre" ci-dessus. En tout cas je viens de poster ma solution, peut-être que ça aide Merci quand même!
Stefano
0

La version du code ici dans quelques réponses modifiant le paramètre meta_query du WP_Query de la recherche dans pre_get_posts ne cherchait plus le post_title. L'ajout de la possibilité de rechercher soit le titre de l'article, OU les méta-valeurs ne peut pas être effectué directement dans WP_Query sans modification du code SQL, car cette question précise : Utilisation de la méta-requête ('meta_query') avec une requête de recherche ('s')

J'ai combiné certaines des techniques ici pour obtenir une version de travail qui évite preg_replaces et trop de modifications SQL (j'espère que cela pourrait être entièrement évité). Le seul inconvénient est qu'après une recherche, le texte du sous-titre en haut de la page indique "Résultats de la recherche pour ''". Je viens de cacher cela avec CSS pour le type de publication personnalisé de mon plugin.

/**
 * Extend custom post type search to also search meta fields
 * @param  WP_Query $query
 */
function extend_cpt_admin_search( $query ) {
  // Make sure we're in the admin area and that this is our custom post type
  if ( !is_admin() || $query->query['post_type'] != 'your_custom_post_type' ){
    return;
  }

  // Put all the meta fields you want to search for here
  $custom_fields = array(
    "your_custom_meta_field",
    "your_custom_meta_field2",
    "your_custom_meta_field3"
  );
  // The string submitted via the search form
  $searchterm = $query->query_vars['s'];

  // Set to empty, otherwise no results will be returned.
  // The one downside is that the displayed search text is empty at the top of the page.
  $query->query_vars['s'] = '';

  if ($searchterm != ""){
    // Add additional meta_query parameter to the WP_Query object.
    // Reference: https://codex.wordpress.org/Class_Reference/WP_Query#Custom_Field_Parameters
    $meta_query = array();
    foreach($custom_fields as $cf) {
      array_push($meta_query, array(
        'key' => $cf,
        'value' => $searchterm,
        'compare' => 'LIKE'
      ));
    }
    // Use an 'OR' comparison for each additional custom meta field.
    if (count($meta_query) > 1){
      $meta_query['relation'] = 'OR';
    }
    // Set the meta_query parameter
    $query->set('meta_query', $meta_query);


    // To allow the search to also return "OR" results on the post_title
    $query->set('_meta_or_title', $searchterm);
  }
}
add_action('pre_get_posts', 'extend_cpt_admin_search');



/**
 * WP_Query parameter _meta_or_title to allow searching post_title when also
 * checking searching custom meta values
 * https://wordpress.stackexchange.com/questions/78649/using-meta-query-meta-query-with-a-search-query-s
 * https://wordpress.stackexchange.com/a/178492
 * This looks a little scary, but basically it's modifying the WHERE clause in the 
 * SQL to say "[like the post_title] OR [the existing WHERE clause]"
 * @param  WP_Query $q
 */
function meta_or_title_search( $q ){
  if( $title = $q->get( '_meta_or_title' ) ){
    add_filter( 'get_meta_sql', function( $sql ) use ( $title ){
      global $wpdb;

      // Only run once:
      static $nr = 0;
      if( 0 != $nr++ ) return $sql;

      // Modified WHERE
      $sql['where'] = sprintf(
          " AND ( (%s) OR (%s) ) ",
          $wpdb->prepare( "{$wpdb->posts}.post_title LIKE '%%%s%%'", $title),
          mb_substr( $sql['where'], 5, mb_strlen( $sql['where'] ) )
      );

      return $sql;
    });
  }
}
add_action('pre_get_posts', 'meta_or_title_search');
Jwinn
la source