Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-components', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => 'fafeef797d9428b9960f');
<?php return array('dependencies' => array('react', 'react-dom', 'wp-api-fetch', 'wp-components', 'wp-dom-ready', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => '02ffd04fe291168f5b3e');
2 changes: 1 addition & 1 deletion dist/modules/custom-status/custom-status-configure.js

Large diffs are not rendered by default.

50 changes: 24 additions & 26 deletions modules/custom-status/custom-status.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@

namespace VIPWorkflow\Modules;

require_once __DIR__ . '/rest/custom-status.php';
require_once __DIR__ . '/rest/custom-status-endpoint.php';

use VIPWorkflow\Modules\CustomStatus\REST\CustomStatusEndpoint;
use VIPWorkflow\VIP_Workflow;
use VIPWorkflow\Modules\Shared\PHP\Module;
use VIPWorkflow\Modules\CustomStatus\REST\EditStatus;
use VIPWorkflow\Modules\Shared\PHP\TaxonomyUtilities;
use WP_Error;
use WP_Query;
Expand All @@ -35,9 +35,9 @@ public function __construct() {
$this->module_url = $this->get_module_url( __FILE__ );
// Register the module with VIP Workflow
$args = [
'module_url' => $this->module_url,
'slug' => 'custom-status',
'configure_page_cb' => 'print_configure_view',
'module_url' => $this->module_url,
'slug' => 'custom-status',
'configure_page_cb' => 'print_configure_view',
];
$this->module = VIP_Workflow::instance()->register_module( 'custom_status', $args );
}
Expand Down Expand Up @@ -88,7 +88,7 @@ public function init() {
add_filter( 'wp_link_pages_link', [ $this, 'modify_preview_link_pagination_url' ], 10, 2 );

// REST endpoints
EditStatus::init();
CustomStatusEndpoint::init();

add_filter( 'user_has_cap', [ $this, 'remove_or_add_publish_capability_for_user' ], 10, 3 );
}
Expand Down Expand Up @@ -134,9 +134,10 @@ public function install() {
[
'term' => __( 'Pending Review' ),
'args' => [
'slug' => 'pending',
'description' => __( 'Post needs to be reviewed by an editor.', 'vip-workflow' ),
'position' => 5,
'slug' => 'pending',
'description' => __( 'Post needs to be reviewed by an editor.', 'vip-workflow' ),
'position' => 5,
'is_review_required' => true,
],
],
];
Expand Down Expand Up @@ -227,7 +228,7 @@ public function disable_custom_statuses_for_post_type( $post_type = null ) {
}

public function add_admin_menu() {
$menu_title = __( 'VIP Workflow', 'vip-workflow' );
$menu_title = __( 'VIP Workflow', 'vip-workflow' );

add_menu_page( $menu_title, $menu_title, 'manage_options', self::SETTINGS_SLUG, [ $this, 'render_settings_view' ] );
}
Expand All @@ -248,8 +249,8 @@ public function action_admin_enqueue_scripts() {

wp_localize_script( 'vip-workflow-custom-status-configure', 'VW_CUSTOM_STATUS_CONFIGURE', [
'custom_statuses' => $this->get_custom_statuses(),
'url_edit_status' => EditStatus::get_crud_url(),
'url_reorder_status' => EditStatus::get_reorder_url(),
'url_edit_status' => CustomStatusEndpoint::get_crud_url(),
'url_reorder_status' => CustomStatusEndpoint::get_reorder_url(),
] );
}

Expand Down Expand Up @@ -456,10 +457,12 @@ public function remove_or_add_publish_capability_for_user( $allcaps, $cap, $args
* The arguments decide how the term is handled based on the $args parameter.
* The following is a list of the available overrides and the defaults.
*
* 'slug'. Expected to be a string. There is no default.
*
* 'description'. There is no default. If exists, will be added to the database
* along with the term. Expected to be a string.
*
* 'slug'. Expected to be a string. There is no default.
* 'is_review_required'. Expected to be a boolean. Default is false.
*
* @param int|string $term The status to add or update
* @param array|string $args Change the values of the inserted term
Expand Down Expand Up @@ -538,11 +541,13 @@ public function update_custom_status( $status_id, $args = [] ) {
}
}
// We're encoding metadata that isn't supported by default in the term's description field
$args_to_encode = [];
$args_to_encode['description'] = ( isset( $args['description'] ) ) ? $args['description'] : $old_status->description;
$args_to_encode['position'] = ( isset( $args['position'] ) ) ? $args['position'] : $old_status->position;
$encoded_description = TaxonomyUtilities::get_encoded_description( $args_to_encode );
$args['description'] = $encoded_description;
$args_to_encode = [];
$args_to_encode['description'] = $args['description'] ?? $old_status->description;
$args_to_encode['position'] = $args['position'] ?? $old_status->position;
$args_to_encode['is_review_required'] = $args['is_review_required'] ?? $old_status->is_review_required ?? false;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this double null coalescing operator is pretty nifty.


$encoded_description = TaxonomyUtilities::get_encoded_description( $args_to_encode );
$args['description'] = $encoded_description;

$updated_status = wp_update_term( $status_id, self::TAXONOMY_KEY, $args );

Expand Down Expand Up @@ -614,7 +619,7 @@ public function delete_custom_status( $status_id, $args = [] ) {
foreach ( $custom_statuses as $status ) {
$this->update_custom_status( $status->term_id, [ 'position' => $current_postition ] );

$current_postition++;
++$current_postition;
}

return $result;
Expand Down Expand Up @@ -877,13 +882,6 @@ public function is_post_using_custom_status( $post_id ) {
return in_array( $post->post_type, $custom_post_types ) && in_array( $post->post_status, $status_slugs );
}

/**
* Register REST API endpoints for custom statuses
*/
public function register_rest_endpoints() {
EditStatus::init();
}

// Hacks for custom statuses to work with core

// phpcs:disable:WordPress.Security.NonceVerification.Missing -- Disabling nonce verification but we should renable it.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
import apiFetch from '@wordpress/api-fetch';
import { Button, Modal, TextControl, TextareaControl, Tooltip } from '@wordpress/components';
import {
Button,
Modal,
TextControl,
TextareaControl,
Tooltip,
ToggleControl,
__experimentalDivider as Divider,
__experimentalHStack as HStack,
} from '@wordpress/components';
import { useState } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';

Expand All @@ -9,6 +18,9 @@ export default function CreateEditCustomStatusModal( { customStatus, onCancel, o
const [ error, setError ] = useState( null );
const [ name, setName ] = useState( customStatus?.name || '' );
const [ description, setDescription ] = useState( customStatus?.description || '' );
const [ isReviewRequired, setIsReviewRequired ] = useState(
customStatus?.is_review_required || false
);
const [ isRequesting, setIsRequesting ] = useState( false );

let titleText;
Expand All @@ -22,10 +34,12 @@ export default function CreateEditCustomStatusModal( { customStatus, onCancel, o
const data = {
name,
description,
is_review_required: isReviewRequired,
};

try {
setIsRequesting( true );

const result = await apiFetch( {
url:
VW_CUSTOM_STATUS_CONFIGURE.url_edit_status + ( customStatus ? customStatus.term_id : '' ),
Expand Down Expand Up @@ -55,31 +69,42 @@ export default function CreateEditCustomStatusModal( { customStatus, onCancel, o
>
{ error && <ErrorNotice errorMessage={ error } setError={ setError } /> }
<TextControl
help={ __( 'The name is used to identify the custom status.', 'vip-workflow' ) }
label={ __( 'Name', 'vip-workflow' ) }
help={ __( 'The name is used to identify the custom status.', 'vip-workflow' ) }
onChange={ setName }
value={ name }
/>
<TextareaControl
label={ __( 'Description', 'vip-workflow' ) }
help={ __(
'The description is primarily for administrative use, to give you some context on what the custom status is to be used for.',
'vip-workflow'
) }
label={ __( 'Description', 'vip-workflow' ) }
onChange={ setDescription }
value={ description }
/>
<Tooltip
text={
customStatus
? __( 'Update the custom status', 'vip-workflow' )
: __( 'Save the new custom status', 'vip-workflow' )
}
>
<Button variant="primary" onClick={ handleSave } disabled={ isRequesting }>
{ customStatus ? __( 'Update', 'vip-workflow' ) : __( 'Save', 'vip-workflow' ) }
</Button>
</Tooltip>
<Divider margin="1rem" />

<ToggleControl
label={ __( 'This status requires a review', 'vip-workflow' ) }
help={ __( 'Require a review from an editor to move to the next status.', 'vip-workflow' ) }
checked={ isReviewRequired }
onChange={ value => setIsReviewRequired( value ) }
/>

<HStack justify="right">
<Tooltip
text={
customStatus
? __( 'Update the custom status', 'vip-workflow' )
: __( 'Save the new custom status', 'vip-workflow' )
}
>
<Button variant="primary" onClick={ handleSave } disabled={ isRequesting }>
{ customStatus ? __( 'Update', 'vip-workflow' ) : __( 'Save', 'vip-workflow' ) }
</Button>
</Tooltip>
</HStack>
</Modal>
);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
/**
* class EditStatus
* REST endpoint for updating a custom status
* class CustomStatusEndpoint
* REST endpoint for managing custom statuses
*/

namespace VIPWorkflow\Modules\CustomStatus\REST;
Expand All @@ -14,7 +14,7 @@

defined( 'ABSPATH' ) || exit;

class EditStatus {
class CustomStatusEndpoint {
/**
* Initialize the class
*/
Expand All @@ -32,7 +32,7 @@ public static function register_routes() {
'permission_callback' => [ __CLASS__, 'permission_callback' ],
'args' => [
// Required parameters
'name' => [
'name' => [
'required' => true,
'validate_callback' => function ( $param ) {
return ! empty( trim( $param ) );
Expand All @@ -43,12 +43,18 @@ public static function register_routes() {
],

// Optional parameters
'description' => [
'description' => [
'default' => '',
'sanitize_callback' => function ( $param ) {
return stripslashes( wp_filter_nohtml_kses( trim( $param ) ) );
},
],
'is_review_required' => [
'default' => false,
'sanitize_callback' => function ( $param ) {
return boolval( $param );
},
],
],
] );

Expand All @@ -58,7 +64,7 @@ public static function register_routes() {
'permission_callback' => [ __CLASS__, 'permission_callback' ],
'args' => [
// Required parameters
'name' => [
'name' => [
'required' => true,
'validate_callback' => function ( $param ) {
return ! empty( trim( $param ) );
Expand All @@ -67,7 +73,7 @@ public static function register_routes() {
return trim( $param );
},
],
'id' => [
'id' => [
'required' => true,
'validate_callback' => function ( $param ) {
$term_id = absint( $param );
Expand All @@ -80,12 +86,18 @@ public static function register_routes() {
],

// Optional parameters
'description' => [
'description' => [
'default' => '',
'sanitize_callback' => function ( $param ) {
return stripslashes( wp_filter_nohtml_kses( trim( $param ) ) );
},
],
'is_review_required' => [
'default' => false,
'sanitize_callback' => function ( $param ) {
return boolval( $param );
},
],
],
] );

Expand Down Expand Up @@ -158,9 +170,10 @@ public static function permission_callback() {
* @param WP_REST_Request $request
*/
public static function handle_create_status( WP_REST_Request $request ) {
$status_name = sanitize_text_field( $request->get_param( 'name' ) );
$status_slug = sanitize_title( $request->get_param( 'name' ) );
$status_description = $request->get_param( 'description' );
$status_name = sanitize_text_field( $request->get_param( 'name' ) );
$status_slug = sanitize_title( $request->get_param( 'name' ) );
$status_description = $request->get_param( 'description' );
$status_is_review_required = $request->get_param( 'is_review_required' );

$custom_status_module = VIP_Workflow::instance()->custom_status;

Expand Down Expand Up @@ -188,8 +201,9 @@ public static function handle_create_status( WP_REST_Request $request ) {

// get status_slug & status_description
$args = [
'description' => $status_description,
'slug' => $status_slug,
'description' => $status_description,
'slug' => $status_slug,
'is_review_required' => $status_is_review_required,
];

$add_status_result = $custom_status_module->add_custom_status( $status_name, $args );
Expand All @@ -204,10 +218,11 @@ public static function handle_create_status( WP_REST_Request $request ) {
* @param WP_REST_Request $request
*/
public static function handle_update_status( WP_REST_Request $request ) {
$term_id = $request->get_param( 'id' );
$status_name = sanitize_text_field( $request->get_param( 'name' ) );
$status_slug = sanitize_title( $request->get_param( 'name' ) );
$status_description = $request->get_param( 'description' );
$term_id = $request->get_param( 'id' );
$status_name = sanitize_text_field( $request->get_param( 'name' ) );
$status_slug = sanitize_title( $request->get_param( 'name' ) );
$status_description = $request->get_param( 'description' );
$status_is_review_required = $request->get_param( 'is_review_required' );

$custom_status_module = VIP_Workflow::instance()->custom_status;

Expand Down Expand Up @@ -245,9 +260,10 @@ public static function handle_update_status( WP_REST_Request $request ) {

// get status_name & status_description
$args = [
'name' => $status_name,
'description' => $status_description,
'slug' => $status_slug,
'name' => $status_name,
'description' => $status_description,
'slug' => $status_slug,
'is_review_required' => $status_is_review_required,
];

// ToDo: Ensure that we don't do an update when the name and description are the same as the current status
Expand Down
6 changes: 2 additions & 4 deletions modules/shared/php/install-utilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@

namespace VIPWorkflow\Modules\Shared\PHP;

use stdClass;
use VIPWorkflow\VIP_Workflow;

class InstallUtilities {
/**
* Given a module name, run a callback function if the module is being run for the first time
Expand All @@ -19,8 +16,9 @@ class InstallUtilities {
*/
public static function install_if_first_run( $module_slug, $callback_function ) {
$module_options = OptionsUtilities::get_module_options( $module_slug );
$is_loaded_once = $module_options->loaded_once ?? false;

if ( ! $module_options->loaded_once ) {
if ( ! $is_loaded_once ) {
call_user_func( $callback_function );

OptionsUtilities::update_module_option_key( $module_slug, 'loaded_once', true );
Expand Down
3 changes: 3 additions & 0 deletions tests/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,8 @@ function _manually_load_plugin() {

tests_add_filter( 'muplugins_loaded', '_manually_load_plugin' );

// Add TestCase classes.
require_once __DIR__ . '/rest-test-case.php';

// Start up the WP testing environment.
require "{$_tests_dir}/includes/bootstrap.php";
Loading