self::CATEGORY,
'hide_empty' => false,
'number' => 1,
)
);
if ( ! is_wp_error( $existing ) && ! empty( $existing ) ) {
update_option( 'forwp_todo_taxonomies_seeded', true, false );
return;
}
self::seed_defaults();
update_option( 'forwp_todo_taxonomies_seeded', true, false );
}
/**
* Save workflow phase from the term add/edit form (defaults to open).
*
* @param int $term_id Term ID.
* @param int $tt_id Term taxonomy ID.
* @return void
*/
public static function save_workflow_phase_from_request( int $term_id, int $tt_id ): void {
unset( $tt_id );
if ( ! current_user_can( 'manage_categories' ) ) {
return;
}
// phpcs:disable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Core taxonomy admin; phase sanitized via sanitize_phase().
if ( isset( $_POST['forwp_todo_workflow_phase'] ) ) {
$raw_phase = wp_unslash( $_POST['forwp_todo_workflow_phase'] );
$phase = self::sanitize_phase( is_string( $raw_phase ) ? $raw_phase : '' );
update_term_meta( $term_id, self::WORKFLOW_PHASE_META, $phase );
// phpcs:enable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
return;
}
if ( ! get_term_meta( $term_id, self::WORKFLOW_PHASE_META, true ) ) {
update_term_meta( $term_id, self::WORKFLOW_PHASE_META, self::PHASE_OPEN );
}
}
/**
* @return void
*/
public static function render_workflow_phase_field(): void {
?>
term_id, self::WORKFLOW_PHASE_META, true ) );
?>
|
|
|
$columns Column headers.
* @return array
*/
public static function workflow_columns( array $columns ): array {
$columns['forwp_todo_phase'] = __( 'Note phase', '4wp-todo' );
return $columns;
}
/**
* @param string $content Column content.
* @param string $column_name Column key.
* @param int $term_id Term ID.
* @return string
*/
public static function workflow_column_content( string $content, string $column_name, int $term_id ): string {
unset( $content );
if ( 'forwp_todo_phase' !== $column_name ) {
return '';
}
$phase = self::sanitize_phase( get_term_meta( $term_id, self::WORKFLOW_PHASE_META, true ) );
return self::PHASE_CLOSED === $phase
? esc_html__( 'When closed', '4wp-todo' )
: esc_html__( 'While open', '4wp-todo' );
}
/**
* @return void
*/
public static function register_taxonomies(): void {
register_taxonomy(
self::CATEGORY,
Task_Post_Type::POST_TYPE,
array(
'labels' => array(
'name' => __( 'Task categories', '4wp-todo' ),
'singular_name' => __( 'Task category', '4wp-todo' ),
'menu_name' => __( 'Categories', '4wp-todo' ),
'all_items' => __( 'All categories', '4wp-todo' ),
'edit_item' => __( 'Edit category', '4wp-todo' ),
'view_item' => __( 'View category', '4wp-todo' ),
'update_item' => __( 'Update category', '4wp-todo' ),
'add_new_item' => __( 'Add new category', '4wp-todo' ),
'new_item_name' => __( 'New category name', '4wp-todo' ),
'search_items' => __( 'Search categories', '4wp-todo' ),
),
'hierarchical' => true,
'public' => false,
'show_ui' => true,
'show_in_menu' => Menu::PAGE_SLUG,
'show_admin_column' => false,
'show_in_rest' => true,
'rewrite' => false,
)
);
register_taxonomy(
self::STATUS,
Task_Post_Type::POST_TYPE,
array(
'labels' => array(
'name' => __( 'Task statuses', '4wp-todo' ),
'singular_name' => __( 'Task status', '4wp-todo' ),
'menu_name' => __( 'Statuses', '4wp-todo' ),
'all_items' => __( 'All statuses', '4wp-todo' ),
'edit_item' => __( 'Edit status', '4wp-todo' ),
'view_item' => __( 'View status', '4wp-todo' ),
'update_item' => __( 'Update status', '4wp-todo' ),
'add_new_item' => __( 'Add new status', '4wp-todo' ),
'new_item_name' => __( 'New status name', '4wp-todo' ),
'search_items' => __( 'Search statuses', '4wp-todo' ),
),
'hierarchical' => false,
'public' => false,
'show_ui' => true,
'show_in_menu' => Menu::PAGE_SLUG,
'show_admin_column' => false,
'show_in_rest' => true,
'rewrite' => false,
)
);
register_taxonomy(
self::WORKFLOW,
Task_Post_Type::POST_TYPE,
array(
'labels' => array(
'name' => __( 'Task workflows', '4wp-todo' ),
'singular_name' => __( 'Task workflow', '4wp-todo' ),
'menu_name' => __( 'Workflows', '4wp-todo' ),
'all_items' => __( 'All workflows', '4wp-todo' ),
'edit_item' => __( 'Edit workflow', '4wp-todo' ),
'view_item' => __( 'View workflow', '4wp-todo' ),
'update_item' => __( 'Update workflow', '4wp-todo' ),
'add_new_item' => __( 'Add new workflow', '4wp-todo' ),
'new_item_name' => __( 'New workflow name', '4wp-todo' ),
'search_items' => __( 'Search workflows', '4wp-todo' ),
),
'hierarchical' => false,
'public' => false,
'show_ui' => true,
'show_in_menu' => Menu::PAGE_SLUG,
'show_admin_column' => false,
'show_in_rest' => true,
'rewrite' => false,
)
);
}
/**
* @return void
*/
public static function register_term_meta(): void {
register_term_meta(
self::WORKFLOW,
self::WORKFLOW_PHASE_META,
array(
'type' => 'string',
'single' => true,
'default' => self::PHASE_OPEN,
'show_in_rest' => true,
'sanitize_callback' => array( __CLASS__, 'sanitize_phase' ),
)
);
}
/**
* @param mixed $phase Raw phase value.
* @return string
*/
public static function sanitize_phase( $phase ): string {
$phase = sanitize_key( (string) $phase );
return self::PHASE_CLOSED === $phase ? self::PHASE_CLOSED : self::PHASE_OPEN;
}
/**
* Seed default terms once (activation or first load).
*
* @return void
*/
public static function seed_defaults(): void {
$defaults = array(
'category' => array(
'qa' => __( 'QA', '4wp-todo' ),
'dev' => __( 'Development', '4wp-todo' ),
'seo' => __( 'SEO', '4wp-todo' ),
'content' => __( 'Content', '4wp-todo' ),
'client' => __( 'For client', '4wp-todo' ),
),
'status' => array(
'open' => __( 'Open', '4wp-todo' ),
'closed' => __( 'Closed', '4wp-todo' ),
),
'workflow' => array(
'in_work' => array(
'label' => __( 'Take in work', '4wp-todo' ),
'phase' => self::PHASE_OPEN,
),
'in_progress' => array(
'label' => __( 'In progress', '4wp-todo' ),
'phase' => self::PHASE_OPEN,
),
'on_qa' => array(
'label' => __( 'On QA', '4wp-todo' ),
'phase' => self::PHASE_OPEN,
),
'passed_reported' => array(
'label' => __( 'Passed and reported', '4wp-todo' ),
'phase' => self::PHASE_CLOSED,
),
'client_approved' => array(
'label' => __( 'Client approved', '4wp-todo' ),
'phase' => self::PHASE_CLOSED,
),
),
);
/**
* Filter default taxonomy terms seeded on install / first load.
*
* @param array $defaults category, status, workflow arrays.
*/
$defaults = apply_filters( 'forwp_todo_default_taxonomy_terms', $defaults );
if ( ! empty( $defaults['category'] ) && is_array( $defaults['category'] ) ) {
self::seed_terms( self::CATEGORY, $defaults['category'] );
}
if ( ! empty( $defaults['status'] ) && is_array( $defaults['status'] ) ) {
self::seed_terms( self::STATUS, $defaults['status'] );
}
if ( ! empty( $defaults['workflow'] ) && is_array( $defaults['workflow'] ) ) {
self::seed_workflow_terms( $defaults['workflow'] );
}
}
/**
* @param string $taxonomy Taxonomy slug.
* @param array $terms slug => label.
* @return void
*/
private static function seed_terms( string $taxonomy, array $terms ): void {
foreach ( $terms as $slug => $label ) {
if ( term_exists( $slug, $taxonomy ) ) {
continue;
}
wp_insert_term(
$label,
$taxonomy,
array(
'slug' => sanitize_key( $slug ),
)
);
}
}
/**
* @param array $terms slug => data.
* @return void
*/
private static function seed_workflow_terms( array $terms ): void {
foreach ( $terms as $slug => $data ) {
if ( ! is_array( $data ) ) {
continue;
}
$label = isset( $data['label'] ) ? (string) $data['label'] : '';
$phase = isset( $data['phase'] ) ? self::sanitize_phase( $data['phase'] ) : self::PHASE_OPEN;
if ( '' === $label ) {
continue;
}
if ( term_exists( $slug, self::WORKFLOW ) ) {
continue;
}
$result = wp_insert_term(
$label,
self::WORKFLOW,
array(
'slug' => sanitize_key( (string) $slug ),
)
);
if ( is_wp_error( $result ) || empty( $result['term_id'] ) ) {
continue;
}
update_term_meta( (int) $result['term_id'], self::WORKFLOW_PHASE_META, $phase );
}
}
/**
* @param string $taxonomy Taxonomy slug.
* @return array slug => label
*/
public static function choices( string $taxonomy ): array {
$terms = get_terms(
array(
'taxonomy' => $taxonomy,
'hide_empty' => false,
)
);
if ( is_wp_error( $terms ) || ! is_array( $terms ) ) {
return array();
}
$choices = array();
foreach ( $terms as $term ) {
if ( ! $term instanceof \WP_Term ) {
continue;
}
$choices[ $term->slug ] = $term->name;
}
return $choices;
}
/**
* @param string $taxonomy Taxonomy slug.
* @param string $slug Term slug.
* @return string Sanitized slug or empty.
*/
public static function sanitize_slug( string $taxonomy, string $slug ): string {
$slug = sanitize_key( $slug );
if ( '' === $slug ) {
return '';
}
$term = get_term_by( 'slug', $slug, $taxonomy );
return ( $term instanceof \WP_Term ) ? $term->slug : '';
}
/**
* @param string $taxonomy Taxonomy slug.
* @param string $slug Term slug.
* @return string
*/
public static function label( string $taxonomy, string $slug ): string {
$term = get_term_by( 'slug', sanitize_key( $slug ), $taxonomy );
return ( $term instanceof \WP_Term ) ? $term->name : '';
}
/**
* @param string $phase open|closed
* @return list
*/
public static function workflow_slugs_for_phase( string $phase ): array {
$phase = self::sanitize_phase( $phase );
$terms = get_terms(
array(
'taxonomy' => self::WORKFLOW,
'hide_empty' => false,
)
);
if ( is_wp_error( $terms ) || ! is_array( $terms ) ) {
return array();
}
$slugs = array();
foreach ( $terms as $term ) {
if ( ! $term instanceof \WP_Term ) {
continue;
}
$term_phase = self::sanitize_phase( get_term_meta( $term->term_id, self::WORKFLOW_PHASE_META, true ) );
if ( $term_phase === $phase ) {
$slugs[] = $term->slug;
}
}
return $slugs;
}
/**
* @param string $slug Term slug.
* @return string open|closed
*/
public static function workflow_phase_for_slug( string $slug ): string {
$term = get_term_by( 'slug', sanitize_key( $slug ), self::WORKFLOW );
if ( ! $term instanceof \WP_Term ) {
return self::PHASE_OPEN;
}
return self::sanitize_phase( get_term_meta( $term->term_id, self::WORKFLOW_PHASE_META, true ) );
}
/**
* @param string $taxonomy Taxonomy slug.
* @return list
*/
public static function registry_terms( string $taxonomy ): array {
$terms = get_terms(
array(
'taxonomy' => $taxonomy,
'hide_empty' => false,
)
);
if ( is_wp_error( $terms ) || ! is_array( $terms ) ) {
return array();
}
$items = array();
foreach ( $terms as $term ) {
if ( ! $term instanceof \WP_Term ) {
continue;
}
$items[] = array(
'slug' => $term->slug,
'label' => $term->name,
'count' => (int) $term->count,
);
}
return $items;
}
}