Skip to content

Versioning System #1

Description

@xipasduarte

The aim of this plugin is to provide a system for versioning any post type.

Features

The basic features to support are:

  • Allow for any post type to be versioned (excluding revisions)
  • Allow versions to be tagged with custom numbers (e.g. continuous 1, 2, 3 ... or semver 1.0.0, 1.1.0, 2.0.0 ...)

Advanced features to consider are:

  • Resolve posts to the latest version
  • Allow working in "unreleased" versions

How it might work

We'll use revisions to control the changes, as they already are used in WordPress to provide the same feature. We'll bend the working of revisions to allow for:

  • Tagging revisions
  • Preventing delete of tagged revisions
  • Collapse untagged revisions between versions
  • Hide previous versions
  • Delete previous versions

Versions

Versions are numbered sequentially starting from 1. All versions are stored as a meta_key with the format:

post_version_#

Labeling versions

If there is a need for a custom version label, the value of that label should be the value of the version meta_key.

Statuses

We'll need to add a custom unreleased status to handle a specific state a post can be in. This status represents a post that has a previous version, but the current is not yet finalized.
A post is set tu unreleased when performing an action to create a new version, which means V1 is never unreleased.

The existence of this status is to prevent issues with queries that would exclude the post from results if w used draft or other statuses.

The First Version (V1)

When creating a post, a version is started (V1). All editing processes are the same, changes as draft, publishing or updating. When the post is published a new action appears: "Create new version".

What happens after V1?

New versions are born with the "Create new version" action. A new version is created with the following steps:

  1. Determine current version
  2. Remove old version meta_key
  3. Add new version meta_key
  4. Change status to unreleased
  5. Mark the latest revision, from the previous version, as publish

Keeping revisions clean

WordPress has a builtin system to clean old revisions. We interfere with this system to keep the latest revision of a given version from being deleted. (TODO: check if we don't need to disable revisions and implement our own system to prevent a loop in revision cleanup checks.)

Creating revisions

Revisions are potential versions in time. WordPress creates revisions when any of the post data is changed (this is only the data stored in the posts table). This means that meta fields and term associations are not stored with revision, i.e., these values are not versioned.

To be more in line with expectations we're going to add support for versioning these external data points. Whenever there is a meta/term operation, apart from read, related to a post, we force a revision creation. On all revisions we preform the following:

  • Go to the revision and add all relation to terms that the parent currently has
  • Go to the revision and add all meta values that the parent currently has

Note: ACF forces revision creation when saving meta. We should either (1) prevent our system from copying meta for all ACF fields; or (2) prevent the ACF revision system from firing.

Version management

For all previous version we'll provide a set of operations:

  • delete: users will be allowed to destroy the revision for a given version, but only if it's not the latest. Deleting a version doesn't trigger a version number recount.
  • hide: users will be able to hide version from the history. Hiding a version is an operation to change it's status to draft, which effectively removes it from public availability.

Queries

When queries are performed we'll update the value of the default statuses to include unreleased in the results. After the posts are fetched we'll perform the following filter on the results:

  • Check if the option to "hide unreleased" post_version_hide_unreleased is false? IF it is, we don't change anything
  • Loop through results and, for each unreleased status, replace with get_current_version() (Note: take care to match the expected result structure)

API

Below are some operations that should be available as an API to be used by developers of Plugins and Themes, or internally.

get_versions( int $post_id ) : WP_Post

Given an ID it'll return a list of WP_Posts for all revisions that represent a version for the post. A revision is a version when:

  • It has the highest ID for a given post_version_# meta key.

get_current_version( int $post_id ) : WP_Post

Given a post ID it'll fetch the current revision ID. The current revision is determined as follows:

  1. Is the post itself in a status publish? If true, the post ID is returned
  2. Call get_versions( $post_id )
  3. Loop through versions (latest to oldest) to find the first that is publishand return it

get_version( int $post_id, int|string $version ) : WP_Post

Retrieve a version based on it's ID or label.

  • If $version is an int fetch the revisions with meta key post_version_[$version]
  • If $version is a string fetch the revisions with meta value to $version
  • Return ID
  • If multiple revisions exist with the same version number, return the largest ID (latest)

Metadata

Metadata

Labels

enhancementNew feature or requesthelp wantedExtra attention is needed

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions