Как добавить "Закрепить запись на главной" в интерфейсе сайта?

18 июл. 2012 г., 02:49:26
Просмотры: 1.87K
Голосов: 6

У меня есть сайт про бейсбол с несколькими авторами. Я использую функцию "Закрепить запись на главной" для обозначения "Выбора редактора" в статьях. Я хотел бы добавить ссылку/кнопку, позволяющую редакторам делать это прямо из интерфейса сайта. Метод может быть реализован либо в самой статье, либо в админ-баре. У меня нет особых предпочтений.

Я просмотрел множество плагинов для админ-бара, но не смог найти ничего связанного с функцией "Закрепить запись на главной".

Спасибо

0
Все ответы на вопрос 3
7

Есть несколько полезных функций, которые пригодятся здесь:

  • unstick_post - Открепить запись
  • stick_post - Закрепить запись
  • is_sticky - Проверить, является ли запись закрепленной

Имея эти три функции, все, что нам нужно сделать, это объединить их с помощью панели администратора.

Для начала давайте обернем все в класс для удобства и гибкости. Этот класс будет содержать несколько констант, которые мы будем использовать позже: nonce, действие для открепления записи и действие для закрепления записи.

class WPSE_58818_Stick_Post
{
    /**
     * Ajax nonce.
     *
     * @since   1.0
     */
    const NONCE = 'wpse58818_nonce_';

    /**
     * Действие открепления через Ajax
     *
     * @since   1.0
     */
    const UNSTICK = 'wpse58818_unstick';

    /**
     * Действие закрепления через Ajax
     *
     * @since   1.0
     */
    const STICK = 'wpse58818_stick';
} // конец класса

Теперь добавим функцию init для добавления наших действий. Первое действие - это подключение к template_redirect.

<?php
class WPSE_58818_Stick_Post
{
    // пропущено

    /**
     * Добавляет действия и прочее.
     *
     * @since   1.0
     * @access  public
     * @uses    add_action
     */
    public static function init()
    {
        add_action(
            'template_redirect',
            array(__CLASS__, 'template_r')
        );
    }
}

ПРИМЕЧАНИЕ: далее я буду опускать часть с class. Полную версию можно посмотреть здесь.

В функции, подключенной к template_redirect, мы проверим, находимся ли мы на странице отдельной записи и может ли пользователь ее редактировать. Если да, то подключимся к admin_bar_menu и wp_footer.

/**
 * Подключено к `template_redirect`. Добавляет кнопку закрепления/открепления
 * в панели администратора, если мы находимся на странице отдельной записи
 * и текущий пользователь может редактировать запись
 * 
 * @since   1.0
 * @access  public
 * @uses    add_action
 */
public static function template_r()
{
    if(
        !is_single() ||
        !current_user_can('edit_post', get_queried_object_id())
    ) return; // не отдельная запись или пользователь не может ее редактировать

    // Подключаемся к admin_bar_menu для добавления элементов
    add_action(
        'admin_bar_menu',
        array(__CLASS__, 'menu'),
        100
    );

    // Подключаемся к подвалу и выводим JavaScript
    add_action(
        'wp_footer',
        array(__CLASS__, 'footer')
    );
}

В функции menu, подключенной к admin_bar_menu, мы можем добавить наш новый элемент:

/**
 * Подключено к `admin_bar_menu`. Добавляет наш узел закрепления/открепления.
 *
 * @since   1.0
 * @access  public
 */
public static function menu($mb)
{
    // получаем ID текущей записи
    $post_id = get_queried_object_id();

    $mb->add_node(array(
        'id'    => 'wpse58818-sticker',
        'meta'  => array(
            'class' => 'wpse58818-sticker',
            'title' => is_sticky($post_id) ? 'unstick' : 'stick'
        ),
        'title' => is_sticky($post_id) ? __('Открепить') : __('Закрепить'),
        'href'  => self::get_url($post_id)
    ));
}

Здесь у нас появляется первая "вспомогательная функция", которая строит URL для узла панели администратора. Это просто обертка вокруг add_query_arg для добавления nonce и создания URL, который мы будем использовать с AJAX позже:

/**
 * Получаем URL для Ajax запроса для указанной записи
 *
 * @since   1.0
 * @access  protected
 */
protected static function get_url($post_id)
{
    return add_query_arg(array(
        'post_id' => absint($post_id),
        'action'  => is_sticky($post_id) ? self::UNSTICK : self::STICK,
        'nonce'   => wp_create_nonce(self::NONCE . $post_id)
    ), admin_url('admin-ajax.php'));
}

Функция footer просто выводит JavaScript для выполнения AJAX запросов. Основная идея: при клике на нашу новую ссылку делаем GET запрос по указанному URL. Если запрос успешен, меняем href, текст и title ссылки (от)крепления.

/**
 * Подключено к `wp_footer`. Выводит немного JS для закрепления/открепления записи
 *
 * @since   1.0
 * @access  public
 */
public static function footer()
{
    ?>
    <script type="text/javascript">
    jQuery(document).ready(function($) {
        $('.wpse58818-sticker a').on('click', function(e) {
            e.preventDefault();
            var action = $(this).attr('title');
            var that = this;
            $.get(
                $(this).attr('href'),
                {},
                function(data) {
                    if('0' == data)
                    {
                        console.log(data);
                        alert('<?php echo esc_js(__('Произошла ошибка')); ?>');
                        return;
                    }

                    $(that).attr('href', data);
                    if('stick' == action) {
                        $(that).html('<?php echo esc_js(__('Открепить')); ?>');
                        $(that).attr('title', 'unstick');
                    } else {
                        $(that).html('<?php echo esc_js(__('Закрепить')); ?>');
                        $(that).attr('title', 'stick');
                    }
                }
            );
        });
    });
    </script>
    <?php
}

Теперь перейдем к AJAX обработчикам. Ajax в плагинах/темах стоит изучить подробнее.

Немного модифицируем нашу функцию init, добавив два новых действия:

/**
 * Добавляет действия и прочее.
 *
 * @since   1.0
 * @access  public
 * @uses    add_action
 */
public static function init()
{
    add_action(
        'template_redirect',
        array(__CLASS__, 'template_r')
    );

    // Ajax действия
    add_action(
        'wp_ajax_' . self::STICK,
        array(__CLASS__, 'stick')
    );

    add_action(
        'wp_ajax_' . self::UNSTICK,
        array(__CLASS__, 'unstick')
    );
}

И наши AJAX обработчики. Они вполне могли бы быть одной функцией. Я разделил их здесь, так как это упрощает возможное расширение/изменение в будущем. Обе этих функции проверяют валидность AJAX запроса, (от)крепляют запись соответствующим образом и выводят новый URL для будущих (от)креплений.

/**
 * Ajax обработчик для функции закрепления
 *
 * @since   1.0
 * @access  public
 */
public static function stick()
{
    $post_id = self::can_ajax();

    stick_post($post_id);

    echo self::get_url($post_id);
    die();
}

/**
 * Ajax обработчик для функции открепления
 *
 * @since   1.0
 * @access  public
 * @uses    unstick_post
 */
public static function unstick()
{
    $post_id = self::can_ajax();

    // nonces проверены, все готово к откреплению!
    unstick_post($post_id);

    echo self::get_url($post_id);
    die();
}

Здесь появляется наша вторая "вспомогательная функция". can_ajax проверяет наши nonces и права пользователя, возвращая ID записи для (от)крепления. Если какие-либо проверки не пройдены, функция завершает выполнение (через die('1')).

/**
 * Проверяет, может ли текущий пользователь выполнять Ajax запросы. Возвращает ID записи
 * для закрепления/открепления в случае успеха. В противном случае завершает выполнение.
 *
 * @since   1.0
 * @access  protected
 */
protected static function can_ajax()
{
    $post_id = isset($_REQUEST['post_id']) ? $_REQUEST['post_id'] : '';

    if(
        !$post_id ||
        !check_ajax_referer(self::NONCE . $post_id, 'nonce', false)
    ) die('0');

    if(!current_user_can('edit_post', $post_id))
        die('0');

    return $post_id;
}

Вот вся эта конструкция в виде плагина.

29 июл. 2012 г. 23:58:44
Комментарии

+1 за рабочий плагин, делает именно то, что просили в вопросе.

Amit Kosti Amit Kosti
30 июл. 2012 г. 00:11:52

Получаю эту ошибку при загрузке .php файла плагина через WordPress. The package could not be installed. PCLZIP_ERR_BAD_FORMAT (-10) : Unable to find End of Central Dir Record signature

Travis Pflanz Travis Pflanz
30 июл. 2012 г. 00:45:24

Тогда загрузи через FTP и отпиши? Скорее всего, потому что плагин не в своей папке или что-то в этом роде.

chrisguitarguy chrisguitarguy
30 июл. 2012 г. 00:50:50

Я добавил файл .php в папку, затем запаковал папку в .zip. Загрузил плагин через WordPress. Все загрузилось и установилось. Кнопка "Stick" отображается в админ-баре, но при нажатии появляется ошибка с текстом - "Произошла ошибка". Я использую Google Chrome, если это имеет значение.

Travis Pflanz Travis Pflanz
30 июл. 2012 г. 01:03:17

Это означает, что что-то пошло не так в ajax-запросе. Либо неверный nonce, ID поста или проблемы с правами. Без доступа к вашему сайту (что я не собираюсь делать) я не могу помочь — у меня на локальной машине всё работает. Шаг 1: работает ли это с темой по умолчанию? Могут ли другие плагины вызывать проблемы?

chrisguitarguy chrisguitarguy
30 июл. 2012 г. 01:13:51

На моей стороне закрепление и открепление работает нормально, но страница не обновляется (WP 3.4.1, плагины отключены, TwentyTen без изменений). Процесс зависает в Ajax-запросе, скриншот: http://cl.ly/IOo8 . . . . . +1+ Очень хорошая работа, профессионально сделано :)

brasofilo brasofilo
30 июл. 2012 г. 01:42:18

Только что переварил всю информацию и попытался модифицировать почти все функции, но не смог заставить обновление работать... Тем не менее, ещё раз спасибо, похоже, что то, что вы называете полным бардаком, часто называют поэзией, не так ли ¿!

brasofilo brasofilo
30 июл. 2012 г. 02:02:33
Показать остальные 2 комментариев
3

Я думаю, этот небольшой исходный код - ваше решение. В настоящее время он не имеет обратной связи на фронтенде для изменения Sticky Post, но вы можете улучшить эту строку, класс или что угодно в функции fb_stick_post.

Первая функция добавляет элемент в панель администратора и создает новый URL с параметром. Также при on click вызывается функция для чтения параметра URL, и если он истинный, то изменяется sticky статус этого ID записи.

add_action( 'admin_bar_menu', 'fb_add_admin_bar_sticky', 35 );
function fb_add_admin_bar_sticky() {
    global $wp_admin_bar;

    if ( ! is_super_admin() || ! is_admin_bar_showing() )
        return;

    $current_object = get_queried_object();
    if ( empty($current_object) )
        return;

    if ( ! empty( $current_object->post_type ) && 
        ( $post_type_object = get_post_type_object( $current_object->post_type ) ) && 
        current_user_can( $post_type_object->cap->edit_post, $current_object->ID ) 
    ) {
        $wp_admin_bar->add_menu( 
            array(
                'id' => 'sticky_post', 
                'title' => __('Sticky'), 
                'href' => get_permalink() . '?stick_post=true', 
                'meta' => array(
                    'title' => __( 'Click me' ),
                    'onclick' => fb_stick_post( get_the_ID() )
                )
            )
        );
    }
}

function fb_stick_post( $post_id ) {

    if ( isset($_GET['stick_post']) && 'true' == htmlspecialchars( $_GET['stick_post'] ) )
        stick_post( $post_id );
}

Обновление 30.07.2012

Теперь небольшой плагин с простым решением. Плагин добавляет элемент в панель администратора. Текст кнопки проверяет, является ли запись sticky, и дает возможность сделать её sticky или unsticky.

Пример в теме Twenty Eleven для записи, помеченной как sticky

Я изменил хук для добавления элемента в панель администратора на `template_redirect`, чтобы использовать перенаправление после обновления sticky статуса записи.

<?php
/**
 * Plugin Name: Stick/Unstick post via Admin bar
 * 
 */

if ( ! function_exists( 'fb_add_admin_bar_sticky' ) ) {

    add_action( 'template_redirect', 'fb_add_admin_bar_sticky' );
    function fb_add_admin_bar_sticky() {
        global $wp_admin_bar;

        if ( ! is_super_admin() || ! is_admin_bar_showing() )
            return;

        $current_object = get_queried_object();
        if ( empty($current_object) )
            return;

        if ( ! empty( $current_object->post_type ) && 
            ( $post_type_object = get_post_type_object( $current_object->post_type ) ) && 
            current_user_can( $post_type_object->cap->edit_post, $current_object->ID ) 
        ) {

            // проверяем, является ли запись sticky
            if ( is_sticky( get_the_ID() ) ) {
                $title = __('Unsticky');
                $link = '?unstick_post=true';
                $attr_title = __( 'Make this post unsticky' );
            } else {
                $title = __('Sticky');
                $link = '?stick_post=true';
                $attr_title = __( 'Make this post sticky' );
            }

            $wp_admin_bar->add_menu(
                array(
                    'id' => 'sticky_post', 
                    'title' => $title, 
                    'href' => get_permalink() . $link, 
                    'meta' => array(
                        'title' => $attr_title,
                        'onclick' => fb_stick_post( get_the_ID() )
                    )
                )
            );
        }
    }

    function fb_stick_post( $post_id ) {

        if ( isset($_GET['stick_post']) && 'true' == htmlspecialchars( $_GET['stick_post'] ) ) {
            stick_post( $post_id );
            wp_redirect( get_permalink( $post_id ) );
            exit();
        }

        if ( isset($_GET['unstick_post']) && 'true' == htmlspecialchars( $_GET['unstick_post'] ) ) {
            unstick_post( $post_id );
            wp_redirect( get_permalink( $post_id ) );
            exit();
        }
    }

}

или скачайте этот плагин Gist 3214922

29 июл. 2012 г. 23:20:40
Комментарии

Небольшой исходный код (и элегантный) работает из коробки, мне только не хватает функции Unstick, но опять же: этого и не просили!

brasofilo brasofilo
30 июл. 2012 г. 02:21:13

Да, я тоже так думаю; но этого не было в вопросе. Это также возможно через url-параметр и функцию unstick( $post_id ). Также мне не хватает визуальной обратной связи при изменении sticky-статуса.

bueltge bueltge
30 июл. 2012 г. 09:47:41

Добро пожаловать! Теперь также доступен плагин для скачивания на Gist 3214922

bueltge bueltge
31 июл. 2012 г. 11:27:06
2

Вот гораздо более простое решение, которое выполнит задачу с использованием хука фильтра the_content

add_filter('the_content','simplest_sticky_solution');
function simplest_sticky_solution($content){
    global $post;
    //ранний выход, если не требуется
    if (!is_single() || !current_user_can('edit_post',$post->ID)) 
        return $content;

    //проверяем, отправлена ли форма, и действуем соответствующим образом
    if (isset($_POST['sticky_action']) && isset($_POST['sticky_id']) && isset($_POST['sticky_nonce']) && wp_verify_nonce($_POST['sticky_nonce'], 'StickIt')){
        if (is_sticky($post->ID)){
            stick_post($post->ID);
        }else{
            unstick_post($post->ID);
        }
    }

    //создаем форму
    $label = (is_sticky())? "Открепить": "Закрепить";
    $form = '
    <form action="" method="POST">
        <input type="hidden" name="sticky_id" value="'.$post->id.'">
        <input type="hidden" name="sticky_action" value="stickit">
        <input type="hidden" name="sticky_nonce" value="'.wp_create_nonce('StickIt').'">
        <input type="button" name="submit" value="'.$label.'">
    </form>';
    return $form.'<br/>'.$content;
}
30 июл. 2012 г. 23:24:19
Комментарии

Я получаю эту ошибку Parse error: syntax error, unexpected T_RETURN in /home1/travisp2/public_html/crowncrazed/wp-content/themes/qawker/functions.php on line 7 которая указывает на return $content;

Travis Pflanz Travis Pflanz
30 июл. 2012 г. 23:59:24

Извините, опечатка, исправил

Bainternet Bainternet
31 июл. 2012 г. 01:14:04