Jaki jest prawidłowy czas korzystania z current_user_can () i powiązanych funkcji?

10

Podczas ładowania rdzenia waniliowego WP konfigurowany jest bieżący użytkownik, $wp-init()który jest po załadowaniu motywu i przed initzaczepieniem. Jest to zgodne z dobrą praktyką polegającą na podłączaniu funkcjonalności initlub później.

Jednak powszechną praktyką jest również wywoływanie funkcji powiązanych, na przykład current_user_can() wcześniej . Jest to z definicji wymagane dla wtyczek, które działają na wcześniejszych etapach procesu ładowania (moja wtyczka Toolbar Theme Switcher byłaby przykładem).

Dokumentacja nie wysuwa żadnych roszczeń za lub przeciw tej praktyce (którą mogłem znaleźć).

Jednak niektóre wtyczki wydają się łączyć z funkcjami związanymi z użytkownikiem i przez initcały czas oczekują stanu po.

Na przykład bbPress rzuca następujące powiadomienie:

// 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' );
}

Aby szybko zademonstrować, wrzuć to do podstawowej definicji current_user_can():

function current_user_can( $capability ) {

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

Kto ma rację w tej sytuacji? Czy istnieje kanoniczne określenie wcześniejszego dozwolonego / zabronionego użycia funkcji związanych z użytkownikiem init?

Rarst
źródło

Odpowiedzi:

7

Jedynym warunkiem current_user_can()jest istnienie wp_get_current_user(). Ten ostatni jest zdefiniowany w pluggable.php, więc możesz go użyć później plugins_loaded.

_doing_it_wrong()Wezwanie jesteś powołując się na swoje pytanie jest niewłaściwe dla siebie. Domyślam się, że wziąłeś to z BuddyPress lub bbPress. Obaj wpadają w rekurencję, jeśli nie czekają tak długo. Istnieją inne, lepsze sposoby zapobiegania rekursji.

W niektórych przypadkach, takich jak zmiana ustawień regionalnych , musisz wcześniej uzyskać dostęp do bieżącego obiektu użytkownika, więc oczekiwanie na after_setup_themenie jest nawet opcją.

fuxia
źródło
2

Jeśli wcześniej sprawdzisz możliwości użytkownika, initoznacza to, że istnieje prawdopodobieństwo, że jesteś odpowiedzialny za ustawienie bieżącego obiektu użytkownika.

Jeśli uzyskasz dostęp do użytkownika później init , masz pewność, że coś innego już go skonfigurowało, w większości przypadków sam rdzeń.

Dlatego dostęp do użytkownika po initjest uważany za bezpieczny .

W rzeczywistości wczesny dostęp może zepsuć działający filtr determine_current_user.

Warto powiedzieć, że jeden jest „kruchym” hakiem, ponieważ są szanse, że nigdy się nie uruchomi, ponieważ jest wystrzeliwany tylko w funkcjach wtykowych.

Są jednak przypadki (jak powiedział @toscho ), w których nie możesz czekać do init, w tych przypadkach nie masz wyboru.

Jedynym sposobem rozwiązania każdej niezgodności jest przypadek, jeśli masz taką wolę.

Rozwiązaniem, które może działać w większości przypadków (w tym bbPress / BuddyPress) jest użycie następującej funkcji zamiast 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 );
}

Pozwala to wcześnie sprawdzić bieżące możliwości użytkownika bez ustawiania globalnego użytkownika, więc teoretycznie można go uruchomić wcześniej init.

Problem polega na tym, że, jak wspomniano powyżej, każdy kod, który przesłania funkcje wtykowe i nie uruchamia się, determine_current_userpsuje go.

gmazzap
źródło
Wydaje mi się, że twoja funkcja ma zmienione wartości. :)
Rarst,
Tak ... pisałem zbyt szybko przed obiadem: P dziękuję @ialocin za naprawę.
gmazzap
Nie wspominaj o tym. Poza tym nie mów tylko, co jest nie tak, napraw to @Rarst :)
Nicolai,
1

Skłaniam się do myślenia, że ​​BuddyPress i bbPress powinni sprawdzić coś jeszcze przed _doing_it_wrongwysłaniem wiadomości

Zmieniłem obie procedury, aby sprawdzić również rzeczywiste ustawienie $ current_user.

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

Powiadomienia nie były już wyświetlane.

Testowanie did_action( "after_setup_theme" )staje się szelkami pasującymi do pasa.

bobbingwide
źródło