Sub-Tab Pattern
Wiederverwendbares Pattern fuer WordPress Settings mit Sub-Tabs
Pattern
Sub-Tabs
Entwicklung
WordPress
Settings
Sub-Tab Pattern
Wiederverwendbares Pattern fuer WordPress Settings-Seiten mit Sub-Tabs.
Problem
Bei Settings-Seiten mit Sub-Tabs werden beim Speichern alle Formularfelder gesendet. Felder aus anderen Sub-Tabs (die nicht im DOM sind) werden dadurch:
- Text-Felder: Nicht ueberschrieben (weil
isset()geprueft wird) - Checkboxen: Auf 0 zurueckgesetzt! (weil
isset()false ist)
// PROBLEM: Checkbox aus anderem Sub-Tab wird auf 0 gesetzt!
update_option('option_name', isset($_POST['option_name']) ? 1 : 0);
Loesung: Hidden-Field + Sub-Tab-aware save_settings()
1. Hidden-Field in jedem Sub-Tab
Jeder Sub-Tab rendert ein Hidden-Field mit seinem Namen:
public static function render_subtab( string $subtab ): void {
?>
<input type="hidden"
name="my_plugin_active_subtab"
value="<?php echo esc_attr( $subtab ); ?>">
<!-- ... Sub-Tab Inhalte ... -->
<?php
}
2. Felder pro Sub-Tab definieren
Eine Methode die alle Felder pro Sub-Tab zurueckgibt:
public static function get_fields_by_subtab(): array {
return array(
'verbindung' => array(
'option_api_token' => 'sanitize_text_field',
'option_api_key' => 'sanitize_text_field',
),
'einstellungen' => array(
'option_auto_sync' => 'boolval', // Checkbox!
'option_auto_send' => 'boolval', // Checkbox!
'option_timeout' => 'absint',
),
'kontakte' => array(
// Kann leer sein wenn Sub-Tab nur Anzeige hat
),
);
}
3. save_settings() anpassen
Nur die Felder des aktiven Sub-Tabs speichern:
case 'mein_tab':
// Aktiven Sub-Tab ermitteln
$active_subtab = isset( $_POST['my_plugin_active_subtab'] )
? sanitize_key( $_POST['my_plugin_active_subtab'] )
: 'verbindung'; // Default
// Felder-Definition holen
$fields_by_subtab = My_Plugin_Settings::get_fields_by_subtab();
if ( isset( $fields_by_subtab[ $active_subtab ] ) ) {
$fields = $fields_by_subtab[ $active_subtab ];
foreach ( $fields as $option_name => $sanitize_callback ) {
if ( isset( $_POST[ $option_name ] ) ) {
$value = wp_unslash( $_POST[ $option_name ] );
// Sanitize basierend auf Callback
if ( 'boolval' === $sanitize_callback ) {
$value = 1; // Checkbox ist gesetzt
} elseif ( is_callable( $sanitize_callback ) ) {
$value = call_user_func( $sanitize_callback, $value );
}
update_option( $option_name, $value );
} elseif ( 'boolval' === $sanitize_callback ) {
// Checkbox nicht gesetzt = 0 (NUR fuer aktiven Sub-Tab!)
update_option( $option_name, 0 );
}
}
}
break;
Beispiel: sevDesk Settings
Implementiert in Session 24.12.2025:
Dateien
| Datei | Zweck |
|---|---|
class-sevdesk-settings.php |
get_fields_by_subtab(), Hidden-Field |
class-settings.php |
Sub-Tab-aware save_settings() |
Sub-Tabs
| Sub-Tab | Felder |
|---|---|
| verbindung | api_token, api_version, user_id, contact_category |
| rechnungen | auto_invoice (bool), auto_send (bool), e_invoice (bool), ... |
| kontakte | (keine - nur Anzeige) |
| dienstleistungen | use_parts (bool), auto_sync_parts (bool), part_category |
| synchronisation | (keine - nur Sync-Button) |
Checkliste fuer neue Sub-Tab-Implementierungen
| Schritt | Beschreibung |
|---|---|
| 1 | Sub-Tab-Konstante definieren (SUB_TABS array) |
| 2 | Navigation rendern mit aktuellem Sub-Tab markiert |
| 3 | Hidden-Field in jedem Sub-Tab rendern |
| 4 | get_fields_by_subtab() Methode erstellen |
| 5 | save_settings() case mit Sub-Tab-Logik anpassen |
| 6 | Checkboxen mit 'boolval' markieren |
Vorteile
| Vorteil | Beschreibung |
|---|---|
| Kein Auto-Save | Normaler Speichern-Button funktioniert |
| Kein AJAX | Keine zusaetzlichen Endpunkte noetig |
| Keine CSS-Hacks | Keine versteckten Speichern-Buttons |
| Robust | Funktioniert mit beliebig vielen Sub-Tabs |
| Erweiterbar | Neue Sub-Tabs einfach hinzufuegbar |
Anti-Patterns (NICHT machen)
| Anti-Pattern | Problem |
|---|---|
| Auto-Save per AJAX | Komplex, fehleranfaellig, konfligiert mit Haupt-Speichern |
| Speichern-Button ausblenden | UX-Problem, Benutzer erwartet Button |
| Alle Felder als hidden | DOM wird aufgeblaet, Error-prone |
| Checkboxen ohne isset() | Standard-WordPress-Problem |
Referenz
- Implementierung: Session 24.12.2025
- sevDesk Settings:
includes/class-sevdesk-settings.php - Main Settings:
includes/class-settings.php(case 'sevdesk')