wp_query kontrollierte keine Userberechtigungen
Sogar ohne jede Berechtigung können User (veröffentlichte) Posts sehen.
Das mag einerseits logisch, andererseits nicht intuitiv klingen.
WordPress bietet bei Beiträgen/Seiten/CPT-Post nur eine Handvoll „Sichtbarkeits“-Einstellungen.
Dazu gehören Dinge wie einen Post auf privat oder veröffentlicht zu stellen.
Eine Feinabstimmung auf Userrollen oder Berechtigungen gibt es nicht. Also nicht direkt im WordPress-Core. Das muss man auf Pluginebene lösen.
Leider.
Das mal als kurzes tl;dr.
Aber warum ist dem so? Schauen wir uns den Code an:
Grundsätzliches zu WP_Query::get_posts()
Nachfolgend eine kleine Erklärung zu dieser Funktion und zur Verwechslungsgefahr.
\WP_Query::get_posts() ist zuständig, um all die übergebenen Parametern im wp_query-Aufruf abzuarbeiten.
Damit wird dann eine SQL-Query erstellt, welche für die Datenbank-Abfrage verwendet wird.
Rückgabewert sind dann die gewünschten Posts.
Exkurs¹: Die Funktion WP_Query::get_posts ist übrigens ein gutes Beispiel für schlechten Code, denn die Funktion umfasst mehr als 1.500 Zeilen Code – ohne Blöcke thematisch in andere Funktionen auszulagern.)
Exkurs²: Die Funktion WP_Query::get_posts ist nicht zu verwechseln mit get_posts(). Erstere liegt in wp-includes/class-wp-query.php, zweitere findet sich unter wp-includes/post.php .
User ohne jede Berechtigung können alle veröffentlichten Posts sehen
Das mag logisch klingen, dass ein User ohne jede Berechtigung gleich viel sehen kann, wie ein nicht eingeloggter User.
Nehme ich einem User also die Berechtigung weg, einen Post zu sehen, spielt das keine Rolle – was nicht ganz logisch erscheint.
Zur Veranschaulichung, hier die Übersicht vom User Role Editor Plugin – das zeigt eine User-Rolle ohne jegliche Berechtigung:
Obwohl dieser User keinerlei Berechtigung für den CPT „Heizungsmaterial“ hat, kann jeder Post von Heizungsmaterial angeschaut werden!
Warum???
WP_Query::get_posts() überprüft nicht direkt auf Rollen
Es gibt keine direkte Überprüfung auf die unterschiedlichen Rollen in dieser Funktion.
Die Funktion current_user_can gibt es in der Funktion WP_Query::get_posts() genau SIEBEN! mal.
Überprüft wird auf edit_others_posts , auf read_private_posts , auf edit_post und auf read_post.
edit_others_posts
Wird nur überprüft, wenn der wp_query Parameter ‚perm‘ angegeben wurde!
if ( ! empty( $q['perm'] ) && 'editable' === $q['perm'] && ! current_user_can( $edit_others_cap ) ) {
Das ist bei einer Query vom WP-Core nicht der Fall, weder auf einer normalen Seite, noch im Archiv!
read_private_posts
Wird ebenfalls nur überprüft, wenn der Parameter „perm“ angegeben wurde:
if ( ! empty( $q['perm'] ) && 'readable' === $q['perm'] && ! current_user_can( $read_private_cap ) ) {
edit_post
Darauf wird überprüft, wenn eine Vorschau angezeigt wird.
if ( $post_status_obj->protected ) { // User must have edit permissions on the draft to preview. if ( ! current_user_can( $edit_cap, $this->posts[0]->ID ) ) {
und
if ( $this->is_preview && $this->posts && current_user_can( $edit_cap, $this->posts[0]->ID ) ) {
Oder wenn ein Post Status verwendet wurde, den WordPress nicht erkennt.
// Post status is not registered, assume it's not public. if ( ! current_user_can( $edit_cap, $this->posts[0]->ID ) ) {
read_post
Auf diese Fähigkeit/Capability wird überprüft, wenn der Post-Status „privat“ ist:
} elseif ( $post_status_obj->private ) {
if ( ! current_user_can( $read_cap, $this->posts[0]->ID ) ) {
Lösung: Wie auf Capability bei wp_query überprüfen?
Wird der Permission Parameter von wp_query angegeben, so kann ich auf die Capability überprüfen.
Wichtig ist also, dass bei einem wp_query Aufruf der Parameter „perm“ angegeben wird, der Codex zeigt das auch als Beispiel:
Es gibt hier zwei Möglichkeiten für diesen Parameter:
- editable
- readable
Den „readable“ Parameter gebe ich hier an, weil ich auch „private“ Posts holen möchte, die dann einer User-Rolle angezeigt wird, die die Berechtigung bekommen hat.
Lösung tl;dr
Will ich jetzt Posts holen, die auf öffentlich geschalten sind aber nur den Rollen anzeigen, die die nötige Berechtigung haben?
Dann muss ich in der wp_query ‚perm‚ auf ‚editable‚ setzen.
Die User-Rolle muss folgende Capability-Einstellung besitzen:
'edit_others_posts' => true,
Somit werden veröffentlichte Posts nur jenen Usern angezeigt, welche auch die nötige Berechtigung besitzen.
Was auch heißt, dass ich die Capability „edit_others_posts“ setzen muss!
Bonus: Wie mache ich das zb bei Archiv-Seiten? pre_get_posts()!
Bei zb Archivseiten erzeuge ich selbst keinen wp_query Aufruf. Der „perm“ Parameter ist auch nicht gesetzt! Das muss ich selbst erledigen.
Damit diese Überprüfungen auch bei Archivseiten o.ä. funktionieren, muss ich in die Standard-WP-Query eingreifen!
Das funktioniert eh einfach über den Hook pre_get_posts().
Links
- https://wp-entwickler.at/?s=wp_query
- https://developer.wordpress.org/reference/functions/current_user_can/
- https://developer.wordpress.org/reference/classes/wp_query/get_posts/
- https://developer.wordpress.org/reference/functions/get_posts/
- https://developer.wordpress.org/reference/classes/wp_query/#permission-parameters
- https://developer.wordpress.org/reference/hooks/pre_get_posts/
- https://wp-entwickler.at/?s=pre%20get%20posts