— Artikel — № 018

018 —WordPress

WordPress zonder dashboard: waarom bureaus in FTP wonen

Waarom ervaren WordPress-bureaus wp-admin overslaan en hun werkdag draaien vanuit een file tree, een SQL-prompt en een tail op het error log.

Messing sleutel op crème papieren kaart met zwart gestempeld label en rode lakzegel, op donker eiken bureau.
Hero · gestileerd stilleven№ 018

Om 23:41 op een dinsdag stuurde een bureau-eigenaar een Loom van zijn scherm. Geen browser. Geen wp-admin. Alleen een file tree op een shared host, een MySQL-prompt in een ander paneel, en een tail -f op error_log. "Zo runnen we klantsites sinds 2014," zei hij. "Het dashboard is voor de klant. Daar gaan we niet in tenzij het echt moet."

Die houding klinkt ketters tot je een paar jaar hebt opgeruimd na WordPress-dashboards. Dan klinkt het als een vanzelfsprekende werkkeuze. Deze post gaat over waarom sommige bureaus een WordPress-portfolio bijna volledig draaien vanuit FTP en MySQL, wat ze ermee winnen, en waar de aanpak stukloopt. Als je ooit wp-admin hebt weggeklikt en in plaats daarvan een SFTP-client hebt geopend, herken je de vorm hiervan.

Het dashboard is een klantoppervlak, geen operator-oppervlak

De WordPress-admin is rond 2005 ontworpen voor één gebruiker die posts intikt. Er kwamen pluginpagina's bij, theme-opties, een blokeditor, een site-editor en een dozijn overlappende menustructuren, maar de onderliggende aanname is nooit veranderd: de operator is dezelfde persoon als de auteur van de content. Voor een bureau dat dertig of veertig verouderde sites beheert, klopt die aanname niet.

De operator wil weten welke plugin de homepage 400 ms heeft vertraagd na de auto-update van vannacht. De auteur wil een persbericht publiceren. Beide taken achter dezelfde login plaatsen dwingt elke operator-actie door een UI die voor het andere doel is afgestemd. Zo krijg je bureaus die wp-admin alleen behandelen als content-oppervlak, en het operator-werk elders doen.

Dat 'elders' is bijna altijd twee dingen: het filesystem via SFTP, en de database via een SQL-client. Zodra je dat accepteert, wordt veel WordPress-onderhoud eenvoudiger.

Hoe 'in de FTP wonen' er in de praktijk uitziet

De uitdrukking is een afkorting. Niemand gebruikt in 2026 nog plain FTP als het te vermijden valt; SFTP over SSH is het minimum. Maar het werkpatroon is hetzelfde als vijftien jaar geleden.

Een bureau-engineer opent de site tree en gaat direct naar wp-content/. De indeling is bekend. plugins/ bevat de traag bewegende WooCommerce-stack en de snelle 'de klant wilde iets'-plugins. themes/ is meestal één child theme van een parent die al twee jaar niet is aangeraakt. uploads/ is waar elke 'de site is nu enorm'-klacht in werkelijkheid zit.

Drie bestanden worden constant geopend:

  • wp-config.php voor database-credentials, debug-flags, memory limits en de table prefix.
  • .htaccess in de document root voor redirects, security blocks en PHP-value overrides.
  • wp-content/debug.log als WP_DEBUG_LOG aanstaat, of de error_log van de host als dat niet zo is.

Het eerste wat de meeste operators op een nieuwe site doen, is debug-output forceren naar een bestand dat het dashboard nooit te zien krijgt:

// wp-config.php: operator-side debugging, never on a production dashboard
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );      // writes to wp-content/debug.log
define( 'WP_DEBUG_DISPLAY', false ); // never leak warnings to visitors
@ini_set( 'display_errors', 0 );

Dat geeft je een echt log dat je kunt tail-en, in plaats van te proberen een deprecation warning te reproduceren door door admin-pagina's te klikken.

De .htaccess als het echte controlpaneel

De meeste operator-configuratie die eigenlijk in een settings-UI thuishoort, staat in plaats daarvan in .htaccess. Een typisch bureau-blok op een gehardende WordPress-installatie ziet er ongeveer zo uit:

# Block direct PHP execution inside uploads
<Directory /var/www/site/wp-content/uploads>
  <FilesMatch "\.(php|phtml|phar)$">
    Require all denied
  </FilesMatch>
</Directory>

# Stop XML-RPC entirely. Almost no client uses it, attackers love it
<Files xmlrpc.php>
  Require all denied
</Files>

# Force HTTPS without depending on a plugin
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Niets daarvan is bereikbaar vanuit wp-admin zonder een plugin te installeren, en die plugin is óf traag, óf verlaten, óf allebei. De Apache rewrite docs zijn nog altijd de canonieke referentie; bookmark ze één keer en je hebt de pluginlaag niet meer nodig.

SQL verslaat het zoekvak van wp-admin

De tweede helft van het bureauleven is de database. Zodra je je SQL-client meer vertrouwt dan het dashboard, krimpt een hele categorie problemen in tot queries van twee regels.

Vind elke post die na een migratie nog naar een oud domein linkt:

SELECT ID, post_title
FROM wp_posts
WHERE post_status = 'publish'
  AND post_content LIKE '%old-domain.test%';

Vind de autoloaded options die stilletjes je TTFB om zeep helpen:

SELECT option_name, LENGTH(option_value) AS bytes
FROM wp_options
WHERE autoload = 'yes'
ORDER BY bytes DESC
LIMIT 20;

Die tweede query is een van de meest impactvolle dingen die je op een trage WordPress-site kunt draaien. Een opgezwollen wp_options-tabel is veruit de meest voorkomende oorzaak van een site die 'over de jaren traag is geworden'. Je vindt dit niet vanuit het dashboard, want het dashboard is juist het ding dat de bloat schrijft.

Een URL over een hele site vervangen op de juiste manier, hoort ook in SQL-terrein. Directe UPDATE-statements breken geserialiseerde PHP-arrays in wp_options en wp_postmeta, dus het werkbare gereedschap is Search-Replace-DB van interconnect/it of het equivalent in WP-CLI. Hoe dan ook: het is een script dat je draait, geen formulier in een dashboard.

Waar de FTP-first aanpak stukloopt

Het eerlijke deel. In de file tree wonen is geen schone winst.

Het veronderstelt dat je code kunt lezen. Een WooCommerce-shop met twintig plugins is een dependency-graaf die je niet in je hoofd houdt, en grep-en op een hook-naam brengt je maar zo ver. Het veronderstelt dat je een staging-kopie hebt, want direct in een productie-functions.php editen via SFTP is hoe sites om 02:00 op een white screen eindigen. En het veronderstelt dat je een audit trail hebt, en die geeft rauwe SFTP je niet. Twee engineers die hetzelfde bestand editen, overschrijven elkaar zonder waarschuwing.

De klassieke bureau-workaround is een Git-mirror van wp-content/ met een deploy hook, plus een dagelijkse mysqldump naar S3. Dat werkt, maar het is veel infrastructuur per klantsite, en zodra een klant een tekstwijziging van één teken vraagt, ben je alsnog aan het SSH-en.

De vorm van die kloof is overal zichtbaar waar mensen WordPress op schaal beheren. WP-CLI bestaat omdat het dashboard de verkeerde plek is om plugins in bulk te updaten of salts te roteren. De officiële debugging guide gaat vooral over flags die je in wp-config.php zet, niet over schermen waarop je klikt. Operator-controle over een WordPress-installatie zit per ontwerp buiten de admin-UI.

Hoe een werkende bureau-setup eruitziet

Als je schetst wat een stabiel WordPress-bureau in 2026 daadwerkelijk draait, ziet het er ongeveer zo uit:

  1. SFTP naar wp-content/ als primair edit-oppervlak, met een lokale mirror in een echte editor.
  2. Een SQL-client verbonden met de live database voor reads, en met een staging-kopie voor writes.
  3. WP_DEBUG_LOG aan, getail-d in een terminalvenster dat de hele dag open blijft.
  4. Een back-upjob die draait voor elke deploy en na elke schemawijziging.
  5. wp-admin overgedragen aan de klant, het operator-account alleen gebruikt als iets wat de klant deed teruggedraaid moet worden.

Het dashboard is er nog steeds. Het is alleen gedegradeerd naar het oppervlak waar het altijd al het beste in was: niet-technische auteurs laten publiceren.

Het gat in version history

Het enige wat deze workflow altijd heeft gemist, is bruikbare version history. SFTP geeft je een bestand; het geeft je niet het bestand van gisteren. Git op wp-content/ is de standaardoplossing en die werkt, maar het is setup-per-site en de meeste eenmansbureaus slaan het over bij kleinere klanten. De kosten van overslaan komen aan het licht zodra een plugin-update een custom hook in een child theme stilletjes overschrijft.

Toen we Pier bouwden, liepen we precies hier tegenaan, omdat de mensen voor wie we het bouwden al in SFTP en een MySQL editor leefden. Wat we uiteindelijk deden, was elke save automatisch versioneren aan de serverkant, zodat one-click rollback werkt of de wijziging nu uit een chat-prompt of een handmatige bestandswijziging komt.

Het kleinste wat je vandaag kunt doen: zet WP_DEBUG_LOG aan op één site die je beheert, tail wp-content/debug.log een uur lang, en zie wat je dashboard al die tijd voor je verborgen heeft.

— Vragen —

Is WordPress bewerken via SFTP veilig op een live site?

Een staging-kopie bewerken en deployen is veiliger. Directe edits op productie werken voor kleine CSS- of template-wijzigingen, maar nooit voor functions.php of plugincode zonder een geteste rollback.

Waarom is wp_options zo vaak de oorzaak van traagheid?

Plugins schrijven autoloaded options die bij elke request worden geladen. Over de jaren laten verlaten plugins megabytes aan autoload-data achter. Eén query op wp_options vindt het meestal binnen enkele minuten.

Kan ik een URL-search-replace doen met gewone SQL?

Alleen voor niet-geserialiseerde kolommen zoals post_content. Alles wat geserialiseerde PHP-arrays kan bevatten (wp_options, wp_postmeta) heeft een tool nodig die serialisatie begrijpt, zoals WP-CLI search-replace of Search-Replace-DB.