From 0d1da4356173e926fdcac42462daa4fcb7617109 Mon Sep 17 00:00:00 2001 From: Daniel Weipert Date: Mon, 21 Dec 2020 16:11:17 +0100 Subject: Initial commit --- src/class-draggable-post-order.php | 175 +++++++++++++++++++++++++++++++++++++ src/index.js | 49 +++++++++++ src/index.scss | 23 +++++ 3 files changed, 247 insertions(+) create mode 100644 src/class-draggable-post-order.php create mode 100644 src/index.js create mode 100644 src/index.scss (limited to 'src') diff --git a/src/class-draggable-post-order.php b/src/class-draggable-post-order.php new file mode 100644 index 0000000..ae9b501 --- /dev/null +++ b/src/class-draggable-post-order.php @@ -0,0 +1,175 @@ + return. + if ( empty( $post_types ) ) { + return; + } + + foreach ( $post_types as $post_type ) { + add_action( "save_post_{$post_type}", [ self::class, 'save_post' ], 10, 2 ); + } + + // add meta box. + add_action( 'add_meta_boxes', [ self::class, 'add_meta_boxes' ] ); + + // add ajax hook. + add_action( 'wp_ajax_update-post-order', [ self::class, 'update_post_order' ] ); + + // load scripts. + add_action( 'admin_enqueue_scripts', [ self::class, 'enqueue_scripts' ] ); + + // sort posts by post order. + add_action( 'pre_get_posts', [ self::class, 'order_posts' ] ); + } + + /** + * Whether the given post type is allowed to be ordered. + * + * @param string $post_type The post type to check against. + * + * @return bool + */ + public static function supports( $post_type = null ) { + $post_type ??= get_current_screen()->post_type ?? ''; + + return post_type_supports( $post_type, 'draggable-post-order' ); + } + + /** + * Callback for "save_post" action. + * + * @param int $post_id The post's ID. + * @param \WP_Post $post The post object. + */ + public static function save_post( $post_id, $post ) { + if ( + ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || + ! check_admin_referer( 'metaBoxDraggablePostOrder', 'metaBoxDraggablePostOrder' ) || + ( ! isset( $_POST['post_ID'] ) || intval( $_POST['post_ID'] ) !== intval( $post_id ) ) || + ! isset( $_POST['draggable-post-order'] ) + ) { + return; + } + + $post_order = sanitize_text_field( wp_unslash( $_POST['draggable-post-order'] ) ); + if ( empty( $post_order ) ) { + $post_order = wp_count_posts( $post->post_type )->publish; + } + + update_post_meta( $post_id, 'draggable-post-order', $post_order ); + } + + /** + * Callback for "add_meta_boxes" action. + */ + public static function add_meta_boxes() { + if ( ! self::supports() ) { + return; + } + + add_meta_box( 'draggable-post-order', __( 'Post Order', 'draggable-post-order' ), [ self::class, 'add_meta_box' ], '', 'side' ); + } + + /** + * Callback for "add_meta_box" function. + * + * @param \WP_Post $post The post object. + */ + public static function add_meta_box( $post ) { + wp_nonce_field( 'metaBoxDraggablePostOrder', 'metaBoxDraggablePostOrder' ); + ?> + $post_id ) { + $order = intval( $order ) + 1; + update_post_meta( $post_id, 'draggable-post-order', ( ( $page - 1 ) * $per_page ) + $order ); + } + } + + /** + * Callback for "admin_enqueue_scripts" action. + */ + public static function enqueue_scripts() { + $current_screen = get_current_screen(); + if ( $current_screen->base !== 'edit' || ! self::supports() ) { + return; + } + + list('dependencies' => $dependencies, 'version' => $version) = require draggable_post_order_path() . '/build/index.asset.php'; + $dependencies[] = 'jquery-ui-sortable'; + wp_enqueue_script( 'draggable-post-order', draggable_post_order_assets_url( 'index.js' ), $dependencies, $version, true ); + wp_enqueue_style( 'draggable-post-order', draggable_post_order_assets_url( 'index.css' ), [], $version ); + } + + /** + * Callback for "pre_get_posts" action. + * + * @param \WP_Query $query The query object. + */ + public static function order_posts( \WP_Query $query ) { + $post_type = $query->get( 'post_type' ); + if ( ! self::supports( $post_type ) ) { + return; + } + + // if no orderby was set previously. + if ( ! $query->get( 'orderby' ) ) { + $meta_sub_query = [ + 'relation' => 'OR', + 'draggable-post-order-clause' => [ + 'key' => 'draggable-post-order', + 'type' => 'NUMERIC', + ], + // get all posts without the meta as well. + 'draggable-post-order-exists-clause' => [ + 'key' => 'draggable-post-order', + 'compare' => 'NOT EXISTS', + ], + ]; + $meta_query = $query->get( 'meta_query' ) ?: []; + $meta_query[] = $meta_sub_query; + + $order = apply_filters( 'draggable_post_order_order', 'ASC', $post_type, $query ); + $orderby = [ + 'draggable-post-order-clause' => $order, + 'draggable-post-order-exists-clause' => $order, + ]; + + $query->set( 'meta_query', $meta_query ); + $query->set( 'orderby', $orderby ); + } + } +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..eecabf6 --- /dev/null +++ b/src/index.js @@ -0,0 +1,49 @@ +/* global jQuery ajaxurl */ + +import './index.scss'; + +( function ( $ ) { + const overlay = $( '
' ).appendTo( 'body' ); + $( '#the-list' ).sortable( { + items: 'tr', + axis: 'y', + cursor: 'move', + + // @see https://stackoverflow.com/a/57611747/6114451 + start( e, ui ) { + const $originals = ui.helper.children(); + ui.placeholder.children().each( function ( index ) { + $( this ).width( $originals.eq( index ).width() ); + $( this ).height( $originals.eq( index ).height() ); + } ); + }, + helper( e, tr ) { + const $helper = tr.clone(); + const $originals = tr.children(); + $helper.children().each( function ( index ) { + $( this ).width( $originals.eq( index ).outerWidth( true ) ); + } ); + return $helper; + }, + + update() { + // show overlay + overlay.addClass( 'post-order-overlay--visible' ); + + // update posts + $.post( + ajaxurl, + { + action: 'update-post-order', + page: $( '#current-page-selector' ).val(), + perPage: $( '#edit_post_per_page' ).val(), + postOrder: $( '#the-list' ).sortable( 'serialize' ), + }, + () => { + // hide overlay after updating + overlay.removeClass( 'post-order-overlay--visible' ); + } + ); + }, + } ); +} )( jQuery ); diff --git a/src/index.scss b/src/index.scss new file mode 100644 index 0000000..124d799 --- /dev/null +++ b/src/index.scss @@ -0,0 +1,23 @@ +.post-order-overlay { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + background: rgba(0, 0, 0, 0.8); + display: none; + + &--visible { + display: block; + } +} + +#the-list { + + tr { + + &.ui-sortable-handle { + cursor: move; + } + } +} -- cgit v1.2.3