|null|false */ private static $context = false; public static function init(): void { add_action( 'restrict_manage_posts', array( self::class, 'select' ), 20 ); add_action( 'admin_notices', array( self::class, 'term_selector' ) ); add_action( 'load-edit-tags.php', array( self::class, 'term_screen' ) ); add_filter( 'get_terms_args', array( self::class, 'term_args' ), 20, 2 ); add_action( 'pre_get_posts', array( self::class, 'prepare' ), 5 ); add_action( 'admin_enqueue_scripts', array( self::class, 'assets' ) ); add_action( 'init', static function () { foreach ( get_taxonomies( array( 'show_ui' => true ) ) as $taxonomy ) { add_filter( 'manage_edit-' . $taxonomy . '_columns', array( self::class, 'term_columns' ) ); add_filter( 'manage_' . $taxonomy . '_custom_column', static function ( $content, $column, $id ) { if ( 'threepo' !== $column ) { return $content; } ob_start(); self::cell( $column, (int) $id ); return (string) ob_get_clean(); }, 10, 3 ); } foreach ( get_post_types( array( 'show_ui' => true ) ) as $type ) { add_filter( 'manage_' . $type . '_posts_columns', array( self::class, 'columns' ) ); add_action( 'manage_' . $type . '_posts_custom_column', array( self::class, 'cell' ), 10, 2 ); } }, 40 ); } /** * @return array|null */ public static function context(): ?array { if ( false !== self::$context ) { return self::$context; } // Read-only list selector. Mutation CSRF protection belongs to the REST API. // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only context selection; capability checked below, mutations use REST nonces. $id = isset( $_GET['threepo_context'] ) ? absint( $_GET['threepo_context'] ) : 0; $c = $id ? Store::get( $id ) : null; self::$context = $c && Store::allowed( $c ) ? $c : null; return self::$context; } /** * Orders the current user may use for one list. * * @return list> */ private static function available( string $kind, string $type ): array { return array_values( array_filter( Store::contexts(), static function ( $row ) use ( $kind, $type ) { return $kind === $row['kind'] && $type === $row['object_type'] && 'importing' !== $row['scope']; } ) ); } /** * @param array $columns Existing columns. * @return array */ public static function term_columns( array $columns ): array { $c = self::context(); return $c && 'term' === $c['kind'] ? array( 'threepo' => __( 'Order', '3task-post-order' ) ) + $columns : $columns; } /** * @param array $args Query arguments. * @param list $taxonomies Taxonomies. * @return array */ public static function term_args( array $args, array $taxonomies ): array { if ( ! is_admin() ) { return $args; } $screen = get_current_screen(); $c = self::context(); if ( $screen && 'edit-tags' === $screen->base && $c && 'term' === $c['kind'] && array( $c['object_type'] ) === $taxonomies && ( isset( $args['page'] ) || 'count' === ( $args['fields'] ?? '' ) ) ) { $args['threepo_context'] = $c['id']; $args['parent'] = $c['parent_id']; $args['hierarchical'] = false; $args['child_of'] = 0; } return $args; } public static function term_screen(): void { $c = self::context(); // Read-only display mode: core otherwise hides a sibling list whose parent is not zero. // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- A read-only list redirect; the context is capability checked. if ( $c && 'term' === $c['kind'] && ! isset( $_GET['orderby'] ) ) { wp_safe_redirect( add_query_arg( 'orderby', 'threepo' ) ); exit; } } /** * Order switcher on a term list, shown only when this taxonomy has an order. */ public static function term_selector(): void { $screen = get_current_screen(); if ( ! $screen || 'edit-tags' !== $screen->base || ! $screen->taxonomy ) { return; } $orders = self::available( 'term', $screen->taxonomy ); if ( ! $orders ) { return; } $current = self::context(); echo '
' . esc_html__( 'Term order:', '3task-post-order' ) . ' '; $default_url = add_query_arg( 'taxonomy', $screen->taxonomy, admin_url( 'edit-tags.php' ) ); echo '' . esc_html__( 'Default order', '3task-post-order' ) . ' '; foreach ( $orders as $row ) { $url = add_query_arg( array( 'taxonomy' => $screen->taxonomy, 'orderby' => 'threepo', 'threepo_context' => $row['id'], ), admin_url( 'edit-tags.php' ) ); $on = $current && $current['id'] === $row['id']; echo '' . esc_html( $row['label'] ) . ' '; } echo '' . esc_html__( 'Manage orders', '3task-post-order' ) . '
'; } /** * Order selector above a post list, shown only when this type has an order. * * @param mixed $type Post type of the list (WordPress passes a string). */ public static function select( $type = 'post' ): void { if ( ! is_string( $type ) || 'attachment' === $type ) { return; } $orders = self::available( 'post', $type ); if ( ! $orders ) { return; } $c = self::context(); echo ''; echo ''; } /** * @param \WP_Query $q WordPress boundary value. */ public static function prepare( $q ): void { if ( ! is_admin() || ! $q->is_main_query() ) { return; } $c = self::context(); if ( ! $c || 'post' !== $c['kind'] ) { return; } $type = ( $q->get( 'post_type' ) ? $q->get( 'post_type' ) : 'post' ); if ( $type !== $c['object_type'] ) { return; } $q->set( 'threepo_context', $c['id'] ); $q->set( 'threepo_native', true ); } /** * @param array $columns Existing columns. * @return array */ public static function columns( array $columns ): array { $c = self::context(); if ( $c && 'post' === $c['kind'] ) { $columns = array( 'threepo' => __( 'Order', '3task-post-order' ) ) + $columns; } return $columns; } public static function cell( string $column, int $id ): void { if ( 'threepo' !== $column ) { return; } $c = self::context(); if ( ! $c || ! Order::member( $c, $id ) || ! Order::object_allowed( $c, $id ) ) { return; } $url = add_query_arg( array( 'page' => 'threepo', 'context' => $c['id'], 'object' => $id, ), admin_url( 'tools.php' ) ); echo ''; echo '' . esc_html__( 'Move to…', '3task-post-order' ) . ''; } public static function assets( string $hook ): void { if ( 'edit-tags.php' === $hook ) { wp_enqueue_style( 'threepo-native', plugins_url( 'assets/native.css', THREEPO_FILE ), array(), Admin::ver( 'assets/native.css' ) ); } if ( ! in_array( $hook, array( 'edit.php', 'edit-tags.php' ), true ) || ! self::context() ) { return; } wp_enqueue_script( 'threepo-native', plugins_url( 'assets/native.js', THREEPO_FILE ), array( 'wp-api-fetch', 'wp-i18n' ), Admin::ver( 'assets/native.js' ), true ); wp_set_script_translations( 'threepo-native', '3task-post-order' ); wp_enqueue_style( 'threepo-native', plugins_url( 'assets/native.css', THREEPO_FILE ), array(), Admin::ver( 'assets/native.css' ) ); } }