Skip to content

Latest commit

 

History

History
241 lines (198 loc) · 8.43 KB

File metadata and controls

241 lines (198 loc) · 8.43 KB

Vector Archive Format

A portable, self-describing archive format for WordPress site data. A Vector archive is a single gzip-compressed tar file (.tar.gz) containing a metadata.json manifest alongside a database dump and/or filesystem snapshot.


Archive Structure

archive.tar.gz
├── metadata.json              ← manifest (always first entry)
├── database.sql               ← mysqldump output (when scope includes database)
├── wp-content/uploads/...     ← WordPress files at natural paths (when scope includes files)
├── wp-content/plugins/...
├── wp-content/themes/...
├── wp-content/mu-plugins/...
├── wp-content/languages/...
└── wp-config.php
  • Single file. The archive is one .tar.gz — easy to upload, download, and transfer.
  • metadata.json is always the first tar entry. This enables cheap manifest extraction without decompressing the full archive: tar xzf archive.tar.gz metadata.json -O.
  • database.sql is uncompressed inside the tar. Compression comes from the outer gzip layer — no double-gzip.
  • WordPress files use natural paths relative to the WP root. No wrapper directory.
  • WordPress core files are not included. Only wp-content/ subdirectories (uploads, plugins, themes, mu-plugins, languages) and wp-config.php. WordPress core is reproducible from the official package.
  • Scope determines which entries exist. A database-scope archive has no file entries. A files-scope archive has no database.sql. A full-scope archive has both.

Extracting the Manifest

To read the manifest without extracting the full archive:

tar xzf archive.tar.gz metadata.json -O

This decompresses only the first few KB of the gzip stream (since metadata.json is the first entry), regardless of total archive size.


Manifest Examples

Full Backup

{
  "version": "1.0",
  "created_at": "2026-02-04T02:00:00Z",
  "scope": "full",
  "compression": "gzip",
  "app": {
    "type": "wordpress",
    "version": "6.7.1",
    "php_version": "8.3.30",
    "site_url": "https://mysite.example.com",
    "multisite": false,
    "active_theme": "flavor/flavor",
    "active_plugins": [
      { "name": "woocommerce", "version": "8.5.1" },
      { "name": "wordfence", "version": "7.11.0" }
    ]
  },
  "database": {
    "engine": "mysql",
    "version": "8.0.36",
    "name": "wordpress",
    "tables": [
      "wp_commentmeta", "wp_comments", "wp_links", "wp_options",
      "wp_postmeta", "wp_posts", "wp_term_relationships",
      "wp_term_taxonomy", "wp_termmeta", "wp_terms",
      "wp_usermeta", "wp_users"
    ],
    "prefix": "wp_",
    "charset": "utf8mb4",
    "collation": "utf8mb4_unicode_520_ci"
  },
  "files": {
    "includes": [
      "wp-content/uploads",
      "wp-content/plugins",
      "wp-content/themes",
      "wp-content/mu-plugins"
    ],
    "excludes": [
      "wp-content/cache",
      "wp-content/upgrade",
      "wp-content/debug.log"
    ]
  }
}

Database-Only Backup

{
  "version": "1.0",
  "created_at": "2026-02-04T14:30:00Z",
  "description": "Before WooCommerce 9.0 update",
  "scope": "database",
  "compression": "gzip",
  "app": {
    "type": "wordpress",
    "version": "6.7.1",
    "php_version": "8.3.30",
    "site_url": "https://store.example.com",
    "multisite": false,
    "active_plugins": [
      { "name": "woocommerce", "version": "8.5.1" }
    ]
  },
  "database": {
    "engine": "mysql",
    "version": "8.0.36",
    "name": "wordpress",
    "tables": [
      "wp_commentmeta", "wp_comments", "wp_links", "wp_options",
      "wp_postmeta", "wp_posts", "wp_term_relationships",
      "wp_term_taxonomy", "wp_termmeta", "wp_terms",
      "wp_usermeta", "wp_users",
      "wp_wc_orders", "wp_wc_order_items"
    ],
    "prefix": "wp_"
  }
}

Minimal Archive

An archive with minimal metadata — only the required fields:

{
  "version": "1.0",
  "created_at": "2026-02-04T18:00:00Z",
  "scope": "full",
  "compression": "gzip",
  "app": {
    "type": "wordpress",
    "version": "6.5.0",
    "php_version": "8.1.27",
    "site_url": "https://old-host.example.com"
  },
  "database": {
    "engine": "mariadb",
    "version": "10.6.12",
    "name": "oldsite_wp",
    "tables": ["wp_options", "wp_posts", "wp_users"],
    "prefix": "wp_"
  },
  "files": {
    "includes": ["wp-content/"]
  }
}

Field Reference

Root Fields

Field Type Required Description
version string Yes Manifest schema version. Currently "1.0".
created_at string (ISO 8601) Yes UTC timestamp when the archive was created.
description string No Human-provided label (e.g., "Before WooCommerce update").
scope string Yes What the archive contains: "full", "database", or "files".
compression string Yes Compression format used for the archive: "gzip".

Scope values:

Value Description
full Contains both database dump and filesystem entries.
database Contains database dump only. No file entries.
files Contains filesystem entries only. No database.sql.

app Object

Describes the application that was backed up. Fields beyond type vary by application and are all optional — the tool captures what it can detect.

Field Type Required Description
app.type string Yes Application type: "wordpress", "unknown".
app.version string No Application version (e.g., "6.7.1" for WordPress).
app.php_version string No PHP version at backup time (e.g., "8.3.30").
app.site_url string No Site URL at backup time. Used as "from" in search-replace on restore.
app.multisite boolean No Whether this is a WordPress multisite installation.
app.active_theme string No Active theme slug (e.g., "flavor/flavor").
app.active_plugins array No Active plugins. Each entry: { "name": "slug", "version": "x.y.z" }.
  • app.type tells consumers how to interpret the rest of the app fields.
  • When app.type is "unknown", no other app fields are expected.

database Object

Present when scope includes database. Omitted when scope is "files".

Field Type Required Description
database.engine string Yes Database engine: "mysql", "mariadb".
database.version string Yes Database server version (e.g., "8.0.36").
database.name string Yes Database name that was dumped.
database.tables string[] Yes All table names included in the dump.
database.prefix string No Table prefix (e.g., "wp_"). WordPress-specific.
database.charset string No Character set (e.g., "utf8mb4").
database.collation string No Collation (e.g., "utf8mb4_unicode_520_ci").

files Object

Present when scope includes files. Omitted when scope is "database".

Field Type Required Description
files.includes string[] No Directories/files that were included.
files.excludes string[] No Directories/files that were excluded.

platform Object

Vendor/platform-specific metadata. Consumers that don't recognize the platform should ignore this section entirely. The entire object is optional — archives created by third-party tools won't have it.

Field Type Required Description
platform.name string Yes Platform identifier.
platform.type string No Archive type (e.g., "manual", "scheduled", "import").

Versioning Rules

  • Readers must ignore unknown fields — don't error on fields you don't recognize.
  • New optional fields can be added without a version bump.
  • New required fields or changed semantics require a version bump.
  • The tool always writes the latest version.

Manifest Ordering

The manifest (metadata.json) is always the first entry in the tar archive. This serves two purposes:

  1. Completeness signal — its presence means the archive was fully written. If extraction fails or the manifest is missing, the archive is corrupt or incomplete.
  2. Cheap extraction — consumers can read just the manifest without decompressing the entire archive, since gzip decompression only needs to process the stream up to the end of the first tar entry.