我正在使用以下代码来转换任何层次化页面或自定义帖子类型,并能够通过简单的拖放对页面进行重新排序。(此外,此代码还向分层页面添加了一个新的显示过滤器,以使事情更简单)。
我需要帮助的问题是,当前无法将一个页面树拖到另一个页面树中或从现有页面树中拖出。
是否有人可以提供扩展此功能所需的代码修改?
如果您知道用不同的代码来实现相同目标的更好方法,而不是扩展下面提供的代码,请也发布它。
UPDATED: 我也在这里发布了代码:https://gist.github.com/812204
NOTE: 对于所有想测试这一点的人,只需执行以下操作。
1st Copy/past the code below in your themes functions.php" file.
///////////////////////////////////////////////////////////////////////////////////////////
// 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();
}
2nd Steps因为下面的脚本调用了一个自定义js文件,所以我们需要装箱并包含该文件。如果不想修改上面的脚本,请在主题文件夹的根目录中创建一个文件夹,并将其称为“自定义”。接下来,在此文件夹中创建另一个名为“js”的文件夹。接下来,在这个文件夹中创建一个名为“page restoring.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();
最合适的回答,由SO网友:jaredwilli 整理而成
这不是一个真正的答案,但也许答案就在这个地方。我解包了navmenu js脚本,并去掉了使拖放可排序的嵌套nav项成为可能的代码。这并不漂亮。
我认为jQuery UI的可拖动/可排序模块不支持嵌套元素,而这很可能是决定成败的因素,无论您是否采用这种方式。navmenu脚本有一组非常深入且难以破译的对象和函数,用于计算内部和外部宽度或深度。我会尝试解决这个问题,但我自己也有一个问题,那就是我的ajax post附件上载动态metabox插件并使其正常工作。
如果您能够使用jqUI,那么看看这一点可能会让您对代码中需要执行的操作有一些了解。
这是整个导航菜单。js文件已解压缩,https://gist.github.com/820633为了理解它,你可能需要看看是什么把这些东西联系在一起,我没有包括在内。
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方法,它做了一些疯狂的代数e=Mc2的东西lol
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中处理其他脚本一样。缩小的单字母vars现在对我来说太多了。这只是字母汤。