Як зробити статус відкритих / закритих та прихованих / показаних метаполев збереженими на основі повідомлення?


9

Моя реальна проблема трохи складна, тому я спробую тут її абстрагувати і просто робити.

Я працюю на користувальницькі додатки на основі WordPress. Я зареєстрував спеціальний тип публікації, назвемо його "люди", де я зберігаю інформацію про ... людей.

CPT підтримує лише поля заголовка публікації та публікації вмісту за замовчуванням, але є деякі метабокси для зберігання інформації про людину (думаю, що моя програма як адресна книга).

Отже, існує метабокс для зберігання особистої інформації, один для зберігання інформації про соціальні мережі, інший для зберігання інформації, пов’язаної з роботою, тобто якщо ця людина для мене - замовник, постачальник, якщо у нас є кредити чи дебети ...

Я спростив тут, але є послідовна кількість метабокс, скажімо 12.

Моя проблема полягає в тому, що деякі люди, для яких я хочу зберігати інформацію, - це лише випадкові контакти, і я хочу зберігати лише особисту інформацію, інші - друзі, і я хочу зберігати особисту інформацію та інформацію про соціальні мережі, інші - клієнти чи постачальники, і я хочете зберігати інформацію про роботу.

Якщо під час редагування публікації я ховаюсь (через меню опцій екрана ) або закриваю будь-яке метаполе, яке мені не потрібно, коли я відкриваю іншу публікацію там, де мені це потрібно, я повинен показати або відкрити їх ще раз. Це тому, що положення / статус / порядок метаполез зберігаються на основі кожного користувача як метадані .

Якщо ви уявляєте, що в деяких публікаціях мені потрібні 2 метабокси, в деяких 10 і в деяких 5, ви розумієте, що це дратує, оскільки зберігання всіх показаних / відкритих робить екран редагування низьким доступним (смуга прокрутки здається нескінченною), а іноді інформація, яку я шукаю, - це в кінці сторінки після зв'язки метабоксов, без інформації ...

Питання:

Чи можливо зберегти положення / статус / замовлення метаполез на основі опублікування для певного типу публікації?


PS: Я знаю, що деякі JS / JQuery може вирішити проблему, але якщо це можливо, я хотів би уникнути JavaScript рішень.

Відповіді:


8

Основна проблема:

Основна проблема тут полягає в тому, що під час закриття , приховування та замовлення ajax-дзвінків немає ідентифікатора пошти, що надсилається з корисним навантаженням. Ось два приклади даних форми:

1) action:closed-postboxes
closed:formatdiv,tagsdiv-post_tag,trackbacksdiv,authordiv
hidden:slugdiv
closedpostboxesnonce:8723ee108f
page:post

2) action:meta-box-order
_ajax_nonce:b6b48d2d16
page_columns:2
page:post
order[side]:submitdiv,formatdiv,categorydiv,tagsdiv-post_tag,postimagediv
order[normal]:postexcerpt,postcustom,trackbacksdiv,commentsdiv,authordiv
order[advanced]:

Ми могли б обійти цю проблему за допомогою іншого користувача Ajax виклику.

Ми, звичайно, можемо просто зачепитись на save_postгачок і змінити дані кожного разу, коли повідомлення зберігається. Але це не звичайний досвід користувальницького інтерфейсу, тому це тут не враховувати

Існує ще одне неелегантне рішення, доступне для PHP, описане тут нижче:

Рішення без JavaScript:

Питання в тому, де зберігати дані? Як метадані користувача , розміщуйте метадані чи, можливо, у спеціальній таблиці?

Тут ми зберігаємо його в якості даних позначки користувача і прийняти закриття з поштових скриньок позначки в якості прикладу.

Коли closedpostboxes_postмета-значення оновлюється, ми також зберігаємо його у closedpostboxes_post_{post_id}мета-значення.

Потім ми викрадаємо вилучення, closedpostboxes_postщоб замінити його відповідним мета-значенням на основі ідентифікатора користувача та ідентифікатора повідомлення.

a) Оновлення під час closed-postboxesдії ajax:

Ми можемо отримати ідентифікатор публікації, wp_get_referer()а потім скористатися зручною url_to_postid()функцією. Я вперше дізнався про цю "смішну" функцію, прочитавши відповідь від @s_ha_dum , кілька місяців тому ;-) На жаль, функція не розпізнає ?post=123GET змінних, але ми можемо зробити невелику хитрість, просто змінивши її, щоб p=123обійти її.

Ми можемо підключитися updated_user_meta, це запускається відразу після closedpostboxes_postоновлення метаданих користувача для :

add_action( 'updated_user_meta',                           
    function ( $meta_id, $object_id, $meta_key, $_meta_value )
    {
        $post_id = url_to_postid( str_replace( 'post=', 'p=', wp_get_referer() ) );
        if( 'closedpostboxes_post' === $meta_key && $post_id > 0 )
            update_user_meta( 
                $object_id, 
                'closedpostboxes_post_' . $post_id, 
                $_meta_value 
            );
    }
, 10, 4 );

b) Отримання даних:

Ми можемо підключити get_user_option_closedpostboxes_postгачок, щоб змінити дані, отримані з closedpostboxes_postмета мета користувача:

add_filter( 'get_user_option_closedpostboxes_post',
    function ( $result, $option, $user )
    {
        $post_id = filter_input( INPUT_GET, 'post', FILTER_SANITIZE_NUMBER_INT );
        $newresult = get_user_option( 'closedpostboxes_post_'. $post_id , $user->ID );
        return ( $newresult ) ? $newresult : $result;
    }
, 10, 3 );

Ми також можемо подумати про випадок, коли немає публікації на основі публікації closedpostboxes_post_{post_id}. Таким чином, він буде використовувати останні збережені налаштування від closedpostboxes_post. Можливо, ви хочете, щоб у цьому випадку все було відкритим або закритим. Було б легко змінити таку поведінку.

Для інших типів користувацьких поштових ми можемо використовувати відповідний closedpostboxes_{post_type}гак.

Те саме повинно бути можливим для впорядкування та приховування метаполез із мета metaboxhidden_{post_type}та meta-box-order_{post_data}користувачем.

ps: вибачте за цю занадто довгу відповідь на вихідні, оскільки вони завжди повинні бути короткими & веселими ;-)


Великий +1. N / P для довгої відповіді, я не очікував би коротких. Якщо чесно, я не очікував жодного у вихідні :) Дві речі мені дуже сподобалися: 1-я ідея зберігати дані на основі користувача та за поштою: моя ідея полягала в тому, щоб зберігати в post meta, але таким чином все користувачі матимуть однаковий статус. 2-я ідея використовувати 'get_user_option_*_post'для того, щоб WP розпізнавав власні дані. Тільки думаю, що мені не дуже подобається, це використання wp_get_refererцього реально на $_SERVERварі, що не дуже надійно, але я думаю, що у мене є ідея подолати "головну проблему";)
gmazzap

Дякую, я думаю, це залежить від кількості користувачів та публікацій, де найкраще зберігати дані. Можливо, ці дані повинні мати деякий TTL і стиратися, наприклад, раз на місяць? Так, я погоджуюся з вами щодо wp_get_referer()методу, тому я назвав це неелегантним рішенням PHP ;-) Спочатку я подумав про збереження поточного ідентифікатора повідомлення для кожного користувача, але це не працює, якщо користувач редагує два чи більше публікації в браузері. З нетерпінням
чекайте почуття

Через 43 дні адвокат надіслав мені відповідь на це. Ще раз дякую за вашу відповідь.
gmazzap

6

Як вказував Birgire у своїй відповіді , WordPress використовує AJAX для оновлення статусу метабоксів, а дані, передані в запиті AJAX, не включають ідентифікатор пошти, і це ускладнює оновлення статусу вікон на основі опублікування.

Після того, як я виявив , що дія AJAX використовується WordPress є 'closed-postboxes', я шукав цей рядок в папці адміністраторському знайти розшарування щільної , як WordPress робить запит AJAX.

Я виявив, що це відбувається на postbox.jsлінії №118 .

Виглядає так:

save_state : function(page) {
  var closed = $('.postbox').filter('.closed').map(function() {
      return this.id;
    }).get().join(',');
  var hidden = $('.postbox').filter(':hidden').map(function() {
      return this.id;
    }).get().join(',');
  $.post(ajaxurl, {
    action: 'closed-postboxes',
    closed: closed,
    hidden: hidden,
    closedpostboxesnonce: jQuery('#closedpostboxesnonce').val(),
    page: page
  });
}

По суті, WordPress розглядає елементи DOM з класом "поштова скринька" та класом "закритим" і створює розділений комами список їх ідентифікаторів. Те ж саме робиться для прихованих елементів DOM з класом "поштова скринька".

Отже, моя думка була такою: я можу створити підроблений метабокс з правильними класами і прихований, встановивши його ідентифікатор, щоб містити ідентифікатор пошти, і таким чином я можу отримати його в запиті AJAX.

Це те, що я зробив:

add_action( 'dbx_post_sidebar', function() {
    global $post;
    if ( $post->post_type === 'mycpt' ) {
        $id = $post->ID;
        $f = '<span id="fakebox_pid_%d" class="postbox closed" style="display:none;"></span>';
        printf( $f, $id );
    }
});

Таким чином я створив метабокс, який завжди закритий і завжди прихований, тому WordPress надсилатиме свій ідентифікатор як $_POSTvar у запиті AJAX, і коли підроблений ідентифікатор поля містить ідентифікатор повідомлення передбачуваним способом, я можу розпізнати публікацію.

Після цього я подивився, як WordPress виконує завдання AJAX.

У admin-ajax.phpрядку 72 WordPress зачіпляє 'wp_ajax_closed-postboxes'пріоритет 1.

Отже, щоб діяти перед WordPress, я міг би підключити ту саму дію з пріоритетом 0.

add_action( 'wp_ajax_closed-postboxes', function() {

    // check if we are in right post type: WordPress passes it in 'page' post var
    $page = filter_input( INPUT_POST, 'page', FILTER_SANITIZE_STRING );
    if ( $page !== 'mycpt' ) return;

    // get post data
    $data = filter_input_array( INPUT_POST, array(
        'closed' => array( 'filter' => FILTER_SANITIZE_STRING ),
        'hidden' => array( 'filter' => FILTER_SANITIZE_STRING )
    ) );

    // search among closed boxes for the "fake" one, and return if not found
    $look_for_fake = array_filter( explode( ',', $data[ 'closed' ] ), function( $id ) {
         return strpos( $id, 'fakebox_pid_' ) === 0;
    } );
    if ( empty( $look_for_fake ) ) return;

    $post_id = str_replace( 'fakebox_pid_', '', $look_for_fake[0] );
    $user_id = get_current_user_id();

    // remove fake id from values
    $closed = implode(',', array_diff( explode(',', $data['closed'] ), $look_for_fake ) );
    $hidden = implode(',', array_diff( explode(',', $data['hidden'] ), $look_for_fake ) );

    // save metabox status on a per-post and per-user basis in a post meta
    update_post_meta( $post_id, "_mycpt_closed_boxes_{user_id}", $closed );
    update_post_meta( $post_id, "_mycpt_hidden_boxes_{user_id}", $hidden );

}, 0 );

Збереження даних у мета-мета дало змогу фільтрувати get_user_option_closedpostboxes_mycptта get_user_option_metaboxhidden_mycpt(обидві варіанти get_user_option_{$option}фільтра) змусити параметри завантаження WordPress з постмета:

add_filter( 'get_user_option_closedpostboxes_mycpt', function ( $result, $key, $user ) {
    global $post;
    $meta = get_post_meta( $post->ID, "_mycpt_closed_boxes_{$user->ID}", TRUE );
    if ( ! empty( $meta ) ) {
        $result = $meta;
    }
    return $result;
}, 10, 3 );

і

add_filter( 'get_user_option_metaboxhidden_mycpt', function ( $result, $key, $user ) {
    global $post;
    $meta = get_post_meta( $post->ID, "_mycpt_hidden_boxes_{$user->ID}", TRUE );
    if ( ! empty( $meta ) ) {
        $result = $meta;
    }
    return $result;
}, 10, 3 );

Яка чудова ідея, використовуючи прихований метабокс із відповідною інформацією +1
birgire

дякую @birgire і ще раз дякую за вашу А, ідея збереження даних як за користувачем, так і за поштою - все ваше :)
gmazzap
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.