Initial public release of BreznFlow, an n8n workflow renderer for WordPress. Fully PHPCS-compliant (WordPress Coding Standards), security-hardened, and ready for WordPress.org plugin review. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
204 lines
5.5 KiB
PHP
204 lines
5.5 KiB
PHP
<?php
|
|
/**
|
|
* Workflow list table for the admin dashboard.
|
|
*
|
|
* @package BreznFlow
|
|
* @since 1.0.0
|
|
*/
|
|
|
|
namespace BreznFlow\Admin;
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
if ( ! class_exists( 'WP_List_Table' ) ) {
|
|
require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
|
|
}
|
|
|
|
/**
|
|
* Extends WP_List_Table to display workflows in the admin.
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
class WorkflowListTable extends \WP_List_Table {
|
|
/**
|
|
* Constructor — sets table configuration.
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
public function __construct() {
|
|
parent::__construct(
|
|
array(
|
|
'singular' => 'workflow',
|
|
'plural' => 'workflows',
|
|
'ajax' => false,
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns the list of table columns.
|
|
*
|
|
* @return array<string, string>
|
|
*/
|
|
public function get_columns(): array {
|
|
return array(
|
|
'cb' => '<input type="checkbox" />',
|
|
'title' => __( 'Title', 'breznflow' ),
|
|
'nodes' => __( 'Nodes', 'breznflow' ),
|
|
'ai' => __( 'AI', 'breznflow' ),
|
|
'mode' => __( 'Mode', 'breznflow' ),
|
|
'views' => __( 'Views', 'breznflow' ),
|
|
'shortcode' => __( 'Shortcode', 'breznflow' ),
|
|
'date' => __( 'Date', 'breznflow' ),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns sortable columns configuration.
|
|
*
|
|
* @return array<string, array<int, mixed>>
|
|
*/
|
|
protected function get_sortable_columns(): array {
|
|
return array(
|
|
'title' => array( 'title', false ),
|
|
'nodes' => array( 'nodes', false ),
|
|
'views' => array( 'views', false ),
|
|
'date' => array( 'date', false ),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns the bulk action choices.
|
|
*
|
|
* @return array<string, string>
|
|
*/
|
|
protected function get_bulk_actions(): array {
|
|
return array(
|
|
'delete' => __( 'Delete', 'breznflow' ),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Queries workflows and sets up pagination.
|
|
*
|
|
* @since 1.0.0
|
|
* @return void
|
|
*/
|
|
public function prepare_items(): void {
|
|
$per_page = 20;
|
|
$current_page = $this->get_pagenum();
|
|
|
|
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
$orderby = isset( $_GET['orderby'] ) ? sanitize_key( $_GET['orderby'] ) : 'date';
|
|
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
$order_raw = isset( $_GET['order'] ) ? strtolower( sanitize_text_field( wp_unslash( $_GET['order'] ) ) ) : '';
|
|
$order = 'asc' === $order_raw ? 'ASC' : 'DESC';
|
|
|
|
$args = array(
|
|
'post_type' => 'breznflow_workflow',
|
|
'post_status' => array( 'publish', 'draft' ),
|
|
'posts_per_page' => $per_page,
|
|
'paged' => $current_page,
|
|
'orderby' => $orderby,
|
|
'order' => $order,
|
|
);
|
|
|
|
$query = new \WP_Query( $args );
|
|
$this->set_pagination_args(
|
|
array(
|
|
'total_items' => $query->found_posts,
|
|
'per_page' => $per_page,
|
|
)
|
|
);
|
|
$this->items = $query->posts;
|
|
|
|
$this->_column_headers = array(
|
|
$this->get_columns(),
|
|
array(),
|
|
$this->get_sortable_columns(),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Renders a non-special column value for a row.
|
|
*
|
|
* @param \WP_Post $item The current post object.
|
|
* @param string $column_name The current column name.
|
|
* @return string
|
|
*/
|
|
protected function column_default( $item, $column_name ): string {
|
|
switch ( $column_name ) {
|
|
case 'nodes':
|
|
return (string) (int) get_post_meta( $item->ID, '_breznflow_node_count', true );
|
|
case 'ai':
|
|
$has_ai = (int) get_post_meta( $item->ID, '_breznflow_has_ai_nodes', true );
|
|
return $has_ai ? '<span class="breznflow-badge-ai" title="' . esc_attr__( 'Contains AI nodes', 'breznflow' ) . '">AI</span>' : '—';
|
|
case 'mode':
|
|
$mode = get_post_meta( $item->ID, '_breznflow_default_mode', true );
|
|
return esc_html( $mode ? $mode : 'visual' );
|
|
case 'views':
|
|
return (string) (int) get_post_meta( $item->ID, '_breznflow_view_count', true );
|
|
case 'shortcode':
|
|
$sc = '[breznflow id="' . $item->ID . '"]';
|
|
return '<code>' . esc_html( $sc ) . '</code> '
|
|
. '<button class="button button-small breznflow-copy-sc" data-sc="' . esc_attr( $sc ) . '">'
|
|
. esc_html__( 'Copy', 'breznflow' )
|
|
. '</button>';
|
|
case 'date':
|
|
return esc_html( get_the_date( 'Y-m-d', $item ) );
|
|
default:
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Renders the title column with edit/delete row actions.
|
|
*
|
|
* @param \WP_Post $item The current post object.
|
|
* @return string
|
|
*/
|
|
protected function column_title( $item ): string {
|
|
$edit_url = add_query_arg(
|
|
array(
|
|
'page' => 'breznflow-add',
|
|
'step' => '2',
|
|
'post_id' => $item->ID,
|
|
),
|
|
admin_url( 'admin.php' )
|
|
);
|
|
|
|
$delete_url = wp_nonce_url(
|
|
add_query_arg(
|
|
array(
|
|
'action' => 'delete',
|
|
'post' => $item->ID,
|
|
'page' => 'breznflow',
|
|
),
|
|
admin_url( 'admin.php' )
|
|
),
|
|
'breznflow_delete_' . $item->ID
|
|
);
|
|
|
|
$title = esc_html( $item->post_title );
|
|
$status = 'publish' === $item->post_status ? '' : ' <span class="post-state">(' . esc_html__( 'Draft', 'breznflow' ) . ')</span>';
|
|
$actions = array(
|
|
'edit' => '<a href="' . esc_url( $edit_url ) . '">' . esc_html__( 'Edit', 'breznflow' ) . '</a>',
|
|
'delete' => '<a href="' . esc_url( $delete_url ) . '" class="submitdelete">' . esc_html__( 'Delete', 'breznflow' ) . '</a>',
|
|
);
|
|
|
|
return '<strong><a href="' . esc_url( $edit_url ) . '">' . $title . '</a>' . $status . '</strong>'
|
|
. $this->row_actions( $actions );
|
|
}
|
|
|
|
/**
|
|
* Renders the checkbox column for bulk actions.
|
|
*
|
|
* @param \WP_Post $item The current post object.
|
|
* @return string
|
|
*/
|
|
protected function column_cb( $item ): string {
|
|
return '<input type="checkbox" name="workflow[]" value="' . esc_attr( (string) $item->ID ) . '" />';
|
|
}
|
|
}
|