Исключить ранее созданные посты в последующих блоках (в редакторе)

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

У меня есть пользовательский блок списка постов, который я использую несколько раз на одной странице. На фронтенде я могу отслеживать ранее отрисованные посты и исключать их из последующих блоков. Но в редакторе это не так просто. Я попытался зарегистрировать хранилище, добавить отрисованные идентификаторы постов в состояние и отправить excludedPosts с fetch и исключить их в wp_query в ответе REST. Но это, похоже, не работает. Я не эксперт по react, поэтому не уверен, почему. Буду признателен за любые советы!

Вот моя текущая реализация:

import { __ } from '@wordpress/i18n';
import { createReduxStore, register, useDispatch, useSelect } from '@wordpress/data';
import apiFetch from '@wordpress/api-fetch';
import { useState, useEffect } from '@wordpress/element';
import { useBlockProps } from '@wordpress/block-editor';
import './editor.css';
import PostListPost from './components/PostListPost';

const DEFAULT_STATE = {
    excludedPosts: []
};

const actions = {
    addExcludedPost(postId) {
        return {
            type: 'ADD_EXCLUDED_POST',
            postId
        }
    },
    removeExcludedPost(postId) {
        return {
            type: 'REMOVE_EXCLUDED_POST',
            postId
        }
    }
};

const reducer = (state = DEFAULT_STATE, action) => {
    switch (action.type) {
        case 'ADD_EXCLUDED_POST':
            return {
                ...state,
                excludedPosts: [...state.excludedPosts, action.postId]
            };
        case 'REMOVE_EXCLUDED_POST':
            return {
                ...state,
                excludedPosts: state.excludedPosts.filter((postId) => postId !== action.postId)
            };
        default:
            return state;
    }
};

const selectors = {
    getExcludedPosts(state) {
        return state.excludedPosts;
    }
};

const store = createReduxStore('my-post-list', {reducer, actions, selectors});

register(store);

export default function Edit({attributes, setAttributes}) {
    const blockProps = useBlockProps();
    const [posts, setPosts] = useState([]);

    const {addExcludedPost} = useDispatch('my-post-list');

    const excludedPosts = useSelect((select) => select('my-post-list').getExcludedPosts());

    useEffect(() => {
        apiFetch({
            path: '/my-post-list/v1/posts', 
            method: 'POST', 
            data: {
                ...attributes,
                excludedPosts: excludedPosts
            }
        }).then((response) => {
            setPosts(response.posts);
            response.posts.map(post => {
                if (excludedPosts.indexOf(post.id) === -1) {
                    addExcludedPost(post.id);
                }
            });
        });
    }, [attributes]);

    return (
        <>
            <div { ...blockProps }>
                {posts.map((post) => {
                    return <PostListPost key={post.id} post={post} />
                })}
            </div>
        </>
    );
}

И функция ответа REST API:

function my_post_list_get_posts(WP_REST_Request $request) {
    $params = $request->get_params();

    $args = [
        'post_type' => $params['postTypes'],
        'post_status' => 'publish',
        'posts_per_page' => $params['postsToShow'],
        'post__not_in' => $params['excludedPosts'] ?? []
    ];

    $query = new WP_Query($args);

    $posts = [];

    if ($query->have_posts()) {
        while ($query->have_posts()) {
            $query->the_post();
            
            $posts[] = [
                'id' => get_the_ID(),
                'title' => get_the_title(),
            ];
        }
    }

    return [
        'posts' => $posts,
    ];
}

add_action('rest_api_init', function () {
    register_rest_route('my-post-list/v1', '/posts', [
        'methods' => 'POST',
        'callback' => 'my_post_list_get_posts',
        'permission_callback' => '__return_true',
    ]);
});

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

Исключение ранее рендеренных постов в последующих блоках редактора: подробный разбор

Введение

Создание пользовательских компонентов в редакторе WordPress (Gutenberg) требует внимательного подхода, особенно когда речь идет о рендеринге постов. В данной статье мы рассмотрим проблему исключения ранее рендеренных постов в последующих блоках редактора, что важно для поддержания уникальности контента на странице.

Проблема

На текущий момент, ваша реализация пытается отслеживать уже отображенные посты и исключать их из выборки в новых блоках. Тем не менее, вы столкнулись с тем, что в редакторе не удается корректно исключить эти посты, несмотря на настройку Redux Store и изменения в wp_query.

Решение

Чтобы эффективно решить проблему, давайте разберем шаги, которые можно предпринять для корректного функционирования вашего блока.

  1. Проверка состояния Redux Store:
    Убедитесь, что состояние вашего хранилища корректно обновляется. Проверьте, что excludedPosts правильно добавляет и удаляет идентификаторы постов. Для этого добавьте логирование в функции-редюсеры и действия, чтобы убедиться, что состояние корректно обновляется.

    case 'ADD_EXCLUDED_POST':
       console.log("Добавление исключенного поста:", action.postId);
       return {
           ...state,
           excludedPosts: [...state.excludedPosts, action.postId]
       };

    Это поможет вам выявить возможные проблемы в том, как управляется состояние.

  2. Проверка вызова API:
    Ваша функция my_post_list_get_posts обрабатывает входящие параметры. Убедитесь, что excludedPosts правильно передаются в запросе. Кроме того, используйте console.log в функции API, чтобы убедиться, что полученные параметры корректные:

    function my_post_list_get_posts(WP_REST_Request $request) {
       $params = $request->get_params();
       error_log(print_r($params, true)); // Логирование параметров
       // ...
    }
  3. Обновление состояний в компоненте:
    Обратите внимание на порядок обновления состояний в useEffect. Вы должны обновить состояние excludedPosts до выполнения запроса API для того, чтобы гарантировать, что в запрос отправляются актуальные данные.

    useEffect(() => {
       if (excludedPosts.length === 0) {
           return; // остановка эффекта, если нет исключенных постов
       }
       apiFetch({
           path: '/my-post-list/v1/posts',
           method: 'POST',
           data: {
               ...attributes,
               excludedPosts: excludedPosts
           }
       }).then((response) => {
           setPosts(response.posts);
           response.posts.forEach(post => {
               if (!excludedPosts.includes(post.id)) {
                   addExcludedPost(post.id); // добавление рендеренного поста
               }
           });
       });
    }, [attributes, excludedPosts]); // добавляем excludedPosts в зависимости
  4. Оптимизация работы с данными:
    Если ваши посты рендерятся на разных блоках, вы можете рассмотреть возможность хранения идентификаторов исключенных постов в атрибутах блока, чтобы предотвратить повторный вызов вызовов API и избежать дублирования. Например:

    setAttributes({ excludedPosts: [...excludedPosts, post.id] });

    Это обеспечит более чистую и предсказуемую работу вашей реализации.

Заключение

Правильное исключение ранее рендеренных постов в редакторе Gutenberg потребует внимательного анализа работы вашего Redux Store, API запросов и управления состоянием компонентов. С помощью вышеописанных рекомендаций вы сможете оптимизировать свою реализацию, что позволит избежать дублирования контента в блоках на странице.

Советы по SEO

  • Применение логов для отслеживания состояния и данных API обеспечивает лучшее понимание работы вашего кода, что помогает повысить его производительность.
  • Убедитесь, что ваши компоненты непосредственно связаны с пользовательским опытом, предоставляя актуальные и уникальные данные, что приводит к повышению вовлеченности пользователей.

Следуя этим рекомендациям, вы сможете создать более эффективный и интуитивно понятный редактор постов в WordPress.

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

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