-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Built release for 0.3.2. For a full change log look at the notes with…
…in the original/0.3.2 release.
- Loading branch information
0 parents
commit 30c2d0c
Showing
26 changed files
with
15,411 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
# Publication Checklist | ||
|
||
Run checks and enforce conditions before posts are published. Built and designed for the WordPress block editor. | ||
|
||
Publication Checklist provides a framework for building out prepublish checks, with flexibility to fit your workflows. | ||
|
||
|
||
## Demo Plugin | ||
|
||
If you prefer to get a boilerplate plugin to add checks and start playing with existing code directly you can download, install and activate the demo plugin available here: | ||
|
||
https://github.com/humanmade/demo-publication-checklist | ||
|
||
|
||
## Creating checks | ||
|
||
The core of a check is a function that receives the post's data and meta, and returns a `Status` object. This status object indicates whether publish should be blocked or not. | ||
|
||
For example, to enforce setting a value for the "foo" meta key: | ||
|
||
```php | ||
use function Altis\Workflow\PublicationChecklist\register_prepublish_check; | ||
use Altis\Workflow\PublicationChecklist\Status; | ||
|
||
add_action( 'altis.publication-checklist.register_prepublish_checks', function () { | ||
register_prepublish_check( 'foo', [ | ||
'run_check' => function ( array $post, array $meta, array $terms ) : Status { | ||
if ( isset( $meta['foo'] ) ) { | ||
return new Status( Status::COMPLETE, 'Foo completed' ); | ||
} | ||
|
||
return new Status( Status::INCOMPLETE, 'Missing foo data' ); | ||
}, | ||
] ); | ||
} ); | ||
``` | ||
|
||
Checks are registered via the `Altis\Workflow\PublicationChecklist\register_prepublish_check` function with a unique ID. This function should be called on the `altis.publication-checklist.register_prepublish_checks` action. | ||
|
||
**Note:** the `altis.publication-checklist.register_prepublish_checks` action runs on the `plugins_loaded` hook so you should make sure your `add_action()` call is run as soon as your custom plugin file is included or in your theme `functions.php`. Do not wrap it in a hook such as `init` or `after_setup_theme`. | ||
|
||
Your check function receives the post data as an array, and the post's meta data as an array. Your function should only use this data to run the check, as this may represent data before it is saved to the database. Specifically, your function's signature should be: | ||
|
||
```php | ||
function ( array $post, array $meta, array $terms ) : Status; | ||
``` | ||
|
||
Your function must return an `Altis\Workflow\PublicationChecklist\Status` object. This object is marked as either complete (allow publishing), incomplete (block publishing), or informational (show as failed, but allow publishing). This status object takes the status type (which should be either `Status::COMPLETE`, `Status::INCOMPLETE`, or `Status::INFO`) and a human-readable message. | ||
|
||
`$post` is an array of post data, matching the shape returned by `get_post( $id, ARRAY_A )`. `$meta` is an array of meta data, in the format `string $key => mixed|mixed[] $value`. `$terms` is an array of terms, in the format `string $taxonomy => int[] $terms`. | ||
|
||
You can additionally pass data with the status object, which can be used on the frontend to assist with rendering. | ||
|
||
By default, checks will only run against the `post` post type. You can pass the relevant type(s) as a `type` option: | ||
|
||
```php | ||
add_action( 'altis.publication-checklist.register_prepublish_checks', function () { | ||
// Pass a single type: | ||
register_prepublish_check( 'foo', [ | ||
'type' => 'page', | ||
// ... | ||
] ); | ||
|
||
// Or multiple: | ||
register_prepublish_check( 'foo', [ | ||
'type' => [ | ||
'post', | ||
'page', | ||
], | ||
// ... | ||
] ); | ||
``` | ||
|
||
|
||
## Displaying check status | ||
|
||
By default, Publication Checklist will render a simple checklist of all checks. | ||
|
||
You can override a specific item to render richer UI if needed. For example, you may wish to integrate deeply into the block editor, or allow users to correct failing checks inline. This UI is directly inserted into the React element tree and replaces the default output. | ||
|
||
Publication Checklist exposes a `altis-publishing-workflow.item.{check_id}` filter using [`withFilters`](https://github.com/WordPress/gutenberg/tree/master/packages/components/src/higher-order/with-filters) to allow overriding the list item component. | ||
|
||
For example, to wrap the default status message with a link to a documentation page for the `foo` check: | ||
|
||
```jsx | ||
import { Fragment } from '@wordpress/element'; | ||
|
||
addFilter( 'altis-publishing-workflow.item.image-texts', 'foo/link-message', () => { | ||
return props => { | ||
return ( | ||
<Fragment> | ||
{ props.renderStatusIcon() } | ||
<a href="http://example.com/">{ props.message }</a> | ||
</Fragment> | ||
); | ||
}; | ||
} ); | ||
``` | ||
|
||
Your component receives the following props: | ||
|
||
```jsx | ||
const propTypes = { | ||
// Check ID. | ||
name: PropTypes.string.isRequired, | ||
|
||
// Human-readable message returned from the backend. | ||
message: PropTypes.string.isRequired, | ||
|
||
// Status string. | ||
status: PropTypes.oneOf( [ 'complete', 'incomplete', 'info' ] ).isRequired, | ||
|
||
// Function to render the status of the current check. | ||
// () => ReactElement | ||
renderStatusIcon: PropTypes.func.isRequired, | ||
|
||
// Additional data from the backend. | ||
data: PropTypes.any, | ||
}; | ||
``` | ||
|
||
To enable advanced functionality, you may want to wrap this component in [selectors which provide data about the post](https://developer.wordpress.org/block-editor/data/data-core-block-editor/). Note that the backend acts as the canonical source of all check data, so changes to check status will require saving to the backend to take effect. | ||
|
||
|
||
## Enforcing checks | ||
|
||
To enforce these checks and block publication, filter the `altis.publication-checklist.block_on_failing` value and return true from your callback. This will change the UI to disable the publish button, display a user-facing message that checks must be completed, and block requests to publish the post. | ||
|
||
|
||
## Modifying the list view | ||
|
||
Publication Checklist will add a Tasks column to the Posts list screen showing the status of each post. This column is only shown if statuses have been registered. | ||
|
||
### Hiding the tasks column | ||
|
||
To hide this column, filter the `altis.publication-checklist.show_tasks_column` value and return false from your callback. This will hide the Tasks column. | ||
|
||
### Changing the location of the tasks column | ||
|
||
The tasks column appears after the title column by default on supported post types. | ||
|
||
To change which column the tasks column appears after use the `altis.publication-checklist.show_tasks_after_column` filter and return the desired column slug such as `title`, `author` or `tags` for example. | ||
|
||
|
||
## License | ||
|
||
Publication Checklist is licensed under the GPLv2 or later. Copyright 2019 Human Made and contributors. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
module.exports = ( api ) => { | ||
api.cache( true ); | ||
|
||
return { | ||
presets: [ '@wordpress/babel-preset-default' ], | ||
plugins: [ '@babel/plugin-proposal-class-properties' ], | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"owner":"humanmade","repo":"publication-checklist","sha":"e589b4e1db097cdd25a5c6e4397a92ee177a7a32","ref":"refs/tags/0.3.2","tagName":"0.3.2","branch":"gh-actions","tags":["0.3.2"],"updated_at":"2024-03-11T11:37:45.568Z"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
["lodash","react","wp-components","wp-compose","wp-data","wp-editPost","wp-element","wp-i18n","wp-plugins","wp-polyfill"] |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
.altis-publication-checklist { | ||
/* Style subtitle using extra class to override Gutenberg specificity */ | ||
/* The prepublish sidebar sits higher than modal overlays, so bump the z-index */ } | ||
.altis-publication-checklist__required { | ||
margin-top: 0; | ||
font-style: italic; } | ||
.altis-publication-checklist__items { | ||
margin: 0.5em 0; } | ||
.altis-publication-checklist__item { | ||
display: flex; | ||
line-height: 2; | ||
margin: 0; | ||
padding: 0; } | ||
.altis-publication-checklist__item > .components-button { | ||
display: inline; | ||
font-size: inherit; } | ||
.altis-publication-checklist__item--status-complete .altis-publication-checklist__item-message { | ||
text-decoration: line-through; } | ||
.altis-publication-checklist__status-icon { | ||
font-weight: bold; | ||
margin-right: 0.5em; | ||
text-align: center; | ||
width: 1em; } | ||
.altis-publication-checklist .altis-publication-checklist__toggle-completed.components-button { | ||
margin-top: 0.5em; } | ||
.altis-publication-checklist .altis-publication-checklist__subtitle { | ||
font-size: inherit; | ||
font-weight: inherit; | ||
margin-top: 1em; } | ||
.altis-publication-checklist__confirm-overlay.components-modal__screen-overlay { | ||
z-index: 100001; } | ||
.altis-publication-checklist__confirm-buttons { | ||
display: flex; | ||
justify-content: flex-end; } | ||
.altis-publication-checklist__confirm-buttons .components-button { | ||
margin-left: 1em; } | ||
|
||
.editor-post-publish-panel__prepublish, | ||
.post-publish-panel__postpublish { | ||
display: flex; | ||
flex-direction: column; | ||
padding-top: 1px !important; } | ||
.editor-post-publish-panel__prepublish .components-panel__body, | ||
.post-publish-panel__postpublish .components-panel__body { | ||
margin-top: -1px; | ||
order: 3; } | ||
.editor-post-publish-panel__prepublish .components-panel__body.altis-publication-checklist__replacement-header, | ||
.post-publish-panel__postpublish .components-panel__body.altis-publication-checklist__replacement-header { | ||
order: 1; | ||
padding: 0; } | ||
.editor-post-publish-panel__prepublish .components-panel__body.altis-publication-checklist__replacement-header .editor-post-publish-panel__header-publish-button, | ||
.post-publish-panel__postpublish .components-panel__body.altis-publication-checklist__replacement-header .editor-post-publish-panel__header-publish-button { | ||
justify-content: flex-start; | ||
text-align: left; } | ||
.editor-post-publish-panel__prepublish .altis-publication-checklist__panel, | ||
.post-publish-panel__postpublish .altis-publication-checklist__panel { | ||
order: 2; | ||
border-top: none; } | ||
.editor-post-publish-panel__prepublish .altis-publication-checklist__panel--to-complete .components-panel__body-title .components-button, | ||
.post-publish-panel__postpublish .altis-publication-checklist__panel--to-complete .components-panel__body-title .components-button { | ||
--indicator-size: 0.8em; | ||
position: relative; } | ||
.editor-post-publish-panel__prepublish .altis-publication-checklist__panel--to-complete .components-panel__body-title .components-button::before, | ||
.post-publish-panel__postpublish .altis-publication-checklist__panel--to-complete .components-panel__body-title .components-button::before { | ||
content: ''; | ||
display: inline-block; | ||
width: calc( var( --indicator-size ) + 0.5em); } | ||
.editor-post-publish-panel__prepublish .altis-publication-checklist__panel--to-complete .components-panel__body-title .components-button::after, | ||
.post-publish-panel__postpublish .altis-publication-checklist__panel--to-complete .components-panel__body-title .components-button::after { | ||
background: #f97a14; | ||
border-radius: 100%; | ||
content: ''; | ||
height: var(--indicator-size); | ||
margin-top: calc( -1 * var( --indicator-size ) / 2); | ||
position: absolute; | ||
top: 50%; | ||
width: var(--indicator-size); } | ||
.editor-post-publish-panel__prepublish .altis-publication-checklist__panel--completed .components-panel__body-title .components-button::after, | ||
.post-publish-panel__postpublish .altis-publication-checklist__panel--completed .components-panel__body-title .components-button::after { | ||
background: #3fcf8e; } | ||
|
||
/* Hide UI for disabling pre-publish checks */ | ||
.editor-post-publish-panel__footer { | ||
display: none; } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"name": "humanmade/publication-checklist", | ||
"description": "Run checks and enforce conditions before posts are published.", | ||
"type": "wordpress-plugin", | ||
"license": "GPL-3.0", | ||
"authors": [ | ||
{ | ||
"name": "Human Made", | ||
"email": "[email protected]" | ||
} | ||
], | ||
"require": { | ||
"php": ">=7.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
<?php | ||
|
||
namespace Altis\Workflow\PublicationChecklist; | ||
|
||
/** | ||
* Status indicator. | ||
* | ||
* Each status item represents a single check in the checklist, and the status | ||
* of that check: either complete (allow publish), incomplete (block publish), | ||
* or info (failed, but don't block publish). | ||
*/ | ||
class Status { | ||
const COMPLETE = 'complete'; | ||
const INCOMPLETE = 'incomplete'; | ||
const INFO = 'info'; | ||
|
||
/** | ||
* Status type. | ||
* | ||
* One of the status constants (`complete`, `incomplete`, `info`). | ||
* | ||
* @var string | ||
*/ | ||
protected $status; | ||
|
||
/** | ||
* Human-readable message explaining the status. | ||
* | ||
* @var string | ||
*/ | ||
protected $message; | ||
|
||
/** | ||
* Additional data about the check status. | ||
* | ||
* This data is passed to the frontend, and can be used to assist with | ||
* custom UI. | ||
* | ||
* @var mixed | ||
*/ | ||
protected $data; | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @param string $status Status type. | ||
* @param string $message Human-readable message. | ||
* @param mixed $data Additional data about the check. | ||
*/ | ||
public function __construct( string $status, string $message, $data = null ) { | ||
$this->status = $status; | ||
$this->message = $message; | ||
$this->data = $data; | ||
} | ||
|
||
/** | ||
* Get the status type. | ||
* | ||
* @return string One of the status constants (`complete`, `incomplete`, `info`) | ||
*/ | ||
public function get_status() : string { | ||
return $this->status; | ||
} | ||
|
||
/** | ||
* Get the status message. | ||
* | ||
* @return string Human-readable message explaining the status. | ||
*/ | ||
public function get_message() : string { | ||
return $this->message; | ||
} | ||
|
||
/** | ||
* Get additional data about the status. | ||
* | ||
* @return mixed Additional data about the check status. | ||
*/ | ||
public function get_data() { | ||
return $this->data; | ||
} | ||
} |
Oops, something went wrong.