Bilder per Rechtsklick aus dem Finder in die WordPress-Mediathek (Synology)

Seit ich meine Theme-Dateien direkt im Finder auf die Synology ziehe, war ein Ärgernis übrig: Bilder. Jedes Beitragsbild, jede Grafik musste weiterhin über den Browser in die WordPress-Mediathek – Mediathek öffnen, „Datei hinzufügen“, auswählen, warten, Alternativtext eintragen. Heute mache ich das mit einem Rechtsklick im Finder: Schnelle Aktionen → Zu WordPress hochladen. Der Mac fragt nach dem Alternativtext, und ein paar Sekunden später ist das Bild in der Mediathek.
Kurz gesagt: Eine Automator-Schnellaktion schickt das Bild per SSH auf die Synology. Dort trägt es WP-CLI – das Kommandozeilen-Werkzeug von WordPress – als der Benutzer, dem WordPress gehört, in die Mediathek ein. Dafür braucht es einmalig WP-CLI auf der Synology und eine eng begrenzte sudo-Regel.
Vorweg: Das ist deutlich technischer als der Finder-Tipp. Du arbeitest im Terminal und auf der Synology mit Administratorrechten. Wenn du das noch nie gemacht hast, nimm dir Zeit und lies den Beitrag einmal ganz, bevor du anfängst.
Warum nicht einfach in den Upload-Ordner kopieren?
Das war mein erster Gedanke: Den Ordner wp-content/uploads im Finder öffnen und das Bild hineinziehen. Das Bild liegt dann zwar auf der Synology – aber WordPress weiß nichts davon. Die Mediathek ist eine Liste in der Datenbank, nicht einfach der Inhalt des Ordners. Ein hineinkopiertes Bild taucht nicht in der Mediathek auf, kann nicht als Beitragsbild gewählt werden, bekommt keinen Alternativtext und keine verkleinerten Versionen.
Der zweite naheliegende Weg wäre die Schnittstelle von WordPress mit einem „Anwendungspasswort“. WordPress erlaubt diese Passwörter aber nur über HTTPS – zu Recht, sonst geht das Passwort im Klartext durchs Netz. Mein WordPress läuft nur im Heimnetz über HTTP, und diese Sicherung wollte ich nicht ausschalten. Also bin ich den Weg über SSH gegangen: Der ist ohnehin verschlüsselt.
Was du brauchst
- Einen Mac und eine Synology mit WordPress aus dem Paket-Zentrum (bei mir DSM 7).
- SSH-Anmeldung mit Schlüssel auf der Synology, also ohne Passworteingabe. Wenn du dich mit
ssh -i ~/.ssh/deinschluessel deinbenutzer@IP-deiner-Synologyanmelden kannst, passt es. - Einen DSM-Benutzer, der zur Gruppe administrators gehört.
- Etwa eine Stunde Zeit beim ersten Mal.
Schritt 1: Herausfinden, wem WordPress gehört
Melde dich per SSH auf der Synology an und schau nach, wem der WordPress-Ordner gehört und welche PHP-Versionen es gibt:
ls -ld /volume1/web_packages/wordpress/wp-content/uploads
ls /usr/local/bin/php*
Bei mir gehört der Ordner nicht dem üblichen Benutzer „http“, sondern einem eigenen Benutzer namens WordPress. Und genau das ist der Knackpunkt: Mein eigener Benutzer darf dort nur lesen, nicht schreiben. Neue Bilder müssen deshalb als „WordPress“ angelegt werden – sonst gehören sie dem falschen Benutzer, und WordPress kann sie später nicht bearbeiten oder löschen.
Merke dir den Besitzer (bei mir WordPress) und eine PHP-Version (bei mir /usr/local/bin/php82). Beides brauchst du gleich.
Schritt 2: WP-CLI auf der Synology installieren
WP-CLI ist eine einzelne Datei. Lade sie auf der Synology herunter und lege sie nach /usr/local/bin. Dafür brauchst du einmal sudo und dein DSM-Passwort:
curl -o /tmp/wp-cli.phar https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
sudo install -m 755 -o root -g root /tmp/wp-cli.phar /usr/local/bin/wp-cli.phar
rm /tmp/wp-cli.phar
Schritt 3: Die sudo-Regel
Damit die Schnellaktion später ohne Passwortabfrage als „WordPress“ arbeiten kann, bekommt dein Benutzer eine Regel: Er darf genau einen Befehl – PHP mit WP-CLI – als Benutzer „WordPress“ ausführen. Sonst nichts. Ersetze deinbenutzer, WordPress und php82 durch deine Werte aus Schritt 1:
sudo -i
grep includedir /etc/sudoers
echo 'deinbenutzer ALL=(WordPress) NOPASSWD: /usr/local/bin/php82 /usr/local/bin/wp-cli.phar *' > /etc/sudoers.d/wpcli
chmod 440 /etc/sudoers.d/wpcli
sudo -l -U deinbenutzer
exit
Die zweite Zeile prüft, ob die Synology den Ordner /etc/sudoers.d überhaupt einliest – dort muss includedir /etc/sudoers.d erscheinen. Die vorletzte Zeile zeigt, ob die Regel erkannt wurde: In der Ausgabe muss wp-cli.phar stehen.
Vorsicht: Normalerweise prüft man solche Regeln mit visudo. Das gibt es auf der Synology nicht. Tippe die Zeile deshalb genau ab – eine fehlerhafte Datei in /etc/sudoers.d kann sudo komplett lahmlegen. Wenn sudo -l einen Fehler meldet, lösche die Datei sofort wieder (rm /etc/sudoers.d/wpcli), solange du noch als root angemeldet bist.
Zur Einordnung: Dein Benutzer ist ohnehin Administrator der Synology. Die Regel gibt ihm keine Rechte, die er nicht schon hat – sie spart nur die Passwortabfrage für diesen einen Befehl.
Schritt 4: Das Hilfsprogramm für die Mediathek
Hier kam der größte Stolperstein. Der normale Befehl wäre wp media import bild.png. Auf meiner Synology antwortete WP-CLI aber nur:
Error: Strange wp-config.php file: wp-settings.php is not loaded directly.
Der Grund: Synology lagert das Ende der wp-config.php in eine eigene Datei aus (syno-wp-config-custom.php). WordPress selbst stört das nicht, WP-CLI aber schon. Die wp-config.php wollte ich nicht umbauen – ein Paket-Update könnte sie wieder überschreiben.
Die Lösung: WP-CLI startet mit --skip-wordpress, also ohne eigene Prüfung, und ein kleines PHP-Programm lädt WordPress ganz normal über wp-load.php – so wie WordPress es auch selbst tut. Dann trägt es das Bild mit den Bordmitteln von WordPress ein. Lege auf dem Mac einen Ordner an, zum Beispiel ~/Werkzeuge/finder-aktion, und speichere darin diese Datei als import.php:
<?php
/**
* Bild in die WordPress-Mediathek eintragen (für die Finder-Schnellaktion).
* Aufruf auf der Synology, als Benutzer, dem WordPress gehört:
* php82 wp-cli.phar eval-file import.php --skip-wordpress --path=/volume1/web_packages/wordpress test
*/
$wp_dir = '/volume1/web_packages/wordpress'; // ← ggf. anpassen
$_SERVER['HTTP_HOST'] = $_SERVER['HTTP_HOST'] ?? 'localhost';
$_SERVER['REQUEST_URI'] = $_SERVER['REQUEST_URI'] ?? '/';
define( 'WP_USE_THEMES', false );
require $wp_dir . '/wp-load.php';
$a = isset( $args ) ? $args : array_slice( $argv, 1 );
// Test: zeigt nur an, ob WordPress geladen werden kann.
if ( empty( $a ) || 'test' === $a[0] ) {
echo 'WordPress geladen: ' . get_option( 'siteurl' ) . "\n";
echo 'Bilder in der Mediathek: ' . wp_count_posts( 'attachment' )->inherit . "\n";
exit( 0 );
}
// Texte kommen base64-kodiert („b64:…“), damit Umlaute und Anführungszeichen sicher ankommen.
$dec = function ( $v ) {
return ( 0 === strpos( (string) $v, 'b64:' ) ) ? (string) base64_decode( substr( $v, 4 ) ) : (string) $v;
};
$file = $a[0];
$alt = isset( $a[1] ) ? trim( $dec( $a[1] ) ) : '';
$orig = isset( $a[2] ) ? $dec( $a[2] ) : basename( $file );
if ( ! is_readable( $file ) ) {
fwrite( STDERR, "FEHLER: Datei nicht lesbar: $file\n" );
exit( 1 );
}
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/media.php';
require_once ABSPATH . 'wp-admin/includes/image.php';
// Als erster Administrator handeln, damit der Autor stimmt.
$admins = get_users( array( 'role' => 'administrator', 'number' => 1, 'orderby' => 'ID' ) );
if ( $admins ) {
wp_set_current_user( $admins[0]->ID );
}
// Dateiname aufräumen: × → x, @ → -, Leerzeichen → -, Umlaute umschreiben.
$name = str_replace( array( '×', '@', ' ' ), array( 'x', '-', '-' ), basename( $orig ) );
$name = sanitize_file_name( remove_accents( $name ) );
// media_handle_sideload verschiebt die Datei – deshalb mit einer Kopie arbeiten.
$tmp = wp_tempnam( $name );
copy( $file, $tmp );
$id = media_handle_sideload( array( 'name' => $name, 'tmp_name' => $tmp ), 0 );
if ( is_wp_error( $id ) ) {
@unlink( $tmp );
fwrite( STDERR, 'FEHLER: ' . $id->get_error_message() . "\n" );
exit( 1 );
}
if ( '' !== $alt ) {
update_post_meta( $id, '_wp_attachment_image_alt', sanitize_text_field( $alt ) );
}
echo "OK $id " . wp_get_attachment_url( $id ) . "\n";
Zweiter Stolperstein, gleich mitgelöst: Ohne die Angabe --path=… beim Aufruf hält WP-CLI den Ordner, aus dem es gestartet wurde, für den WordPress-Ordner. Bei mir war das /tmp – und WordPress suchte seine Dateien dann dort.
Schritt 5: Das Skript für die Schnellaktion
Im selben Ordner speicherst du dieses Skript als zu-wordpress-hochladen.sh. Oben im Abschnitt „anpassen“ trägst du deine Werte ein:
#!/bin/bash
# Finder-Schnellaktion „Zu WordPress hochladen“
# Fragt je Bild nach dem Alternativtext und trägt es per SSH + WP-CLI in die Mediathek ein.
# ---- anpassen ----
SYNO="deinbenutzer@192.168.1.50" # Benutzer und IP der Synology
PORT=22 # SSH-Port
KEY="$HOME/.ssh/synology" # SSH-Schlüssel
WPUSER="WordPress" # Besitzer des WordPress-Ordners
PHP="/usr/local/bin/php82" # PHP-Version auf der Synology
WPPATH="/volume1/web_packages/wordpress"
# -------------------
DIR="$(cd "$(dirname "$0")" && pwd)"
LOG="$DIR/upload.log"
SSHO=(-i "$KEY" -p "$PORT" -o IdentitiesOnly=yes -o BatchMode=yes -o ConnectTimeout=8)
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG"; }
meldung() { osascript -e "display notification \"$2\" with title \"$1\"" >/dev/null 2>&1; }
fehler() { log "FEHLER: $1"; osascript -e "display alert \"Zu WordPress hochladen\" message \"$1\" as critical" >/dev/null 2>&1; }
[ "$#" -eq 0 ] && { fehler "Keine Datei übergeben."; exit 1; }
# Arbeitsordner auf der Synology anlegen und das Hilfsprogramm hinüberschicken.
# Hinweis: Kopiert wird mit „ssh … cat“, nicht mit scp – scp braucht SFTP, das auf vielen Synologys aus ist.
RT="/tmp/wp-up-$$"
if ! ssh "${SSHO[@]}" "$SYNO" "mkdir -p $RT && chmod 755 $RT && cat > $RT/import.php && chmod 644 $RT/import.php" < "$DIR/import.php" 2>>"$LOG"; then
fehler "Die Synology ist nicht erreichbar. Bist du im Heimnetz?"; exit 1
fi
OK=0; NR=0
for F in "$@"; do
NR=$((NR+1)); NAME="$(basename "$F")"
case "$(echo "${NAME##*.}" | tr 'A-Z' 'a-z')" in
png|jpg|jpeg|webp|gif) ;;
*) fehler "„$NAME“ ist kein Bild und wurde übersprungen."; continue ;;
esac
ALT=$(osascript <<OSA 2>/dev/null
set n to "$(echo "$NAME" | sed 's/["\\]/ /g')"
try
set r to display dialog "Alternativtext für:" & return & n default answer "" with title "Zu WordPress hochladen" buttons {"Überspringen", "Hochladen"} default button "Hochladen"
if button returned of r is "Hochladen" then return text returned of r
return "##SKIP##"
on error
return "##ABBRUCH##"
end try
OSA
)
[ "$ALT" = "##ABBRUCH##" ] && break
[ "$ALT" = "##SKIP##" ] && continue
ALT64="b64:$(printf '%s' "$ALT" | base64 | tr -d '\n')"
NAME64="b64:$(printf '%s' "$NAME" | base64 | tr -d '\n')"
if ! ssh "${SSHO[@]}" "$SYNO" "cat > $RT/bild-$NR && chmod 644 $RT/bild-$NR" < "$F" 2>>"$LOG"; then
fehler "„$NAME“ konnte nicht kopiert werden."; continue
fi
ERG=$(ssh "${SSHO[@]}" "$SYNO" "cd /tmp && sudo -n -u $WPUSER $PHP /usr/local/bin/wp-cli.phar eval-file $RT/import.php --skip-wordpress --path=$WPPATH $RT/bild-$NR '$ALT64' '$NAME64'" 2>&1)
if echo "$ERG" | grep -q '^OK '; then
OK=$((OK+1)); log "Hochgeladen: $NAME → $(echo "$ERG" | grep '^OK ' | cut -d' ' -f2-)"
meldung "In der Mediathek" "$NAME"
else
log "$ERG"; fehler "„$NAME“: $(echo "$ERG" | grep -m1 -E 'FEHLER|Error|error' | cut -c1-200)"
fi
done
ssh "${SSHO[@]}" "$SYNO" "rm -rf $RT" 2>/dev/null
[ "$OK" -gt 0 ] && meldung "Zu WordPress hochladen" "$OK Bild(er) in der Mediathek."
exit 0
Danach im Terminal ausführbar machen:
chmod +x ~/Werkzeuge/finder-aktion/zu-wordpress-hochladen.sh
Was das Skript macht: Für jedes Bild fragt es nach dem Alternativtext, kopiert das Bild über SSH in einen Arbeitsordner auf der Synology, ruft dort das Hilfsprogramm als Benutzer „WordPress“ auf und räumt danach auf. Am Ende meldet sich der Mac mit „In der Mediathek“. Geht etwas schief, erscheint ein Hinweisfenster, und Details stehen in upload.log.
Dritter Stolperstein: Ich hatte die Dateien zuerst mit scp kopiert und bekam subsystem request failed on channel 0. Neuere macOS-Versionen kopieren mit scp intern über SFTP – und das ist auf vielen Synologys ausgeschaltet. Deshalb kopiert das Skript mit ssh … cat.
Schritt 6: Die Schnellaktion in Automator anlegen
- Öffne Automator (⌘ + Leertaste, „Automator“), wähle Neues Dokument → Schnellaktion.
- Stelle oben ein: „Arbeitsablauf empfängt aktuelle: Bilddateien“ in „Finder.app“. (Nicht ins Suchfeld links tippen – das sind die Auswahlfelder rechts oben.)
- Suche links nach „Shell-Skript ausführen“ und ziehe die Aktion nach rechts in die graue Fläche.
- Stelle in der Aktion Shell: /bin/bash und Eingabe übergeben: als Argumente ein.
- Ersetze den Text im Feld durch eine einzige Zeile:
"$HOME/Werkzeuge/finder-aktion/zu-wordpress-hochladen.sh" "$@" - Speichere mit ⌘S unter dem Namen „Zu WordPress hochladen“.
Schritt 7: Ausprobieren
Klicke im Finder mit der rechten Maustaste auf ein Bild und wähle Schnelle Aktionen → Zu WordPress hochladen (bei manchen macOS-Versionen unter Dienste). Gib zum Testen einen Alternativtext ein und klicke auf Hochladen. Beim ersten Mal fragt macOS eventuell, ob die Aktion auf Dateien zugreifen darf – das erlaubst du.
Dann in WordPress unter Medien → Mediathek nachsehen: Das Bild ist da, mit Alternativtext, aufgeräumtem Dateinamen und allen verkleinerten Versionen. Du kannst auch mehrere Bilder auf einmal markieren – das Skript fragt dann für jedes einzeln.
Gut zu wissen
- Nur im Heimnetz. Bist du unterwegs, meldet die Aktion, dass die Synology nicht erreichbar ist.
- Nach großen DSM-Updates kann es passieren, dass die sudo-Regel oder WP-CLI weg ist. Dann bricht die Aktion mit einer Fehlermeldung ab, und du wiederholst Schritt 2 und 3. Kaputt geht dabei nichts.
- Dateinamen: Das Skript macht aus „ד ein „x“ und aus „@“ ein „-“. Solche Zeichen in Bildnamen hatten mir vorher beim Teilen in WhatsApp Ärger gemacht.
- Ausprobieren ohne Risiko: Mit
sudo -n -u WordPress /usr/local/bin/php82 /usr/local/bin/wp-cli.phar eval-file /pfad/zu/import.php --skip-wordpress --path=/volume1/web_packages/wordpress testauf der Synology siehst du, ob WordPress geladen werden kann – ohne etwas zu verändern.
Was ich daraus mitnehme
Der Weg war länger als gedacht: Rechte, die nicht passen, ein fehlendes visudo, eine wp-config.php, die WP-CLI nicht versteht, und ein scp, das plötzlich nicht mehr will. Jeder dieser Punkte für sich ist klein – zusammen haben sie einen Nachmittag gekostet. Dafür spare ich jetzt bei jedem Beitrag den Umweg über den Browser. Und wenn du über eine der Fehlermeldungen oben gestolpert bist: Jetzt weißt du, woran es liegt.