Каково правильное время использования current_user_can () и связанных функций?

10

Во время загрузки ядра vanilla WP текущий пользователь настраивается $wp-init()после загрузки темы и до initподключения. Это соответствует хорошей практике подключения к функциональности initили позже.

Однако также является обычной практикой вызывать связанные функции, например, current_user_can() раньше . Это по определению требуется для плагинов, которые работают с более ранними этапами процесса загрузки (мой плагин панели инструментов Theme Switcher будет примером).

Документация не претендует на или против этой практики (что я мог найти).

Однако некоторые плагины, кажется, подключаются к пользовательской функциональности и ожидают initсостояние post- всегда.

Например, bbPress выдает следующее уведомление:

// If the current user is being setup before the "init" action has fired,
// strange (and difficult to debug) role/capability issues will occur.
if ( ! did_action( 'after_setup_theme' ) ) {
    _doing_it_wrong( __FUNCTION__, __( 'The current user is being initialized without using $wp->init().', 'bbpress' ), '2.3' );
}

Для быстрой демонстрации добавьте это в определение ядра current_user_can():

function current_user_can( $capability ) {

    if ( ! did_action('after_setup_theme') ) {
        echo wp_debug_backtrace_summary();
    }

Кто «прав» в этой ситуации? Существует ли каноническое определение о разрешенном / запрещенном использовании пользовательских функций ранее init?

Rarst
источник

Ответы:

7

Единственным условием current_user_can()является существующее wp_get_current_user(). Последний определен в pluggable.php, так что вы можете использовать его после plugins_loaded.

_doing_it_wrong()Звонок вы со ссылкой на ваш вопрос не так для себя. Я думаю, что вы взяли это из BuddyPress или bbPress. Оба впадают в рекурсию, если не будут ждать так долго. Есть и другие, более эффективные способы предотвращения рекурсии.

В некоторых случаях, например при изменении языкового стандарта , вам необходимо получить доступ к текущему объекту пользователя раньше, поэтому ожидание after_setup_themeдаже не вариант.

Фуксия
источник
2

Если вы проверили возможности пользователя раньше, initзначит, есть вероятность, что вы несете ответственность за настройку текущего объекта пользователя.

Если вы обращаетесь к пользователю после init , то вы уверены, что что- то еще уже настроило пользователя, в большинстве случаев само ядро.

Вот почему доступ к пользователю после initсчитается безопасным .

Фактически, ранний доступ может нарушить работу некоторых фильтров determine_current_user.

Стоит сказать, что это «хрупкий» хук, потому что есть вероятность, что он никогда не запустится, будучи запущенным только в подключаемых функциях.

Однако в некоторых случаях (как сказал @toscho ) вы не можете дождаться инициализации, в этих случаях у вас нет выбора.

Единственный способ решить любую несовместимость - это в каждом конкретном случае, если у вас есть.

Решение, которое может работать в большинстве случаев (включая bbPress / BuddyPress), заключается в использовании следующей функции вместо current_user_can:

function compat_current_user_can( $capability )
{
  if ( did_action( 'init' ) ) {
     return current_user_can( $capability );
  }

  $user_id = apply_filters( 'determine_current_user', false );

  return user_can( $user_id, $capability );
}

Это позволяет проверить текущие возможности пользователя без предварительной настройки глобального пользователя, поэтому теоретически безопасно запускать его раньше init.

Проблема в том, что, как сказано выше, любой код, который переопределяет подключаемые функции, а не запускает determine_current_userего, нарушает его.

Gmazzap
источник
Я думаю, что в вашей функции есть переменные. :)
Rarst
Да ... набрал слишком быстро перед ужином: P спасибо @ialocin за исправление.
gmazzap
Не упоминай это. Кроме того, не говорите, что не так, исправьте это @Rarst :)
Николай
1

Я склонен думать, что BuddyPress и bbPress должны проверять что-то еще перед отправкой _doing_it_wrongсообщения

Я изменил обе процедуры, чтобы также проверить фактическую настройку $ current_user.

global $current_user; 
if ( is_null( $current_user ) ) {
    _doing_it_wrong( ... );
}

Уведомления больше не отображались.

Испытание did_action( "after_setup_theme" )становится скобками, чтобы идти с поясом.

bobbingwide
источник