Lighthouse meckert über nicht-beschreibende Link-Texte in der Navigation. „WordPress“, „Service“, „Blog“ – klar, was gemeint ist, aber ein Screenreader weiß ohne Kontext nicht wohin der Link führt. Die Lösung: ein eigenes Feld im Menü-Editor, das ein aria-label pro Menü-Item aufnimmt.
Das Ziel
Im WordPress-Menü-Editor soll ein neues Textfeld erscheinen: „Aria-Label“. Wenn es befüllt ist, gibt der Walker das aria-label-Attribut am Link aus. Wenn es leer bleibt, passiert nichts – der Link verhält sich wie gehabt.
Schritt 1: Custom Field im Menü-Editor registrieren
WordPress stellt dafür den Action-Hook wp_nav_menu_item_custom_fields bereit. Der wird für jedes Menü-Item aufgerufen und gibt die Item-ID mit. Alles landet direkt in der functions.php des Themes:
function prefix_menu_item_aria_label_field( $item_id, $item ) {
$value = get_post_meta( $item_id, '_prefix_menu_aria_label', true );
?>
<p class="field-aria-label description description-wide">
<label for="edit-menu-item-aria-label-<?php echo $item_id; ?>">
Aria-Label
<input
type="text"
id="edit-menu-item-aria-label-<?php echo $item_id; ?>"
class="widefat edit-menu-item-aria-label"
name="menu-item-aria-label[<?php echo $item_id; ?>]"
value="<?php echo esc_attr( $value ); ?>"
/>
</label>
</p>
<?php
}
add_action( 'wp_nav_menu_item_custom_fields', 'prefix_menu_item_aria_label_field', 10, 2 );
Das Feld wird als Post-Meta unter dem Schlüssel _prefix_menu_aria_label gespeichert. Der Unterstrich am Anfang verhindert, dass es in der normalen Custom-Fields-Ansicht auftaucht.
Schritt 2: Custom Field speichern
Beim Speichern des Menüs feuert wp_update_nav_menu_item. Hier lese ich den POST-Wert aus und speichere ihn – oder lösche das Meta wenn das Feld geleert wurde:
function prefix_menu_item_aria_label_save( $menu_id, $menu_item_db_id ) {
if ( ! isset( $_POST['menu-item-aria-label'][ $menu_item_db_id ] ) ) {
return;
}
$value = sanitize_text_field( $_POST['menu-item-aria-label'][ $menu_item_db_id ] );
if ( ! empty( $value ) ) {
update_post_meta( $menu_item_db_id, '_prefix_menu_aria_label', $value );
} else {
delete_post_meta( $menu_item_db_id, '_prefix_menu_aria_label' );
}
}
add_action( 'wp_update_nav_menu_item', 'prefix_menu_item_aria_label_save', 10, 2 );
Schritt 3: Custom Walker
Der Standard-Walker von WordPress kennt das Feld nicht – ich brauche einen eigenen. Die Klasse erweitert Walker_Nav_Menu und überschreibt nur start_el():
class Prefix_Nav_Walker extends Walker_Nav_Menu {
public function start_el( &$output, $item, $depth = 0, $args = null, $id = 0 ) {
$aria_label = get_post_meta( $item->ID, '_prefix_menu_aria_label', true );
$aria_attr = '';
if ( ! empty( $aria_label ) ) {
$aria_attr = ' aria-label="' . esc_attr( $aria_label ) . '"';
}
$atts = array(
'href' => ! empty( $item->url ) ? $item->url : '#',
'target' => ! empty( $item->target ) ? $item->target : '',
'rel' => ! empty( $item->xfn ) ? $item->xfn : '',
'class' => 'nav-link',
);
$attributes = '';
foreach ( $atts as $attr => $value ) {
if ( ! empty( $value ) ) {
$attributes .= ' ' . $attr . '="' . esc_attr( $value ) . '"';
}
}
$link_before = isset( $args->link_before ) ? $args->link_before : '';
$link_after = isset( $args->link_after ) ? $args->link_after : '';
$title = apply_filters( 'the_title', $item->title, $item->ID );
$output .= '<li' . $this->build_css_class( $item, $depth ) . '>';
$output .= '<a' . $attributes . $aria_attr . '>';
$output .= $link_before . esc_html( $title ) . $link_after;
$output .= '</a>';
}
private function build_css_class( $item, $depth ) {
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$classes[] = 'menu-item-' . $item->ID;
$class_names = implode( ' ', array_filter( $classes ) );
return $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
}
}
Schritt 4: Walker einbinden
Alle drei Teile – Field-Registrierung, Save-Hook und Walker-Klasse – kommen direkt in die functions.php des Themes. Keine extra Datei, kein Plugin. Danach in den wp_nav_menu()-Args den neuen Walker übergeben:
'walker' => new Prefix_Nav_Walker(),
Das war es. Im Menü-Editor erscheint jetzt unter jedem Item das Feld „Aria-Label“. Befüllt – wird es ausgegeben. Leer – kein Attribut, kein Overhead.
Fazit
Ein Custom Nav Walker klingt nach Aufwand, ist aber überschaubar. Die Alternative – Link-Texte in der Navigation umbenennen – ist meistens keine Option wenn das visuelle Design kurze Labels fordert. Drei Funktionen in der functions.php, einmal den Walker eintragen – fertig.