Вопрос или проблема
В данный момент Gamipress позволяет вам импортировать CSV файл, который содержит имя пользователя (электронную почту или ID) и значение очков, которое нужно добавить к типу очков для этого пользователя. Для достижения этой цели используется данная функция, которая записывает в журнал gamipress.
/**
* AJAX обработчик для инструмента импорта очков
*
* @since 1.6.4
*/
function gamipress_import_export_points_tool_ajax_import() {
// Проверка безопасности, завершает работу, если безопасность не пройдена
check_ajax_referer( 'gamipress_admin', 'nonce' );
// Проверка прав пользователя
if( ! current_user_can( gamipress_get_manager_capability() ) ) {
wp_send_json_error( __( 'Вам не разрешено выполнять это действие.', 'gamipress' ) );
}
// Проверка полученных параметров
if( ! isset( $_FILES['file'] ) ) {
wp_send_json_error( __( 'Нет файла для импорта.', 'gamipress' ) );
}
$import_file = $_FILES['file']['tmp_name'];
if( empty( $import_file ) ) {
wp_send_json_error( __( 'Не удаётся получить файл для импорта, проверьте права доступа к файлам сервера.', 'gamipress' ) );
}
ignore_user_abort( true );
if ( ! gamipress_is_function_disabled( 'set_time_limit' ) ) {
set_time_limit( 0 );
}
// Получение содержимого файла
$file_contents = file_get_contents( $import_file );
if( empty( $file_contents ) ) {
wp_send_json_error( __( 'Пустой файл, нечего импортировать.', 'gamipress' ) );
}
// Настройка переменных
$points_types = gamipress_get_points_types();
// Разделение по переносам строк
$lines = explode( "\n", $file_contents );
foreach( $lines as $number => $line ) {
$columns = str_getcsv( $line );
if( count( $columns ) >= 3 ) {
$user = false;
$points = 0;
$points_type="";
$log_description = '';
$deduct = false;
// Пользователь
if( isset( $columns[0] ) && ! empty( $columns[0] ) ) {
$user_field = 'login';
if( filter_var( $columns[0], FILTER_VALIDATE_EMAIL ) ) {
$user_field = 'email';
} else if( is_numeric( $columns[0] ) ) {
$user_field = 'id';
}
$user = get_user_by( $user_field, $columns[0] );
}
// Очки
if( isset( $columns[1] ) && is_numeric( $columns[1] ) ) {
// Если сумма очков имеет отрицательный знак, значит, пользователь хочет вычесть
if ( substr( $columns[1], 0, 1 ) === '-') {
$deduct = true;
$columns[1] = substr( $columns[1], 1); // Удалить отрицательный знак
}
$points = absint( $columns[1] );
}
// Тип очков
if( isset( $columns[2] ) && ! empty( $columns[2] ) && isset( $points_types[$columns[2]] ) ) {
$points_type = $columns[2];
}
// Описание журнала
if( isset( $columns[3] ) && ! empty( $columns[3] ) ) {
$log_description = $columns[3];
}
// Проверка, выполнено ли всё
if( $user && $points > 0 && ! empty( $points_type ) ) {
// При награждении очками, передав ID администратора, нам нужно передать полную новую сумму
$current_points = gamipress_get_user_points( $user->ID, $points_type );
$args = array(
'admin_id' => get_current_user_id(),
'reason' => $log_description,
'log_type' => 'points_award'
);
// Если описание журнала пустое, пусть GamiPress настроит его из настроек журнала
if( empty( $log_description ) ) {
$args = array( 'admin_id' => get_current_user_id() );
}
if( $deduct ) {
// Вычесть очки у пользователя
gamipress_deduct_points_to_user( $user->ID, $current_points - $points, $points_type, $args );
} else {
// Наградить очками пользователя
gamipress_award_points_to_user( $user->ID, $points + $current_points, $points_type, $args );
}
}
}
}
// Возвратить сообщение об успешном завершении
wp_send_json_success( __( 'Баланс очков пользователя был успешно обновлён.', 'gamipress' ) );
}
add_action( 'wp_ajax_gamipress_import_export_points_tool_import', 'gamipress_import_export_points_tool_ajax_import' );
Эта функция не добавляет очки к общий счет пользователей. Она просто записывает это в журнал. У меня есть функция, которую я написал, чтобы зарегистрировать очки для пользователя. Однако она регистрирует общую сумму очков, а не добавляет значение очков – так как функция импорта передаёт очки +/- текущие очки. Я хотел бы зарегистрировать значение очков – не очки +/- текущие очки.
//Gamipress - Регистрация очков пользователя при импорте очков из CSV
function ofc_insert_user_earning_on_import_points_tool( $user_id, $points, $points_type, $args ) {
if( ! defined( 'DOING_AJAX' ) ) return;
if( ! DOING_AJAX ) return;
if( ! isset( $_REQUEST['action'] ) ) return;
if( $_REQUEST['action'] !== 'gamipress_import_export_points_tool_import' ) return;
$points_type_obj = gamipress_get_points_type( $points_type );
$award = ( current_filter() === 'gamipress_award_points_to_user' );
if( ! $award ) {
$points *= -1;
}
gamipress_insert_user_earning( $user_id, array(
'title' => ( isset( $args['reason'] ) ? $args['reason'] : '' ),
'post_id' => $points_type_obj['ID'],
'post_type' => 'points-type',
'points' => $points,
'points_type' => $points_type,
'date' => date( 'Y-m-d H:i:s', current_time( 'timestamp' ) ),
) );
}
add_action( 'gamipress_award_points_to_user', 'ofc_insert_user_earning_on_import_points_tool', 10, 4 );
add_action( 'gamipress_deduct_points_to_user', 'ofc_insert_user_earning_on_import_points_tool', 10, 4 );
Как мне подключиться к функции gamipress_import_export_points_tool_ajax_import, чтобы получить $points вместо общей суммы очков? (Надеюсь, это имеет смысл)
Оказывается, всё было так просто, как добавить эту строку в мою функцию:
$current_total_points = gamipress_get_user_points( $user_id, $points_type);
И затем передать $points – $current_total_points в функцию вставки заработка пользователя GamiPress.
function ofc_insert_user_earning_on_import_points_tool( $user_id, $points, $points_type, $args ) {
if( ! defined( 'DOING_AJAX' ) ) return;
if( ! DOING_AJAX ) return;
if( ! isset( $_REQUEST['action'] ) ) return;
if( $_REQUEST['action'] !== 'gamipress_import_export_points_tool_import' ) return;
$points_type_obj = gamipress_get_points_type( $points_type );
$award = ( current_filter() === 'gamipress_award_points_to_user' );
//если мы вычитаем очки, то делаем очки отрицательными
if( ! $award ) {
$points *= -1;
}
$current_total_points = gamipress_get_user_points( $user_id, $points_type);
gamipress_insert_user_earning( $user_id, array(
'title' => ( isset( $args['reason'] ) ? $args['reason'] : '' ),
'post_id' => $points_type_obj['ID'],
'post_type' => 'points-type',
'points' => $points - $current_total_points,
'points_type' => $points_type,
'date' => date( 'Y-m-d H:i:s', current_time( 'timestamp' ) ),
) );
}
add_action( 'gamipress_award_points_to_user', 'ofc_insert_user_earning_on_import_points_tool', 10, 4 );
add_action( 'gamipress_deduct_points_to_user', 'ofc_insert_user_earning_on_import_points_tool', 10, 4 );
Ответ или решение
Как использовать хуки или фильтры, или переписать функцию Gamipress?
В вопросе рассматривается ситуация, когда необходимо изменить поведение функции gamipress_import_export_points_tool_ajax_import
, чтобы при импорте очков из CSV-файла добавлялись не общие баллы пользователя, а только значения очков, указанные в импорте. Ниже представлена подробная инструкция по решению этой задачи.
Проблема
Gamipress в своем базовом функционале лишь записывает сумму очков для пользователя в лог, без их фактического добавления к текущему балансу. Переписывание функции, как правило, не рекомендуется из-за возможных проблем с обновлениями и совместимостью с другими плагинами. Вместо этого лучше использовать хуки и фильтры.
Решение
-
Использование хуков:
Вам необходимо использовать хукgamipress_award_points_to_user
для обработки процесса добавления очков к пользователю. Этот хук позволит вам изменить логику добавления очков в систему. -
Извлечение текущего количества очков:
Чтобы правильно управлять очками, вы можете добавить следующую строку в вашу функцию:$current_total_points = gamipress_get_user_points($user_id, $points_type);
-
Модификация функции:
Теперь вам нужно изменить логику, чтобы вместо установки нового количества очков, система корректно добавляла только новые очки. Обновленная функция может выглядеть следующим образом:function ofc_insert_user_earning_on_import_points_tool($user_id, $points, $points_type, $args) { if (!defined('DOING_AJAX') || !DOING_AJAX) return; if (!isset($_REQUEST['action']) || $_REQUEST['action'] !== 'gamipress_import_export_points_tool_import') return; $points_type_obj = gamipress_get_points_type($points_type); $award = (current_filter() === 'gamipress_award_points_to_user'); // Учитываем вычитание очков if (!$award) { $points *= -1; } // Получаем текущее количество очков $current_total_points = gamipress_get_user_points($user_id, $points_type); // Записываем новые очки gamipress_insert_user_earning($user_id, array( 'title' => (isset($args['reason']) ? $args['reason'] : ''), 'post_id' => $points_type_obj['ID'], 'post_type' => 'points-type', 'points' => $points - $current_total_points, // Изменение здесь 'points_type' => $points_type, 'date' => date('Y-m-d H:i:s', current_time('timestamp')), )); } add_action('gamipress_award_points_to_user', 'ofc_insert_user_earning_on_import_points_tool', 10, 4); add_action('gamipress_deduct_points_to_user', 'ofc_insert_user_earning_on_import_points_tool', 10, 4);
Заключение
Ваше изменение теперь будет корректно обрабатывать добавление очков для пользователя, основываясь на импорте из CSV. Вместо того чтобы переопределять основную функцию Gamipress, вы используете хуки, что обеспечивает более стабильную и совместимую реализацию. Это решение позволяет избежать трудностей с обновлениями плагина и сохраняет гибкость в дальнейшем развитии вашей функциональности.
Вопрос, как изменить поведение gamipress_import_export_points_tool_ajax_import
не всегда очевиден, однако использование хуков и фильтров в WordPress предоставляет множество возможностей для кастомизации — что и продемонстрировано в этом решении.