Multiselect-Felder in WordPress richtig leeren
Veröffentlicht: – Kommentar hinterlassen Letzte Aktualisierung:
Die Arbeit mit Einstellungen in WordPress ist mit Hilfe der Settings API in der Regel ziemlich unkompliziert. Doch es gibt ein Problem bei der Verwendung von Multiselect-Feldern. Da die Auswahl eines Multiselect-Felds komplett leer sein, macht es das Löschen des letzten Wertes standardmäßig unmöglich.
Aber warum ist das so? Wenn du mindestens einen Wert eines Multiselect-Feldes auswählst (ein <select> mit einem multiple-Attribut), wird dieser Wert (oder die Liste der Werte) Teil von $_POST beim Absenden der Einstellung und deshalb in der Datenbank über die Settings API aktualisiert.
Wenn du jedoch die Auswahl aller Werte des Multiselect-Feldes entfernst und es dann absendest, gibt es keinen Eintrag in $_POST (da leere Felder ignoriert werden) und das Feld wird von WordPress ignoriert, da WordPress nicht weiß, dass dieses Feld verändert werden soll.
Leider gibt es keinen direkten Filter, um WordPress zu sagen, welche Felder auf geänderte Werte geprüft werden sollen, weshalb wir hier einen kleinen Trick benötigen. Der einzige Filter, der zu dieser Zeit läuft, ist allowed_options, der überprüft, ob die aktuellen $_POST-Felder aktualisiert werden dürfen. Durch die Zweckentfremdung des Filters kann ich die Option löschen, wenn sie via register_setting registriert wurde, aber kein Teil der $_POST-Felder ist:
/**
* Delete all empty settings.
*
* @param array $allowed_options List of allowed options
* @return array List of allowed options
*/
static function delete_empty_settings( array $allowed_options ): array {
global $wp_settings_fields;
// phpcs:disable WordPress.Security.NonceVerification.Missing
if (
! isset( $_POST['option_page'] )
|| ! isset( $_POST['action'] )
|| \sanitize_text_field( \wp_unslash( $_POST['option_page'] ) ) !== 'product_settings'
|| \sanitize_text_field( \wp_unslash( $_POST['action'] ) ) !== 'update'
) {
return $allowed_options;
}
foreach ( $wp_settings_fields['product_settings'] as $settings_fields ) {
foreach ( \array_keys( $settings_fields ) as $field_name ) {
if ( ! isset( $_POST[ $field_name ] ) ) {
\delete_option( $field_name );
}
}
}
// phpcs:enable WordPress.Security.NonceVerification.Missing
return $allowed_options;
}
Code-Sprache: PHP (php)
In Zeile 14 prüfe ich, ob meine individuelle Optionsseite die ist, von der die Anfrage kommt. Dies muss auf Basis deiner verwendeten Einstellungsseite angepasst werden. Dasselbe gilt für den Schlüssel in der globalen $wp_settings_fields in Zeile 20 verwendet wird.
Der Code iteriert dann über alle Einstellungen und prüft, ob sie Teil der $_POST-Felder sind. Wenn nicht, werden sie gelöscht.
Der Wert von $allowed_options bleibt immer, wie er ist. Ihr Filter wird nur verwendet, um die Anfrage beim Abspeichern von Optionen zu verwenden, um den Code auszuführen.
Übrigens: die ignorierte Nonce-Prüfung ist Absicht. Der Filter läuft nur nach einer erfolgreichen Nonce-Prüfung in /wp-admin/options.php und mehrere Nonce-Überprüfungen werden von WordPress nicht unterstützt.