Как ограничить количество пользовательских постов, которые определенные пользователи могут публиковать в WordPress с помощью PHP-скрипта?

Вопрос или проблема

Фон:
Я попробовал как https://wordpress.org/plugins/bainternet-posts-creation-limits, так и https://wordpress.org/plugins/limit-posts/, но по какой-то причине они не работали с моими пользовательскими записями. Поэтому я решил написать свой собственный PHP скрипт, который добавил в файл functions.php своей дочерней темы, чтобы ограничить количество некоторых типов пользовательских записей, которые определенные пользователи могут создавать.

Структура:
Я использую WordPress 5.4.2, установленный на Bluehost. Я использую GeoDirectory для создания пользовательских типов записей (практикующие и организации) и MemberPress для управления правами доступа.
Я решил отфильтровать wp_post_data, потому что все, что я хочу сделать, это изменить статус записи при ее первом создании, в зависимости от того, сколько записей автор уже создал. Некоторые предлагали использовать wp_insert_post_empty_content, но я думаю, что более подходящий вариант — это позволить им сначала создать настоящую запись как черновик, а затем попросить их получить соответствующую подписку для публикации.

Ограничения:
Поскольку другой плагин на моем сайте предоставляет привилегии только для определенной роли, я даю всем, кто не является администратором, эту определенную роль пользователя и, следовательно, не могу ограничить права на публикацию по роли пользователя. Вот почему я использую подписку MemberPress для регулирования возможности публикации.

Проблема/Что не так:
После запуска кода:
1- Все пользователи, вместо того чтобы только не администраторы с недостаточными подписками, не могут сохранять новые CPT. Даже администратор не может сохранить CPT.
2- Пользователи получают это сообщение, когда нажимают отправить: “У вас нет привилегий для выполнения этого действия.” Я написал другое сообщение, чтобы сообщить пользователю, у которого неправильная подписка для этого действия.

Подход:

<?php
//Перед тем, как новая запись будет сохранена в базе данных, фильтруем по подписке
add_filter('wp_insert_post_data', 'tml_filter_by_membership', 99, 2);
/**
 99 обозначает приоритет, при котором этот фильтр выполняется; 99 указывает, что это один из последних фильтров, выполняемых при этом действии
 2 указывает, что мы хотим оба аргумента, предоставленных фильтром (поскольку второй содержит очищенные, но не измененные данные, которые нам нужны). Без 2 функция по умолчанию принимает 1, что дает нам только экранированные данные записи
 *
 */

//фильтрация по подписке действует только на неадминистраторские записи определенных типов записей
function tml_filter_by_membership($data, $postarr)
{

    //принимаем только неадминистраторские записи
    if (!user_can($postarr['post_author'], 'manage_options'))
    {

        // продолжаем только если тип записи - gd_practitioner или gd_organization
        if ($postarr['post_type'] == 'gd_practitioner' || $postarr['post_type'] == 'gd_organization')
        {

            //Установить лимиты на записи по подписке по типу записи
            $membership_post_limits = tml_set_membership_post_limits_by_post_type();

            //Получить подписку автора
            $author_memberships = tml_get_post_author_memberships($postarr);

            //Посмотреть лимит записей автора для этого типа записи в массиве лимитов записей по подписке
            $author_post_limit = tml_get_author_post_limit($author_memberships, $membership_post_limits, $postarr);

            //Посчитать опубликованные записи автора определенного типа записи
            $number_of_published_posts_by_author = tml_get_author_published_posts($postarr);

            //Сравнить количество опубликованных записей с лимитом автора и вернуть $postarr
            tml_compare_posts_to_limit($author_post_limit, $number_of_published_posts_by_author, $postarr);
        }
    }
}

//установить лимиты на записи по подписке по типу записи
function tml_set_membership_post_limits_by_post_type()
{
    $membership_post_limits = Array(
        462 => Array(
            'gd_practitioner' => 1,
            'gd_organization' => 1
        ) ,
        463 => Array(
            'gd_practitioner' => 1,
            'gd_organization' => 1
        ) ,
        464 => Array(
            'gd_practitioner' => 1,
            'gd_organization' => 1
        ) ,
        465 => Array(
            'gd_practitioner' => 10,
            'gd_organization' => 10
        ) ,
        466 => Array(
            'gd_practitioner' => 1,
            'gd_organization' => 1
        ) ,
        467 => Array(
            'gd_practitioner' => 10,
            'gd_organization' => 10
        ) ,
        752 => Array(
            'gd_practitioner' => 1,
            'gd_organization' => 1
        ) ,
        753 => Array(
            'gd_practitioner' => 1,
            'gd_organization' => 1
        ) ,
        754 => Array(
            'gd_practitioner' => 1,
            'gd_organization' => 1
        )
    );
    return $membership_post_limits;
}

//Получить подписку автора
function tml_get_post_author_memberships($postarr)
{
    if (class_exists('MeprUser'))
    {
        $user_id = $postarr['post_author'];
        $user = new MeprUser($user_id);
        $get_memberships = $user->active_product_subscriptions();
        $author_memberships = array_values(array_unique($get_memberships));
        return $author_memberships;
    }
    else
    {
        return false;
    }
}

//Посмотреть лимит записей автора для этого типа записи в массиве лимитов записей по подписке, используя $postarr для указания типа записи и $user_memberships для указания подписок автора
function tml_get_author_post_limit($author_memberships, $membership_post_limits, $postarr)
{
    $author_post_limit = 1;
    foreach ($author_memberships as $membership)
    {
        if ($author_post_limit < $membership_post_limits[$membership][$postarr['post_type']])
        {
            $author_post_limit = $membership_post_limits[$membership][$postarr['post_type']];
        }
    }
    return $author_post_limit;
}

//Посчитать опубликованные записи автора определенного типа записи
function tml_get_author_published_posts($postarr)
{
    $posts = get_posts(array(
        'author' => $postarr['post_author'],
        'post_type ' => $postarr['post_type'],
        'numberposts ' => - 1,
        'post_status ' => 'publish'
    ));
    $number_of_published_posts_by_author = count($posts);
    return $number_of_published_posts_by_author;
}

/**
 //Другой вариант, используя функцию count_user_posts вместо
 function tml_get_author_published_posts($postarr){
 $author= $postarr['post_author'];
 $post_type = $postarr['post_type'];
 $number_of_published_posts_by_author=count_user_posts($author, $post_type);
 return $number_of_published_posts_by_author;
 }
 *
 */

//Сравнить количество опубликованных записей с лимитом автора
function tml_compare_posts_to_limit($author_post_limit, $number_of_published_posts_by_author, $postarr)
{
    $message = "";
    if ($number_of_published_posts_by_author >= $author_post_limit)
    {
        $postarr['post_status'] = 'draft';
        $message = "Вы превысили количество записей для вашей подписки";
    }
    echo "<div> ${message} </div>";
    return $postarr;
}

Добро пожаловать в StackExchange! Я внес некоторые изменения в ваш код, которые отметил комментариями. Я не уверен, что это сработает, поэтому вам придется попробовать, и, вероятно, ваш способ вывода сообщения не сработает, потому что после обновления происходит перенаправление, поэтому вам придется работать с действием admin_notices и найти способ сохранить сообщение после перенаправления. Однако я думаю, что это тема для другого вопроса, поэтому я заменил часть вывода на error_log, что будет достаточно, чтобы определить, работает ли это так, как задумано, посмотрев на логи.

<?php
add_filter('wp_insert_post_data', 'tml_filter_by_membership', 99, 2);

/* 
При использовании фильтра первый аргумент всегда является данными, которые нужно изменить и вернуть. 
Обычно вы проверяете, хотите ли вы что-то изменить, в противном случае вы возвращаете
первый аргумент ($data), чтобы другие фильтры тоже могли работать. Если вы ничего не вернете,
то, вероятно, сломаете что-то. Здесь вы должны использовать $data вместо $postarr,
которые являются одним и тем же массивом, но последний ($postarr) — необработанный.
*/
function tml_filter_by_membership($data, $postarr)
{

    /* Если вы хотите брать только неадминистраторских пользователей, не проверяйте способности, проверьте
вместо этого конкретную роль. */
    if (!in_array('administrator', get_user_by('ID', $data['post_author'])->roles))
    {

        if ($data['post_type'] == 'gd_practitioner' || $data['post_type'] == 'gd_organization')
        {

            $membership_post_limits = tml_set_membership_post_limits_by_post_type();

            $author_memberships = tml_get_post_author_memberships($data['post_author']);

            $author_post_limit = tml_get_author_post_limit($author_memberships, $membership_post_limits, $data);

            $number_of_published_posts_by_author = tml_get_author_published_posts($data);
            /* Я подумал, что последняя функция была ненужной, поэтому просто удалил ее и переместил
ее код сюда. */
            if ($number_of_published_posts_by_author >= $author_post_limit)
            {
                $data['post_status'] = 'draft';
                /* Проверьте свои логи, чтобы увидеть, работает ли это на самом деле. Отображение
сообщения - это то, что вы можете решить позже. */
                error_log('Вы превысили количество записей для вашей подписки');
            }
            /* Верните ваш измененный объект. Ранее вы использовали функцию, которая
возвращала что-то, но возврат должен быть внутри области действия функции, связанной с
фильтром, чтобы на самом деле это вернуть. Ранее вы ничего не возвращали. */
            return $data;

        }
    }

    return $data;
}

function tml_set_membership_post_limits_by_post_type()
{
    $membership_post_limits = Array(
        462 => Array(
            'gd_practitioner' => 1,
            'gd_organization' => 1
        ) ,
        463 => Array(
            'gd_practitioner' => 1,
            'gd_organization' => 1
        ) ,
        464 => Array(
            'gd_practitioner' => 1,
            'gd_organization' => 1
        ) ,
        465 => Array(
            'gd_practitioner' => 10,
            'gd_organization' => 10
        ) ,
        466 => Array(
            'gd_practitioner' => 1,
            'gd_organization' => 1
        ) ,
        467 => Array(
            'gd_practitioner' => 10,
            'gd_organization' => 10
        ) ,
        752 => Array(
            'gd_practitioner' => 1,
            'gd_organization' => 1
        ) ,
        753 => Array(
            'gd_practitioner' => 1,
            'gd_organization' => 1
        ) ,
        754 => Array(
            'gd_practitioner' => 1,
            'gd_organization' => 1
        )
    );
    return $membership_post_limits;
}

function tml_get_post_author_memberships($user_id)
{
    if (class_exists('MeprUser'))
    {

        $user = new MeprUser($user_id);
        $get_memberships = $user->active_product_subscriptions();
        $author_memberships = array_values(array_unique($get_memberships));
        return $author_memberships;
    }
    else
    {
        return false;
    }
}

function tml_get_author_post_limit($author_memberships, $membership_post_limits, $data)
{
    $author_post_limit = 1;
    foreach ($author_memberships as $membership)
    {
        if ($author_post_limit < $membership_post_limits[$membership][$data['post_type']])
        {
            $author_post_limit = $membership_post_limits[$membership][$data['post_type']];
        }
    }
    return $author_post_limit;
}

function tml_get_author_published_posts($data)
{

    return count(get_posts(array(
        'author' => $data['post_author'],
        'post_type ' => $data['post_type'],
        'numberposts ' => - 1,
        'post_status ' => 'publish'
    )));

}

Ответ или решение

Для ограничения числа пользовательских постов, которые определённые пользователи могут публиковать в WordPress, можно использовать фильтр wp_insert_post_data. Данный подход позволяет модифицировать данные поста перед его сохранением в базе данных.

Вот полный скрипт, который можно добавить в файл functions.php вашей дочерней темы. Этот код учтёт, сколько постов определённого типа может создать пользователь на основе его подписки:

<?php
add_filter('wp_insert_post_data', 'tml_filter_by_membership', 99, 2);

/**
 * Функция фильтрации данных перед сохранением поста
 */
function tml_filter_by_membership($data, $postarr) {
    // Проверка на непотребляемого пользователя (не администратор)
    if (!in_array('administrator', get_user_by('ID', $data['post_author'])->roles)) {
        // Если пост тип соответствует нужным
        if ($data['post_type'] == 'gd_practitioner' || $data['post_type'] == 'gd_organization') {
            $membership_post_limits = tml_set_membership_post_limits_by_post_type();

            // Получаем подписки автора
            $author_memberships = tml_get_post_author_memberships($data['post_author']);

            // Получаем лимит постов для этого автора
            $author_post_limit = tml_get_author_post_limit($author_memberships, $membership_post_limits, $data);

            // Подсчитываем опубликованные посты этого автора
            $number_of_published_posts_by_author = tml_get_author_published_posts($data);

            // Сравниваем количество опубликованных постов с лимитом
            if ($number_of_published_posts_by_author >= $author_post_limit) {
                $data['post_status'] = 'draft';
                error_log('Вы превысили лимит постов для вашей подписки');
            }
        }
    }

    // Возвращаем измененный объект данных
    return $data;
}

/**
 * Задаем лимиты постов по типу подписки
 */
function tml_set_membership_post_limits_by_post_type() {
    return array(
        462 => array('gd_practitioner' => 1, 'gd_organization' => 1),
        463 => array('gd_practitioner' => 1, 'gd_organization' => 1),
        464 => array('gd_practitioner' => 1, 'gd_organization' => 1),
        465 => array('gd_practitioner' => 10, 'gd_organization' => 10),
        466 => array('gd_practitioner' => 1, 'gd_organization' => 1),
        467 => array('gd_practitioner' => 10, 'gd_organization' => 10),
        752 => array('gd_practitioner' => 1, 'gd_organization' => 1),
        753 => array('gd_practitioner' => 1, 'gd_organization' => 1),
        754 => array('gd_practitioner' => 1, 'gd_organization' => 1)
    );
}

/**
 * Получаем подписки автора
 */
function tml_get_post_author_memberships($user_id) {
    if (class_exists('MeprUser')) {
        $user = new MeprUser($user_id);
        $get_memberships = $user->active_product_subscriptions();
        return array_values(array_unique($get_memberships));
    } else {
        return false;
    }
}

/**
 * Получаем лимит постов для конкретной подписки
 */
function tml_get_author_post_limit($author_memberships, $membership_post_limits, $data) {
    $author_post_limit = 1; // Значение по умолчанию
    foreach ($author_memberships as $membership) {
        if (isset($membership_post_limits[$membership][$data['post_type']])) {
            $author_post_limit = max($author_post_limit, $membership_post_limits[$membership][$data['post_type']]);
        }
    }
    return $author_post_limit;
}

/**
 * Подсчитываем опубликованные посты данного автора
 */
function tml_get_author_published_posts($data) {
    return count(get_posts(array(
        'author' => $data['post_author'],
        'post_type' => $data['post_type'],
        'numberposts' => -1,
        'post_status' => 'publish'
    )));
}
?>

Объяснение:

  1. Фильтер wp_insert_post_data: Ваш код использует этот фильтр для изменения данных поста перед их сохранением.

  2. Проверка авторских прав: Функция tml_filter_by_membership проверяет, не является ли пользователь администратором, а затем проверяет тип поста. Если это пользователь и он создает определённый тип поста, функция продолжает выполнение.

  3. Получение лимитов по типу подписки: Функция tml_set_membership_post_limits_by_post_type задает, сколько постов может создать пользователь в зависимости от его подписки.

  4. Сравнение и установка статуса поста: Если количество уже опубликованных постов пересекает этот лимит, статус нового поста устанавливается как draft.

  5. Логирование сообщений: Для отладки используется error_log, чтобы отправить сообщение в журнал ошибок: "Вы превысили лимит постов для вашей подписки".

Запросите функциональность дополнительного сообщения пользователям о превышении лимита постов. Вы можете использовать один из механизмов admin_notices, чтобы управлять пользовательскими уведомлениями.

Попробуйте эти изменения и посмотрите, как это повлияет на вашу установку WordPress.

Оцените материал
Добавить комментарий

Капча загружается...