Членство в Wordpress. Получите всех активных участников плана, у которых есть непустое значение для определенного мета-ключа. Также получить дополнительные метаданные - PullRequest
0 голосов
/ 05 июля 2018

Я создаю карту Google с маркерами для всех моих активных участников WP Memberships. Сначала мне нужно запросить базу данных, чтобы получить всех ACTIVE (и / или COMPLIMENTARY) членов конкретного плана членства (который передается в функцию), но они также должны иметь непустое значение для пользовательского meta_key affiliate_location. Для моих пользователей доступна форма внешнего интерфейса, в которой они могут зарегистрироваться на карте, введя свое местоположение (и другие данные) в форму, сохранив информацию в виде мета пользователя. Если они не указали свое местоположение, у них будет пустое значение meta_value для meta_key affiliate_location.

Я уже выполнил вышесказанное. Моя функция может проверить, является ли пользователь активным / дополнительным участником, а затем проверить, есть ли у него непустое значение affiliate_location meta_value, и вернуть список этих пользователей, который включает в себя их user_id, display_name и affiliate_location meta_key и meta_value (meta_value - это то, что я буду использовать, чтобы разместить их маркер на карте Google).

То, что я сейчас пытаюсь выполнить, - это вернуть дополнительные метаданные пользователей, если они пройдут вышеуказанные тесты. Если они являются активным членом и ввели местоположение, то я также хочу вернуть (в том же запросе) мета-значения для следующих мета-ключей: affiliate_name, affiliate_email, affiliate_website, affiliate_phone_number.

Я попытался выполнить приведенный ниже запрос SQL с помощью ответа @ LoicTheAztec на этот вопрос , настроив SQL для проверки мета-значения affiliate_location.

Я попытался создать псевдоним мета-таблицы пользователя для других пар мета-ключ / значение, которые мне нужно вернуть. Вы можете увидеть это в последней строке LEFT JOIN ... usermeta AS um1..., а затем перечислить um1.meta_key в первом выражении и, наконец, включить условие AND um1.meta_key = 'affiliate_name', но результаты всегда включают только одно meta_key и одно meta_value свойство. Я не могу понять, как вернуть дополнительные метаданные, которые мне нужны для каждого соответствующего пользователя. Любая помощь высоко ценится!

// List of Active Users for a Membership Plan
function get_active_members_for_membership( $membership_slug )
{
    global $wpdb;

    // Getting all User IDs and data for a membership plan
    return $wpdb->get_results( "

        SELECT DISTINCT um.user_id, u.display_name, um.meta_key, um.meta_value, um1.meta_key, um1.meta_value

        FROM {$wpdb->prefix}posts AS p
            LEFT JOIN {$wpdb->prefix}posts AS p2 ON p2.ID = p.post_parent
            LEFT JOIN {$wpdb->prefix}users AS u ON u.id = p.post_author
            LEFT JOIN {$wpdb->prefix}usermeta AS um ON u.id = um.user_id
            LEFT JOIN {$wpdb->prefix}usermeta AS um1 ON u.id = um1.user_id

        WHERE p.post_type = 'wc_user_membership'
            AND p.post_status IN ('wcm-active', 'wcm-complimentary')
            AND p2.post_type = 'wc_membership_plan'
            AND p2.post_name LIKE '$membership_slug'
            AND um.meta_key = 'affiliate_location'
            AND um.meta_value <> ''
            AND um1.meta_key = 'affiliate_name'
            -- AND um.meta_key = 'affiliate_email'
            -- AND um.meta_key = 'affiliate_website'
            -- AND um.meta_key = 'affiliate_phone_number'
    " );
}

Вот результаты, которые я получаю от вышеуказанной попытки:

Array
(
    [0] => stdClass Object
        (
            [user_id] => 1
            [display_name] => Colin
            [meta_key] => affiliate_name
            [meta_value] => fake affiliate name 1
        )

    [1] => stdClass Object
        (
            [user_id] => 925
            [display_name] => Hello
            [meta_key] => affiliate_name
            [meta_value] => fake affiliate name 2
        )
)

В этом случае, как видите, результаты включают мета-ключ / значение affiliate_name. Что является лишь частью того, что я хочу. Если я удалю um1.meta_key, um1.meta_value из первого выражения SQL, то получу мета-ключ / значение местоположения.

В принципе, для всех подходящих пользователей («активных» участников, которые хранят данные affiliate_location) мне нужно также вернуть их имя, адрес электронной почты, веб-сайт и номер телефона в одном запросе. В противном случае мне придется выполнить один запрос, чтобы получить всех подходящих пользователей, а затем использовать их значения User_ID для запуска сотен отдельных запросов, чтобы собрать все их партнерские данные. Есть ли способ получить все эти данные в одном запросе?

Заранее большое спасибо за помощь!


UPDATE

Я реализовал решение @ Эдварда. Он предложил 2 решения, одно со стандартным подзапросом JOIN, а другое с более продвинутым OUTER APPLY, но я обнаружил, что моя база данных MySQL не поддерживает синтаксис OUTER APPLY, поэтому я решил реализовать первое решение с парой исправлений (была опечатка с website против web_site) и дополнительным условием в конце основного предложения WHERE. Вот что я попробовал:

SELECT DISTINCT user_meta.user_id, u.display_name, user_meta.loc_key, user_meta.loc_value, user_meta.name_key, user_meta.name_value, user_meta.email_key, user_meta.email_value, user_meta.website_key, user_meta.website_value, user_meta.phone_key, user_meta.phone_value

FROM {$wpdb->prefix}posts AS p
    LEFT JOIN {$wpdb->prefix}posts AS p2 ON p2.ID = p.post_parent
    LEFT JOIN {$wpdb->prefix}users AS u ON u.id = p.post_author
    LEFT JOIN
    (
        SELECT
            loc.user_id,
            loc.meta_key AS loc_key,
            loc.meta_value AS loc_value,
            name.meta_key AS name_key,
            name.meta_value AS name_value,
            email.meta_key AS email_key,
            email.meta_value AS email_value,
            website.meta_key AS website_key,
            website.meta_value AS website_value,
            phone.meta_key  AS phone_key,
            phone.meta_value  AS phone_value

        FROM {$wpdb->prefix}usermeta AS loc
            LEFT JOIN {$wpdb->prefix}usermeta AS name
                ON loc.user_id = name.user_id
                AND name.meta_key = 'affiliate_name'
            LEFT JOIN {$wpdb->prefix}usermeta AS email
                ON loc.user_id = email.user_id
                AND email.meta_key = 'affiliate_email'
            LEFT JOIN {$wpdb->prefix}usermeta AS website
                ON loc.user_id = website.user_id
                AND website.meta_key = 'affiliate_website'
            LEFT JOIN {$wpdb->prefix}usermeta AS phone
                ON loc.user_id = phone.user_id
                AND phone.meta_key = 'affiliate_phone_number'

        WHERE loc.meta_key = 'affiliate_location'
            AND loc.meta_value <> ''

    )  AS user_meta ON user_meta.user_id = u.id

WHERE p.post_type = 'wc_user_membership'
    AND p.post_status IN ('wcm-active', 'wcm-complimentary')
    AND p2.post_type = 'wc_membership_plan'
    AND p2.post_name LIKE '$membership_slug'
    AND user_meta.loc_value <> ''

Это решение достигло именно того, чего я хотел! Без окончательного условия AND user_meta.loc_value <> '' возвращаемый массив включал всех «активных» пользователей, даже если у них были пустые значения affiliate_location. При добавлении окончательного условия эти пользователи были отфильтрованы.

Большое спасибо за вашу помощь @Edward Очень признателен! Я многому научился. Ура!

1 Ответ

0 голосов
/ 06 июля 2018

Я думаю, что нашел вашу проблему. um1.meta_value возвращает NULL, потому что вы не фильтруете um1. на основе не пустоты правила мета-значения affiliate_location, как для um..

В частности, эти строки в предложении WHERE не выполняют то, что вы от них хотите.

  WHERE ...
            AND um.meta_key = 'affiliate_location'
            AND um.meta_value <> ''
            AND um1.meta_key = 'affiliate_name'

Так как в вашем предложении FROM вы используете два LEFT OUTER JOIN.

Я не знаю вашу структуру данных, но добавление чего-то к WHERE может выглядеть так:

  AND um1.user_id = um.user_id -- this is what will force um1. records to match um. records
  AND um1.meta_value <> '' -- this should be removed unless everyone with a location also has an affilicate_name 

Помогает ли это вообще?

07/12

Так что в ответ на ваш комментарий я расширю свой ответ здесь. LEFT JOINS, который вы делаете, действительно извлекает те же столбцы из usermeta, но важно то, что SQL обрабатывает их как два отдельных объекта.

Это важно, поскольку оператор WHERE AND um.meta_key = affiliate_location не будет влиять на столбцы usermeta AS um1, возвращаемые SELECT ... um1.meta_key , um1.meta_value ....

Он не делает то, что вы ожидаете.

Чтобы um1 возвращал только те столбцы, которые вам интересны, вам нужно отфильтровать um, как вы уже сделали, а затем явно заставить um1.id соответствовать um.id.

Вы можете попробовать это тоже.

FROM ..
LEFT JOIN (
  SELECT um.user_id , um.meta_key, um1.meta_value
  FROM usermeta as um 
  INNER JOIN usermeta as um1 
    ON um.user_id = um1.user_id 
  WHERE 
       um.meta_key = 'affiliate_location'
   AND um.meta_value <> '' 
   AND um1.meta_key = 'affiliate_name') AS usermeta 
ON usermeta.user_id = u.id 

Я немного переделал ваш исходный запрос, надеюсь, он вернет то, что вы просили.

    SELECT DISTINCT 
            user_meta.user_id
        ,   u.display_name
        ,   user_meta.loc_key
        ,   user_meta.loc_value
        ,   user_meta.name_key
        ,   user_meta.name_value
        ,   user_meta.email_key
        ,   user_meta.email_value
        ,   user_meta.website_key
        ,   user_meta.website_value
        ,   user_meta.phone_key
        ,   user_meta.phone_value
    FROM {$wpdb->prefix}posts AS p
    LEFT JOIN {$wpdb->prefix}posts AS p2 ON p2.ID = p.post_parent
    LEFT JOIN {$wpdb->prefix}users AS u ON u.id = p.post_author
    LEFT JOIN ( 
        SELECT 
                loc.user_id
            ,   loc.meta_key AS loc_key
            ,   loc.meta_value AS loc_value
            ,   name.meta_key AS name_key
            ,   name.meta_value AS name_value
            ,   email.meta_key AS email_key
            ,   email.meta_value AS email_value
            ,   website.meta_key AS website_key
            ,   website.meta_value AS website_value
            ,   phone.meta_key  AS phone_key
            ,   phone.meta_value  AS phone_value
        FROM {$wpdb->prefix}usermeta AS loc 
        LEFT JOIN {$wpdb->prefix}usermeta AS name 
            ON loc.id = name.user_id
            AND name.meta_key = 'affiliate_name'
        LEFT JOIN {$wpdb->prefix}usermeta AS email 
            ON loc.id = email.user_id
            AND email.meta_key = 'affiliate_email'
        LEFT JOIN {$wpdb->prefix}usermeta AS website
            ON loc.id = website.user_id
            AND web_site.meta_key = 'affiliate_website'
        LEFT JOIN {$wpdb->prefix}usermeta AS phone
            ON loc.id = phone.user_id
            AND phone.meta_key = 'affiliate_phone_number'
        WHERE loc.meta_key = 'affiliate_location'
        AND loc.meta_value <> ''
    )  AS user_meta
    ON user_meta.user_id = u.id 
WHERE p.post_type = 'wc_user_membership'
    AND p.post_status IN ('wcm-active', 'wcm-complimentary')
    AND p2.post_type = 'wc_membership_plan'
    AND p2.post_name LIKE '$membership_slug'
    AND user_meta.loc_value <> ''

Это может быть довольно неэффективно из-за всех LEFT JOINS.

07/13 - вышеуказанное решение с LEFT OUTER JOIN работает на mySQL. Если кто-то пытается что-то похожее на SQLServer, то ему может повезти с методом OUTER APPLY, поэтому я оставляю это в этом ответе.

SELECT DISTINCT 
            um.user_id
        ,   u.display_name
        ,   meta_data.meta_key
        ,   meta_data.meta_value
    FROM {$wpdb->prefix}posts AS p
    LEFT JOIN {$wpdb->prefix}posts AS p2 ON p2.ID = p.post_parent
    LEFT JOIN {$wpdb->prefix}users AS u ON u.id = p.post_author
    LEFT JOIN {$wpdb->prefix}usermeta as um ON um.user_id = u.id 
    OUTER APPLY ( 
            SELECT meta_key , meta_value
            FROM usermeta as um1 
            WHERE um1.meta_key IN ('affiliate_name', 'affiliate_phone_number' , 'affiliate_email' , 'affiliate_website')
            AND um1.user_id = um.user_id
            ORDER BY um1.meta_key ASC 
        ) as meta_data 
    WHERE p.post_type = 'wc_user_membership'
    AND p.post_status IN ('wcm-active', 'wcm-complimentary')
    AND p2.post_type = 'wc_membership_plan'
    AND p2.post_name LIKE '$membership_slug'
    AND um.meta_key = 'affiliate_location'
    AND um.meta_value <> ''
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...