web-dev-qa-db-ja.com

管理ページリスト画面でカスタムドラッグドロップページの順序を拡張するのに役立ちます

私は以下のコードを利用しています。これは階層的なページやカスタム投稿タイプを単純なドラッグアンドドロップでページを並べ替える機能で変換します。 (また、このコードでは、物事を単純にするために階層ページに新しい表示フィルタも追加されています)。

現時点では機能しない、私が助けを必要とする問題は、あるページツリーを別のページツリーにドラッグすることや既存のページツリーから移動することができることです。

誰かがこの機能を拡張するのに必要なコード修正を提供してもらえますか?

下記のコードを拡張するのではなく、異なるコードで同じ目的を達成するためのより良い方法を知っている場合は、それも投稿してください。

更新:ここにもコードを投稿しました。 https://Gist.github.com/812204

注:これを試してみたいと思うすべての個人のために、ただ次のようにしてください。

第1テーマのfunctions.php "ファイルに以下のコードをコピーするか貼り付けてください。

///////////////////////////////////////////////////////////////////////////////////////////
// CODE TO ADD POST PER PAGE FILTER
///////////////////////////////////////////////////////////////////////////////////////////    
    add_filter( 'edit_posts_per_page', 'reorder_edit_posts_per_page', 10, 2 );
    function reorder_edit_posts_per_page( $per_page, $post_type ) {

        // CHECK USER PERMISSIONS
        if ( !current_user_can('edit_others_pages') )
            return;
        $post_type_object = get_post_type_object( $post_type );

        // ONLY APPLY TO HIERARCHICAL POST TYPE
        if ( !$post_type_object->hierarchical )
            return;

        // ADD POST PER PAGE DROP DOWN UI
        add_action( 'restrict_manage_posts', 'reorder_posts_per_page_filter' );

        // ADD SPECIAL STYLES (MOVE CURSOR & SPINNING LOADER AFTER REORDER)
        wp_enqueue_script( 'page-ordering', get_bloginfo('stylesheet_directory') . '/custom/js/page-resorting.js', array('jquery-ui-sortable'), '0.8.4', true );
        add_action( 'admin_print_styles', 'reorder_admin_styles' );

        if ( isset( $_GET['spo'] ) && is_numeric( $_GET['spo'] ) && ( $_GET['spo'] == -1 || ($_GET['spo']%10) == 0 ) ) :
            global $edit_per_page, $user_ID;
            $per_page = $_GET['spo'];
            if ( $per_page == -1 )
                $per_page = 99999;
            update_user_option( $user_ID, $edit_per_page, $per_page );
        endif;
        return $per_page;
    }


    // STYLING CSS FOR THE AJAX
       function reorder_admin_styles() {
        echo '<style type="text/css">table.widefat tbody th, table.widefat tbody td { cursor: move; }</style>';
       }


    // FUNCTION TO CREATE THE NUMBER OF POSTS PER PAGE DROPDOWN UI
       function reorder_posts_per_page_filter() {
        global $per_page;       
        $spo = isset($_GET['spo']) ? (int)$_GET['spo'] : $per_page;
       ?>
        Display:<select name="spo" style="width: 100px;">
            <option<?php selected( $spo, -1 ); ?> value="-1"><?php _e('All Results'); ?></option>
            <?php for( $i=10;$i<=100;$i+=10 ) : ?>
            <option<?php selected( $spo, $i ); ?> value="<?php echo $i ?>"><?php echo $i; ?> <?php _e('Results'); ?></option>
            <?php endfor; ?>        
        </select>
       <?php
       } 



    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // ACTUAL AJAX REQUEST FOR SORTING PAGES 
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////

    add_action( 'wp_ajax_simple_page_ordering', 'reorder_do_page_ordering' );
    function reorder_do_page_ordering() {

        // RECHECK PERMISSIONS
        if ( !current_user_can('edit_others_pages') || !isset($_POST['id']) || empty($_POST['id']) || ( !isset($_POST['previd']) && !isset($_POST['nextid']) ) )
            die(-1);

        // IS IT A REAL POST?
        if ( !$post = get_post( $_POST['id'] ) )
            die(-1);
        $previd = isset($_POST['previd']) ? $_POST['previd'] : false;
        $nextid = isset($_POST['nextid']) ? $_POST['nextid'] : false;
        if ( $previd ) {

            // FETCH ALL THE SIBLINGS (RELATIVE ORDERING)
            $siblings = get_posts(array( 'depth' => 1, 'numberposts' => -1, 'post_type' => $post->post_type, 'post_status' => 'publish,pending,draft,future,private', 'post_parent' => $post->post_parent, 'orderby' => 'menu_order', 'order' => 'ASC', 'exclude' => $post->ID ));
            foreach( $siblings as $sibling ) :

                // BEGIN UPDATING MENU ORDERS
                if ( $sibling->ID == $previd ) {
                    $menu_order = $sibling->menu_order + 1;
                    // UPDATE THE ACTUAL MOVED POST TO 1 AFTER PREV
                    wp_update_post(array( 'ID' => $post->ID, 'menu_order' => $menu_order ));
                    continue;
                }

                // NOTHING LEFT TO DO - NUMBERS CORRECTLY PADDED
                if ( isset($menu_order) && $menu_order < $sibling->menu_order )
                    break; 

                // NEED TO UPDATE THE SIBLINGS MENU ORDER AS WELL
                if ( isset($menu_order) ) {
                    $menu_order++;
                    // UPDATE THE ACTUAL MOVED POST TO 1 AFTER PREV
                    wp_update_post(array( 'ID' => $sibling->ID, 'menu_order' => $menu_order )); 
                }       
            endforeach;
        }

        if ( !isset($menu_order) && $nextid ) {

            // FETCH ALL THE SIBLINGS (RELATIVE ORDERING)
            $siblings = get_posts(array( 'depth' => 1, 'numberposts' => -1, 'post_type' => $post->post_type, 'post_status' => 'publish,pending,draft,future,private', 'post_parent' => $post->post_parent, 'orderby' => 'menu_order', 'order' => 'DESC', 'exclude' => $post->ID ));
            foreach( $siblings as $sibling ) :

                // START UPDATING MENU ORDERS
                if ( $sibling->ID == $nextid ) {
                    $menu_order = $sibling->menu_order - 1;
                    // UPDATE THE ACTUAL MOVED POST TO 1 AFTER PREV
                    wp_update_post(array( 'ID' => $post->ID, 'menu_order' => $menu_order ));
                    continue;
                }

                // NOTHING LEFT TO DO - NUMBER ALREADY PADDED
                if ( isset($menu_order) && $menu_order > $sibling->menu_order )
                    break; 

                // NEED TO UPDATE THE SIBLING MENU ORDER
                if ( isset($menu_order) ) {
                    $menu_order--;
                    // UPDATE THE ACTUAL MOVED POST TO 1 AFTER PREV
                    wp_update_post(array( 'ID' => $sibling->ID, 'menu_order' => $menu_order )); 
                }       
            endforeach;
        }

        // FETCH ALL THE SIBLINGS WITH RELATIVE ORDERING AND IF THE MOVED POST HAS CHILDREN REFRESH THE PAGE
        $children = get_posts(array( 'depth' => 1, 'numberposts' => 1, 'post_type' => $post->post_type, 'post_status' => 'publish,pending,draft,future,private', 'post_parent' => $post->ID ));
        if ( !empty($children) )
            die('children');
        die();
    }

第2ステップ以下のスクリプトはカスタムjsファイルを呼び出すので、このファイルを作成して含める必要があります。上記のスクリプトを変更したくない場合は、テーマフォルダのルートディレクトリにフォルダを作成して「カスタム」と呼びます。次に、このフォルダ内に "js"という別のフォルダを作成します。次に、このページ内に "page-resorting.js"という名前の新しいファイルを作成し、次のコードをそのファイルに貼り付けます。これが完了したら、管理領域のすべてのページをドラッグアンドドロップで並べ替えることができるはずです。

/////////////////////////////////////////////////////////////////////////////////////////////////////
// THIS SCRIPT APPLIES TO THE CUSTOM SCRIPT MODIFICATION ALLOWING HIERARCHICAL PAGES TO BE REORDERED
/////////////////////////////////////////////////////////////////////////////////////////////////////


jQuery("table.widefat tbody").sortable({  
    cursor: 'move',
    axis: 'y',
    containment: 'table.widefat',
    scrollSensitivity: 40,
    helper: function(e, ui) {                   
        ui.children().each(function() { jQuery(this).width(jQuery(this).width()); });
        return ui;
    },
    start: function(event, ui) {
        if ( ! ui.item.hasClass('alternate') ) ui.item.css( 'background-color', '#ffffff' );
        ui.item.children('td, th').css('border','none');
        ui.item.css( 'outline', '1px solid #dfdfdf' );
    },
    stop: function(event, ui) {     
        ui.item.removeAttr('style');
        ui.item.children('td, th').removeAttr('style');
    },
    update: function(event, ui) {   
        if ( ui.item.hasClass('inline-editor') ) {
            jQuery("table.widefat tbody").sortable('cancel');
            alert( 'Please close the quick editor before reordering this item.' );
            return;
        }

        var postid = ui.item.find('.check-column input').val(); // THIS POST ID
        var postparent = ui.item.find('.post_parent').html();   // POST PARENT

        var prevpostid = ui.item.prev().find('.check-column input').val();
        var nextpostid = ui.item.next().find('.check-column input').val();

        // can only sort in same tree

        var prevpostparent = undefined;
        if ( prevpostid != undefined ) {
            var prevpostparent = ui.item.prev().find('.post_parent').html()
            if ( prevpostparent != postparent) prevpostid = undefined;
        }

        var nextpostparent = undefined;
        if ( nextpostid != undefined ) {
            nextpostparent = ui.item.next().find('.post_parent').html();
            if ( nextpostparent != postparent) nextpostid = undefined;
        }   

        // DISPLAY AN ALERT MESSAGE IF ANY OF THE FOLLOWING TAKES PLACE
        // IF PREVIOUS AND NEXT ARE NOT AT THE SAME TREE LEVEL OR NOT AT THE SAME TREE LEVEL AND THE PREVIOUS PAGE IS THE PARENT OF THE NEXT OR JUST MOVED BENEATH ITS OWN CHILDREN                     
        if ( ( prevpostid == undefined && nextpostid == undefined ) || ( nextpostid == undefined && nextpostparent == prevpostid ) || ( nextpostid != undefined && prevpostparent == postid ) ) {
            jQuery("table.widefat tbody").sortable('cancel');
            alert( "SORRY, THIS ACTION IS NOT POSSIBLE!\n\n>>> WHY THIS DOES NOT WORK:\nDrag-and-Drop capabilities only work for items within their current tree.\n\n>>> HERE IS HOW YOU CAN MOVE IT:\nIn order to move this item to the location you specified you simply need to use the \"Quick Edit\" link and modify the associated \"Parent\" page.\n\n>>> LOCATING THE QUICK EDIT LINK:\nOn the post you want to move, just hover over the post title and click on the \"Quick Edit\" link which appears below the title." );
            return;
        }

        // SHOW AJAX SPINNING SAVE ELEMENT
        ui.item.find('.check-column input').hide().after('<img alt="processing" src="images/wpspin_light.gif" class="waiting" style="margin-left: 6px;" />');

        // EXECUTE THE SORTING VIA AJAX
        jQuery.post( ajaxurl, { action: 'simple_page_ordering', id: postid, previd: prevpostid, nextid: nextpostid }, function(response){           
            if ( response == 'children' ) window.location.reload();
            else ui.item.find('.check-column input').show().siblings('img').remove();
        });

        // FIX CELL COLORS
        jQuery( 'table.widefat tbody tr' ).each(function(){
            var i = jQuery('table.widefat tbody tr').index(this);
            if ( i%2 == 0 ) jQuery(this).addClass('alternate');
            else jQuery(this).removeClass('alternate');
        });
    }
}).disableSelection();
1

実際には答えではありませんが、おそらく答えはこのどこかにあります。私はnavmenu jsスクリプトを解凍し、ドラッグアンドドロップでソート可能なネストされたナビゲーションアイテムを可能にするコードであると思われるものを取り除きました。かわいくないです。

私はjQuery UIのドラッグ可能/ソート可能モジュールが入れ子要素をサポートしているとは思いません、そしてそれはあなたがそれをそのように動かすようにするかどうかにかかわらず作るか壊れるものでしょう。 navmenuスクリプトには、内外の幅、つまり奥行きを計算するために使用されるオブジェクトと関数のセットを、かなり詳細では解読するのが難しいです。私はそれを理解しようとしますが、私は私のAjaxポスト添付ファイルが動的メタボックスプラグインをアップロードし、それがまだ正しく機能するようにすることに関する私自身の問題を抱えています。

あなたがjqUIを使うことさえできるならば、多分これを見ることはあなたがあなたのコードで何をする必要があるかについてあなたにいくらかの洞察を与えるでしょう。

これは解凍されたnav-menu.jsファイル全体です。 https://Gist.github.com/8206 これを理解するためには、これらを結び付ける必要があるかもしれません。含めなかった。

depthToPx: function (c) {
    return c * a.options.menuItemDepthPerLevel
},
pxToDepth: function (c) {
    return Math.floor(c / a.options.menuItemDepthPerLevel)
}

menuItemDepth: function () {
    var c = a.isRTL ? this.eq(0).css("margin-right") : this.eq(0).css("margin-left");
    return a.pxToDepth(c && -1 != c.indexOf("px") ? c.slice(0, -2) : 0)
},
updateDepthClass: function (d, c) {
    return this.each(function () {
        var e = b(this);
        c = c || e.menuItemDepth();
        b(this).removeClass("menu-item-depth-" + c).addClass("menu-item-depth-" + d)
    })
},
shiftDepthClass: function (c) {
    return this.each(function () {
        var d = b(this),
            e = d.menuItemDepth();
        b(this).removeClass("menu-item-depth-" + e).addClass("menu-item-depth-" + (e + c))
    })
},
childMenuItems: function () {
    var c = b();
    this.each(function () {
        var d = b(this),
            f = d.menuItemDepth(),
            e = d.next();
        while (e.length && e.menuItemDepth() > f) {
            c = c.add(e);
            e = e.next()
        }
    });
    return c
},
updateParentMenuItemDBId: function () {
    return this.each(function () {
        var e = b(this),
            c = e.find(".menu-item-data-parent-id"),
            f = e.menuItemDepth(),
            d = e.prev();
        if (f == 0) {
            c.val(0)
        } else {
            while (!d[0] || !d[0].className || -1 == d[0].className.indexOf("menu-item") || (d.menuItemDepth() != f - 1)) {
                d = d.prev()
            }
            c.val(d.find(".menu-item-data-db-id").val())
        }
    })
}

これはsortablesのinitメソッドです。

initSortables: function () {
    var p = 0,
        e, t, d, l, o, f, c, i, s, m = a.menuList.offset().left,
        h = b("body"),
        q, n = r();
    m += a.isRTL ? a.menuList.width() : 0;
    a.menuList.sortable({
        handle: ".menu-item-handle",
        placeholder: "sortable-placeholder",
        start: function (A, z) {
            var u, x, w, v, y;
            if (a.isRTL) {
                z.item[0].style.right = "auto"
            }
            s = z.item.children(".menu-item-transport");
            e = z.item.menuItemDepth();
            j(z, e);
            w = (z.item.next()[0] == z.placeholder[0]) ? z.item.next() : z.item;
            v = w.childMenuItems();
            s.append(v);
            u = s.outerHeight();
            u += (u > 0) ? (z.placeholder.css("margin-top").slice(0, -2) * 1) : 0;
            u += z.helper.outerHeight();
            i = u;
            u -= 2;
            z.placeholder.height(u);
            q = e;
            v.each(function () {
                var B = b(this).menuItemDepth();
                q = (B > q) ? B : q
            });
            x = z.helper.find(".menu-item-handle").outerWidth();
            x += a.depthToPx(q - e);
            x -= 2;
            z.placeholder.width(x);
            y = z.placeholder.next();
            y.css("margin-top", i + "px");
            z.placeholder.detach();
            b(this).sortable("refresh");
            z.item.after(z.placeholder);
            y.css("margin-top", 0);
            k(z)
        },
        stop: function (x, w) {
            var v, u = p - e;
            v = s.children().insertAfter(w.item);
            if (u != 0) {
                w.item.updateDepthClass(p);
                v.shiftDepthClass(u);
                g(u)
            }
            a.registerChange();
            w.item.updateParentMenuItemDBId();
            w.item[0].style.top = 0;
            if (a.isRTL) {
                w.item[0].style.left = "auto";
                w.item[0].style.right = 0
            }
            a.refreshMenuTabs(true)
        },
        change: function (v, u) {
            if (!u.placeholder.parent().hasClass("menu")) {
                (l.length) ? l.after(u.placeholder) : a.menuList.prepend(u.placeholder)
            }
            k(u)
        },
        sort: function (w, v) {
            var y = v.helper.offset(),
                u = a.isRTL ? y.left + v.helper.width() : y.left,
                x = a.negateIfRTL * a.pxToDepth(u - m);
            if (x > d || y.top < f) {
                x = d
            } else {
                if (x < t) {
                    x = t
                }
            }
            if (x != p) {
                j(v, x)
            }
            if (c && y.top + i > c) {
                o.after(v.placeholder);
                k(v);
                b(this).sortable("refreshPositions")
            }
        }
    });

    function k(u) {
        var v;
        l = u.placeholder.prev();
        o = u.placeholder.next();
        if (l[0] == u.item[0]) {
            l = l.prev()
        }
        if (o[0] == u.item[0]) {
            o = o.next()
        }
        f = (l.length) ? l.offset().top + l.height() : 0;
        c = (o.length) ? o.offset().top + o.height() / 3 : 0;
        t = (o.length) ? o.menuItemDepth() : 0;
        if (l.length) {
            d = ((v = l.menuItemDepth() + 1) > a.options.globalMaxDepth) ? a.options.globalMaxDepth : v
        } else {
            d = 0
        }
    }
    function j(u, v) {
        u.placeholder.updateDepthClass(v, p);
        p = v
    }
    function r() {
        if (!h[0].className) {
            return 0
        }
        var u = h[0].className.match(/menu-max-depth-(\d+)/);
        return u && u[1] ? parseInt(u[1]) : 0
    }
    function g(u) {
        var v, w = n;
        if (u === 0) {
            return
        } else {
            if (u > 0) {
                v = q + u;
                if (v > n) {
                    w = v
                }
            } else {
                if (u < 0 && q == n) {
                    while (!b(".menu-item-depth-" + w, a.menuList).length && w > 0) {
                        w--
                    }
                }
            }
        }
        h.removeClass("menu-max-depth-" + n).addClass("menu-max-depth-" + w);
        n = w
    }
}

彼らがWPの他のスクリプトでそうするように、彼らがこのファイルのdevバージョンを持っているならば、いいでしょう。縮小された1文字のvarは、今のところ私には処理できません。それはただアルファベットのスープです。

2
jaredwilli