Вопрос или проблема
Фон:
Я попробовал как 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'
)));
}
?>
Объяснение:
-
Фильтер
wp_insert_post_data
: Ваш код использует этот фильтр для изменения данных поста перед их сохранением. -
Проверка авторских прав: Функция
tml_filter_by_membership
проверяет, не является ли пользователь администратором, а затем проверяет тип поста. Если это пользователь и он создает определённый тип поста, функция продолжает выполнение. -
Получение лимитов по типу подписки: Функция
tml_set_membership_post_limits_by_post_type
задает, сколько постов может создать пользователь в зависимости от его подписки. -
Сравнение и установка статуса поста: Если количество уже опубликованных постов пересекает этот лимит, статус нового поста устанавливается как
draft
. -
Логирование сообщений: Для отладки используется
error_log
, чтобы отправить сообщение в журнал ошибок: "Вы превысили лимит постов для вашей подписки".
Запросите функциональность дополнительного сообщения пользователям о превышении лимита постов. Вы можете использовать один из механизмов admin_notices
, чтобы управлять пользовательскими уведомлениями.
Попробуйте эти изменения и посмотрите, как это повлияет на вашу установку WordPress.