サポート » 使い方全般 » 投稿を【ユーザーメタデータ】で検索したい

  • temina

    (@temina)


    WordPress 3.8
    Search Everything 8.0
    ———————————–

    いつも大変お世話になっております。

    掲題ママなのですが、投稿(正確にはカスタム投稿タイプ)をuser_metaで検索したいのですが、どうすればいいのかほとほと困り果てております。

    例えば、user_metaのキーが住所、値に関東と入力されており、
    検索で「関東」と入力した場合、合致したユーザーのカスタム投稿が引っかかって欲しいのです。

    ニックネームができるので、きっと他のメタデータもできるはず…と思い調べているのですが、どうしてもユーザーの検索ばかり引っかかってしまい、私が希望している投稿の検索が出てきません。

    また、過去にフォーラムにて質問されているものもあるのですが、
    http://ja.forums.wordpress.org/topic/2722?replies=6
    4年前の投稿で、プラグインのコードを見ても近しい部分や該当する部分がありませんでした…。

    そもそも本件可能なのでしょうか?
    もしご存じの方がいらっしゃいましたら、何卒お助け下さい。

6件の返信を表示中 - 16 - 21件目 (全21件中)
  • トピック投稿者 temina

    (@temina)

    こんにちは。
    kjmtshさん、度々ありがとうございます。

    すみません、ご報告?ご相談?なのですが、
    一番最後に書いて頂いたコードでちょっとエラーが出てしまっていたので(波括弧とか、セミコロンとかでした)エラーが出ないようにしてみたのですが、
    検索をしても上手く動いていないみたいで、ちょっと困っております…。

    以下、コードです。
    ————————————————————-

    【functions.phpに記載してあるもの】

    if (isset($_GET['my_nonce']) && wp_verify_nonce($_GET['my_nonce'], 'my_search')) {
        if (isset($_GET['address']) && $_GET['address'] != 'none') {
            function replace_search_template($template) {
            return locate_template(array('search.php'));
            }
            add_filter('template_include', 'replace_search_template', 99);
            search_with_usermeta();
        }
    } elseif (isset($_GET['address'])) {
        if (!isset($_GET['my_nonce']) || !wp_verify_nonce($_GET['my_nonce'], 'my_search')) {
            echo 'This operation is not allowed on this server';
            exit;
        }
    }
    function search_with_usermeta() {
        global $wpdb, $wp_query;
    
        $query_strings = $_GET['s'];
        $post_types    = "('カスタム投稿タイプ名')";       // 投稿タイプ 複数指定可
        $post_status   = "publish";        // 投稿ステータス See WP_Query manual
        $address       = urldecode($_GET['address']); // 住所 meta_value の値に使う
        $meta_key      = "address";            // wp_usermeta の meta_key フィールド名
        $limit         = 5;                // 1ページに表示する投稿数
        $where         = '';
    
        $query_strings = stripslashes($query_strings);
        if (empty($query_strings)) {
            $search_terms = array('');
        } else {
            $query_strings = urldecode($query_strings);
            $query_strings = str_replace(array("\r", "\n"), '', $query_strings);
            if (preg_match_all('/".*?("|$)|((?<=[\t ",+])|^)[^\t ",+]+/', $query_strings, $matches)) {
                foreach ($matches[0] as $match) {
                    if (preg_match('/^".+"$/', $match)){
                        $search_terms[] = trim($match, "\"'");
    				} else {
                        $search_terms[] = trim($match, "\"' ");
    				}
                }
                if (empty($search_terms)) {
                    $search_terms = array($query_strings);
                }
            } else {
                $search_terms = array($query_strings);
            }
        }
        foreach ($search_terms as $term) {
            $term = like_escape(esc_sql($term));
            $where .= " AND ((p.post_content LIKE '%{$term}%') OR (p.post_title LIKE '%{$term}%'))";
        }
        $where .= " AND (p.post_type IN $post_types AND p.post_status = '{$post_status}')";
        $where .= " AND (um.meta_key = '{$meta_key}' AND um.meta_value = '{$address}')";
        $sql = "SELECT * FROM $wpdb->posts AS p
            LEFT JOIN $wpdb->usermeta AS um
            ON p.post_author=um.user_id
            WHERE 1=1 $where
            ORDER BY p.post_date DESC
            LIMIT $limit";
        $args = array(
            'query'          => $sql,
            'posts_per_page' => $limit,
            'paged'          => get_query_var('paged')
        );
        unset($wp_query);
        $wp_query = new WP_Query($args);
    }

    【検索フォーム】(value部分に該当する値はユーザーメタに入れてあります)

    <form role="search" id="searchform" method="GET" action="<?php echo home_url('/'); ?>">
        <label for="s">Search for:</label>
        <input type="text" value="" name="s" id="s" />
        <label for="address">Address</label>
        <select name="address">
            <option value="none">none</option>
            <option value="関東">関東</option>
            <option value="東北">東北</option>
        </select>
        <input type="submit" id="searchsubmit" value="Search" style="display:inline;" />
        <?php wp_nonce_field('my_search', 'my_nonce'); ?>
    </form>

    【繰り返し部分】(テストの仮のものです)

    <?php $my_posts = search_with_usermeta();?>
    <?php foreach ($my_posts as $post) : : ?>
    <p><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></p>
    <?php endforeach; ?>

    —————————————————————–

    すみません、お忙しいとは思うのですが、お伺いしたい点がいくつかありまして…。

    1)カスタムポストタイプの指定はform部分でする必要は無い?
      functions.phpの時点で指定しているので大丈夫、という事でしょうか?

    2)繰り返し部分についてなのですが、上記の書き方で合ってるでしょうか?
     現在使用しているテーマのsearch.phpが、

    <?php if ( have_posts() ) : ?>
    	<?php while ( have_posts() ) : the_post(); ?>
    		<?php get_template_part( 'content', 'search' ); ?>
    	<?php endwhile; ?>
    <?php else : ?>
    	<?php get_template_part( 'no-results', 'search' ); ?>
    <?php endif; ?>

    となっていて、色々トライしてcontent.phpの方に書いてみてもsarch.phpに書いてみても上手く表示ができず…。

    本当にすみません、今一度お教え頂いてもよろしいでしょうか…?
    何卒よろしくお願いします。

    げ、すんません。コードもドキュメントもごちゃごちゃですね。

    <?php $my_posts = search_with_usermeta();?>
    <?php foreach ($my_posts as $post) : : ?>
    <p><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></p>
    <?php endforeach; ?>

    繰り返し部分についてなのですが、上記の書き方で合ってるでしょうか?

    これはもう必要ありませんので、削除してください。search.php デフォルトのループだけでけっこうです。黙って仕様を変えるという反則技を使っちゃいました。

    カスタムポストタイプの指定はform部分でする必要は無い?

    はい、ハードコーディングされてます。必要なら、チェックボックスなどをフォームに追加して、環境変数で受け取ることができます。(‘カスタム投稿’) と書いてありますが、(‘カスタム投稿’, ‘post’, ‘draft’) みたいな書き方ができます。

    トピック投稿者 temina

    (@temina)

    ご返信ありがとうございます!!
    functionsだけでいいのですか、ありがとうございます、かしこまりました。

    そうですよね、そうですよね、ポストタイプの指定いらないですよね、書いてありますもんね。

    色々試してみたのですが
    1)単語を入力するとPageとPostと投稿タイプが引っかかるが、ユーザーメタでの検索が働いてない
    2)単語欄が未入力だとユーザーメタでの検索が無視されて、通常のPostのみがひっかかる

    といった感じなのです。
    既に投稿タイプを指定しているはずなのに引っかかるものが意図していないものだったので、改めてお伺いしたのです…。

    カスタム投稿タイプ名をpageにしたりしてみても結果が変わらないので、

    $where .= ” AND (p.post_type = ‘{$post_types}’ AND p.post_status = ‘{$post_status}’)”;

    を試しに直接
    $where .= ” AND (p.post_type = ‘カスタム投稿タイプ名’ AND p.post_status = ‘{$post_status}’)”;

    にしてみても上手くいかなかったのです。

    すみません、私がいけないのかもしれないので、色々触ってみますが、もし思い当たるフシがありましたらご協力いただけませんでしょうか…頼ってしまってすみません…

    1)単語を入力するとPageとPostと投稿タイプが引っかかるが、ユーザーメタでの検索が働いてない
    2)単語欄が未入力だとユーザーメタでの検索が無視されて、通常のPostのみがひっかかる

    そうなってますねぇ… ちょっと出直しですね。もうちょっと時間をください。

    トピック投稿者 temina

    (@temina)

    わぁ、kjmtshさんすみません…
    勿論お時間があって気の向いた時で大丈夫ですので。

    ありがとうございます。

    できました。たぶん…

    一つだけ克服できないところがあって、search.php で場合わけをしないといけなくなりました。検索フォームはそのままで結構です。

    search.php

    <?php
    if ($the_query = search_with_usermeta()) {
        global $wp_query;
        $wp_query = $the_query;
    }
    ?>
    <?php if (have_posts()): ?>
    <?php while (have_posts()) : the_poss(); ?>
    ...
    <?php endwhile; endif; ?>

    通常のループが始まる前に、if 以下を追加してください。

    functions.php の方は、ちょっと長いです。結局、WP_Query をそのまま使うのはあきらめて、それを継承した新たなクラスを作っちゃいました。ページング情報のところだけ抜き出して使うという感じです。

    post_type や meta_key など、必要なところは書き換えてください。絞り込みができて、複数ページに渡ったときに、ちゃんとページングができれば、成功です。そうでなければ、失敗。一応自分でもチェックしましたが、未知のバグがあるかもしれませんので、結果をお知らせいただけると助かります。

    if (isset($_GET['my_nonce']) && wp_verify_nonce($_GET['my_nonce'], 'my_search')) {
        if (isset($_GET['address']) && $_GET['address'] != 'none') {
            function replace_search_template($template) {
                return locate_template(array('search.php'));
            }
            add_filter('template_include', 'replace_search_template', 99);
        }
    } else if (isset($_GET['address'])) {
        if (!isset($_GET['my_nonce']) || !wp_verify_nonce($_GET['my_nonce'], 'my_search')) {
            echo 'This operation is not allowed on this server';
            exit;
        }
    }
    function search_with_usermeta() {
        if (isset($_GET['address']) && $_GET['address'] != 'none') {
            global $wpdb;
    
            $query_strings = $_GET['s'];
            $post_types    = "('post')";       // 投稿タイプ 複数指定可
            $post_status   = "publish";        // 投稿ステータス See WP_Query manual
            $address       = urldecode($_GET['address']); // 住所 meta_value の値に使う
            $meta_key      = "key";            // wp_usermeta の meta_key フィールド名
            $limit         = 5;                // 1ページに表示する投稿数
            $where         = '';
    
            $query_strings = stripslashes($query_strings);
            if (empty($query_strings)) {
                $search_terms = array('');
            } else {
                $query_strings = urldecode($query_strings);
                $query_strings = str_replace(array("\r", "\n"), '', $query_strings);
                if (preg_match_all('/".*?("|$)|((?<=[\t ",+])|^)[^\t ",+]+/', $query_strings, $matches)) {
                    foreach ($matches[0] as $match) {
                        if (preg_match('/^".+"$/', $match))
                            $search_terms[] = trim($match, "\"'");
                        else
                            $search_terms[] = trim($match, "\"' ");
                    }
                    if (empty($search_terms)) {
                        $search_terms = array($query_strings);
                    }
                } else {
                    $search_terms = array($query_strings);
                }
            }
            foreach ($search_terms as $term) {
                $term = like_escape(esc_sql($term));
                $where .= " AND (($wpdb->posts.post_content LIKE '%{$term}%') OR ($wpdb->posts.post_title LIKE '%{$term}%'))";
            }
            $where .= " AND ($wpdb->posts.post_type IN $post_types AND $wpdb->posts.post_status = '{$post_status}')";
            $where .= " AND ($wpdb->usermeta.meta_key = '{$meta_key}' AND $wpdb->usermeta.meta_value = '{$address}')";
            $sql = "SELECT * FROM $wpdb->posts
                LEFT JOIN $wpdb->usermeta
                ON $wpdb->posts.post_author=$wpdb->usermeta.user_id
                WHERE 1=1 $where
                ORDER BY $wpdb->posts.post_date DESC
                LIMIT $limit";
            $args = array(
                'query'          => $sql,
                'posts_per_page' => $limit,
                'paged'          => get_query_var('paged') ? get_query_var('paged') : 1
            );
            $the_query = new WP_Query_mini($args);
            return $the_query;
        }
        return false;
    }
    
    class WP_Query_mini extends WP_Query {
        function parse_query($query = '') {
            if (!empty($query)) {
                $this->init();
                $this->query = $this->query_vars = wp_parse_args($query);
            } elseif (!isset($this->query)) {
                $this->query = $this->query_vars;
            }
        }
        function get_posts() {
            global $wpdb;
            $this->parse_query();
            $q = &$this->query_vars;
            if (!isset($q['posts_per_page']) || $q['posts_per_page'] == 0)
                $q['posts_per_page'] = get_option('posts_per_page');
            $q['posts_per_page'] = (int) $q['posts_per_page'];
            if ($q['posts_per_page'] < -1)
                $q['posts_per_page'] = abs($q['posts_per_page']);
            else if ($q['posts_per_page'] == 0)
                $q['posts_per_page'] = 1;
            if (isset($q['no_found_rows']))
                $q['no_found_rows'] = (bool) $q['no_found_rows'];
            else
                $q['no_found_rows'] = false;
            if (empty($q['nopaging']) && !$this->is_singular) {
                $page = absint($q['paged']);
                if (!$page) $page = 1;
                if (empty($q['offset'])) {
                    $pgstrt = ($page - 1) * $q['posts_per_page'] . ', ';
                } else {
                    $q['offset'] = absint($q['offset']);
                    $pgstrt = $q['offset'] . ', ';
                }
                $limits = 'LIMIT ' . $pgstrt . $q['posts_per_page'];
            }
            $found_rows = 'SQL_CALC_FOUND_ROWS';
            $this->request = preg_replace("/^SELECT\\s*.+?FROM/i", "SELECT $found_rows DISTINCT $wpdb->posts.* FROM", $q['query']);
            $this->request = $old_request = preg_replace("/^(.+)\\s*LIMIT.*$/ims", "\\1 $limits", $this->request);
            $this->posts = $wpdb->get_results($this->request);
            $this->set_found_posts($q, $limits);
            if ($this->posts) {
                $this->post_count = count($this->posts);
            } else {
                $this->post_count = 0;
                $this->posts = array();
            }
            return $this->posts;
        }
    }
6件の返信を表示中 - 16 - 21件目 (全21件中)
  • トピック「投稿を【ユーザーメタデータ】で検索したい」には新たに返信することはできません。