— Article — № 018

018 —WordPress

WordPress without the dashboard: why some agencies live in the FTP

A look at why working WordPress agencies bypass wp-admin entirely and run their day from a file tree, a SQL prompt and a tail on the error log.

Brass skeleton key on a cream paper card with black stamped label and red wax seal, on scarred dark oak desk.
Hero · staged still№ 018

At 23:41 on a Tuesday, an agency lead sent over a Loom of his screen. No browser. No wp-admin. Just a file tree on a shared host, a MySQL prompt in another pane, and a tail -f on error_log. "This is how we've run client sites since 2014," he said. "The dashboard is for the customer. We don't go in there unless we have to."

That stance sounds heretical until you've spent a few years cleaning up after WordPress dashboards. Then it sounds like an obvious workflow choice. This post is about why some agencies run a WordPress estate almost entirely from FTP and MySQL, what they gain from it, and where the approach breaks. If you've ever closed wp-admin and reached for an SFTP client instead, you'll recognise the shape of this.

The dashboard is a customer surface, not an operator surface

The WordPress admin was designed around 2005 for a single user typing posts. It picked up plugin pages, theme options, a block editor, a site editor, and a dozen overlapping menu structures, but the underlying assumption never changed: the operator is the same person as the content author. For an agency running thirty or forty legacy sites, that assumption is wrong.

The operator wants to know which plugin slowed the homepage by 400 ms after last night's auto-update. The author wants to publish a press release. Putting both jobs behind the same login forces every operator action to go through a UI tuned for the other use case. So you get agencies who treat wp-admin as a content surface only, and do the operator work elsewhere.

The elsewhere is almost always two things: the filesystem over SFTP, and the database over a SQL client. Once you accept that, a lot of WordPress maintenance simplifies.

What "living in the FTP" actually looks like

The phrase is shorthand. Nobody uses plain FTP in 2026 if they can avoid it; SFTP over SSH is the floor. But the working pattern is the same as it was fifteen years ago.

An agency engineer opens the site tree and goes straight to wp-content/. They already know the layout. plugins/ holds the slow-moving WooCommerce stack and the fast-moving "client wanted a thing" plugins. themes/ is usually one child theme of a parent that hasn't been touched in two years. uploads/ is where every "the site is huge now" complaint actually lives.

Three files get opened constantly:

  • wp-config.php for database creds, debug flags, memory limits, and the table prefix.
  • .htaccess at the document root for redirects, security blocks and PHP value overrides.
  • wp-content/debug.log when WP_DEBUG_LOG is on, or the host's error_log when it isn't.

The first thing most operators do on a new site is force debug output into a file the dashboard never sees:

// 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 );

That gives you a real log you can tail instead of trying to reproduce a deprecation warning by clicking through admin pages.

The .htaccess as the real control panel

Most of the operator-grade configuration that should be in a settings UI lives in .htaccess instead. A typical agency block on a hardened WordPress install looks something like this:

# 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]

None of that is reachable from wp-admin without installing a plugin, and the plugin will either be slow, abandoned, or both. The Apache rewrite docs are still the canonical reference; bookmark them once and you stop needing the plugin layer.

SQL beats the wp-admin search box

The second half of agency life is the database. Once you trust your SQL client more than the dashboard, a class of problems collapses to two-line queries.

Find every post that links to an old domain after a migration:

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

Find the autoloaded options that are quietly destroying TTFB:

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

That second query is one of the highest-leverage things you can run on a slow WordPress site. A bloated wp_options table is the single most common cause of a site that "got slow over the years." You will not find this from inside the dashboard, because the dashboard is the thing writing the bloat.

Replacing a URL across a site, the right way, also lives in SQL territory. Direct UPDATE statements break serialised PHP arrays inside wp_options and wp_postmeta, so the working tool is interconnect/it's Search-Replace-DB or the equivalent built into WP-CLI. Either way, it's a script you run, not a dashboard form.

Where the FTP-first approach breaks

The honest part. Living in the file tree is not a clean win.

It assumes you can read code. A WooCommerce store with twenty plugins is a dependency graph you cannot hold in your head, and grepping for a hook name only gets you so far. It assumes you have a staging copy, because directly editing a production functions.php over SFTP is how sites end up white-screened at 02:00. And it assumes you have an audit trail, which raw SFTP does not give you. Two engineers editing the same file overwrite each other silently.

The classic agency workaround is a Git mirror of wp-content/ with a deploy hook, plus a daily mysqldump to S3. That works, but it's a lot of plumbing per client site, and the moment a client asks for a one-character copy change you're still SSH-ing in.

The shape of the gap is visible everywhere people maintain WordPress at scale. WP-CLI exists because the dashboard is the wrong place to bulk-update plugins or rotate salts. The official debugging guide is mostly about flags you set in wp-config.php, not screens you click. Operator-level control of a WordPress install lives outside the admin UI, by design.

The shape of a working agency setup

If you sketch what a stable WordPress agency actually runs in 2026, it looks roughly like this:

  1. SFTP into wp-content/ as the primary editing surface, with a local mirror in a real editor.
  2. A SQL client connected to the live database for reads, and to a staging copy for writes.
  3. WP_DEBUG_LOG on, tailed in a terminal window that stays open all day.
  4. A backup job that runs before any deploy and after any schema change.
  5. wp-admin handed to the client, with the operator's account used only when something the client did needs to be undone.

The dashboard is still there. It's just demoted to the surface it was always best at: letting non-technical authors publish.

The version-history gap

The one thing this workflow has always lacked is a usable version history. SFTP gives you a file; it does not give you yesterday's file. Git on wp-content/ is the standard fix, and it works, but it's per-site setup and most one-person agencies skip it on smaller clients. The cost of skipping it shows up the first time a plugin update silently overwrites a custom hook in a child theme.

When we built Pier we ran into this exact thing, because the people we built it for were already living in SFTP and a MySQL editor. The way we ended up handling it was to version every save automatically, on the server side, so one-click rollback works whether the edit came from a chat prompt or a manual file change.

The smallest thing you can do today: turn on WP_DEBUG_LOG on one site you maintain, tail wp-content/debug.log for an hour, and see what your dashboard has been hiding from you.

— Questions —

Is editing WordPress over SFTP safe on a live site?

Editing a staging copy and deploying is safer. Direct edits on production work for small CSS or template changes, but never for functions.php or plugin code without a tested rollback path.

Why is wp_options so often the source of slowness?

Plugins write autoloaded options that load on every request. Over years, abandoned plugins leave megabytes of autoload data behind. A single query against wp_options usually finds it in minutes.

Can I do a URL search-replace with plain SQL?

Only for unserialised columns like post_content. Anything that may contain serialised PHP arrays (wp_options, wp_postmeta) needs a serialisation-aware tool such as WP-CLI search-replace or Search-Replace-DB.

Should I disable wp-admin entirely?

No. Clients still need it to publish. The pattern is to demote it to a content surface, do operator work over SFTP and SQL, and keep an admin account only for cleanup.