PluginProbe ʕ •ᴥ•ʔ
Simple Page Ordering / 2.2
Simple Page Ordering v2.2
2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.8.0 trunk 0.8.4 0.9 0.9.1 0.9.5 0.9.6 1.0 2.0 2.1 2.1.1 2.1.2 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.3
simple-page-ordering / simple-page-ordering.php
simple-page-ordering Last commit date
localization 12 years ago readme.txt 12 years ago simple-page-ordering.css 12 years ago simple-page-ordering.dev.js 12 years ago simple-page-ordering.js 12 years ago simple-page-ordering.php 12 years ago
simple-page-ordering.php
287 lines
1 <?php
2 /**
3 Plugin Name: Simple Page Ordering
4 Plugin URI: http://10up.com/plugins/simple-page-ordering-wordpress/
5 Description: Order your pages and hierarchical post types using drag and drop on the built in page list. For further instructions, open the "Help" tab on the Pages screen.
6 Version: 2.2
7 Author: Jake Goldman, 10up
8 Author URI: http://10up.com
9 License: GPLv2 or later
10 */
11
12 if ( ! class_exists( 'Simple_Page_Ordering' ) ) :
13
14 class Simple_Page_Ordering {
15
16 /**
17 * Handles initializing this class and returning the singleton instance after it's been cached.
18 *
19 * @return null|Simple_page_Ordering
20 */
21 public static function get_instance() {
22 // Store the instance locally to avoid private static replication
23 static $instance = null;
24
25 if ( null === $instance ) {
26 $instance = new self();
27 self::_add_actions();
28 }
29
30 return $instance;
31 }
32
33 /**
34 * An empty constructor
35 */
36 public function __construct() { /* Purposely do nothing here */ }
37
38 /**
39 * Handles registering hooks that initialize this plugin.
40 */
41 public static function _add_actions() {
42 add_action( 'load-edit.php', array( __CLASS__, 'load_edit_screen' ) );
43 add_action( 'wp_ajax_simple_page_ordering', array( __CLASS__, 'ajax_simple_page_ordering' ) );
44 }
45
46 /**
47 * Load up page ordering scripts for the edit screen
48 */
49 public static function load_edit_screen() {
50 $screen = get_current_screen();
51 $post_type = $screen->post_type;
52
53 // is post type sortable?
54 $sortable = ( post_type_supports( $post_type, 'page-attributes' ) || is_post_type_hierarchical( $post_type ) ); // check permission
55 if ( ! $sortable = apply_filters( 'simple_page_ordering_is_sortable', $sortable, $post_type ) ) {
56 return;
57 }
58
59 // does user have the right to manage these post objects?
60 if ( ! self::check_edit_others_caps( $post_type ) ) {
61 return;
62 }
63
64 add_filter( 'views_' . $screen->id, array( __CLASS__, 'sort_by_order_link' ) ); // add view by menu order to views
65 add_action( 'wp', array( __CLASS__, 'wp' ) );
66 add_action( 'admin_head', array( __CLASS__, 'admin_head' ) );
67 }
68
69 /**
70 * when we load up our posts query, if we're actually sorting by menu order, initialize sorting scripts
71 */
72 public static function wp() {
73 if ( 0 === strpos( get_query_var('orderby'), 'menu_order' ) ) {
74 $script_name = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? 'simple-page-ordering.dev.js' : 'simple-page-ordering.js';
75 wp_enqueue_script( 'simple-page-ordering', plugins_url( $script_name, __FILE__ ), array('jquery-ui-sortable'), '2.1', true );
76 wp_enqueue_style( 'simple-page-ordering', plugins_url( 'simple-page-ordering.css', __FILE__ ) );
77 }
78 }
79
80 /**
81 * Add page ordering help to the help tab
82 */
83 public static function admin_head() {
84 $screen = get_current_screen();
85 $screen->add_help_tab(array(
86 'id' => 'simple_page_ordering_help_tab',
87 'title' => 'Simple Page Ordering',
88 'content' => '<p>' . __( 'To reposition an item, simply drag and drop the row by "clicking and holding" it anywhere (outside of the links and form controls) and moving it to its new position.', 'simple-page-ordering' ) . '</p>',
89 ));
90 }
91
92 public static function ajax_simple_page_ordering() {
93 // check and make sure we have what we need
94 if ( empty( $_POST['id'] ) || ( !isset( $_POST['previd'] ) && !isset( $_POST['nextid'] ) ) ) {
95 die(-1);
96 }
97
98 // real post?
99 if ( ! $post = get_post( $_POST['id'] ) ) {
100 die(-1);
101 }
102
103 // does user have the right to manage these post objects?
104 if ( ! self::check_edit_others_caps( $post->post_type ) ) {
105 die(-1);
106 }
107
108 // badly written plug-in hooks for save post can break things
109 if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
110 error_reporting( 0 );
111 }
112
113 $previd = empty( $_POST['previd'] ) ? false : (int) $_POST['previd'];
114 $nextid = empty( $_POST['nextid'] ) ? false : (int) $_POST['nextid'];
115 $start = empty( $_POST['start'] ) ? 1 : (int) $_POST['start'];
116 $excluded = empty( $_POST['excluded'] ) ? array( $post->ID ) : array_filter( (array) $_POST['excluded'], 'intval' );
117
118 $new_pos = array(); // store new positions for ajax
119 $return_data = new stdClass;
120
121 do_action( 'simple_page_ordering_pre_order_posts', $post, $start );
122
123 // attempt to get the intended parent... if either sibling has a matching parent ID, use that
124 $parent_id = $post->post_parent;
125 $next_post_parent = $nextid ? wp_get_post_parent_id( $nextid ) : false;
126 if ( $previd == $next_post_parent ) { // if the preceding post is the parent of the next post, move it inside
127 $parent_id = $next_post_parent;
128 } elseif ( $next_post_parent !== $parent_id ) { // otherwise, if the next post's parent isn't the same as our parent, we need to study
129 $prev_post_parent = $previd ? wp_get_post_parent_id( $previd ) : false;
130 if ( $prev_post_parent !== $parent_id ) { // if the previous post is not our parent now, make it so!
131 $parent_id = ( $prev_post_parent !== false ) ? $prev_post_parent : $next_post_parent;
132 }
133 }
134 // if the next post's parent isn't our parent, it might as well be false (irrelevant to our query)
135 if ( $next_post_parent !== $parent_id ) {
136 $nextid = false;
137 }
138
139 $max_sortable_posts = (int) apply_filters( 'simple_page_ordering_limit', 50 ); // should reliably be able to do about 50 at a time
140 if ( $max_sortable_posts < 5 ) { // don't be ridiculous!
141 $max_sortable_posts = 50;
142 }
143
144 // we need to handle all post stati, except trash (in case of custom stati)
145 $post_stati = get_post_stati(array(
146 'show_in_admin_all_list' => true,
147 ));
148
149 $siblings = new WP_Query(array(
150 'depth' => 1,
151 'posts_per_page' => $max_sortable_posts,
152 'post_type' => $post->post_type,
153 'post_status' => $post_stati,
154 'post_parent' => $parent_id,
155 'orderby' => 'menu_order title',
156 'order' => 'ASC',
157 'post__not_in' => $excluded,
158 'update_post_term_cache' => false,
159 'update_post_meta_cache' => false,
160 'suppress_filters' => true,
161 'ignore_sticky_posts' => true,
162 )); // fetch all the siblings (relative ordering)
163
164 // don't waste overhead of revisions on a menu order change (especially since they can't *all* be rolled back at once)
165 remove_action( 'pre_post_update', 'wp_save_post_revision' );
166
167 foreach( $siblings->posts as $sibling ) :
168
169 // don't handle the actual post
170 if ( $sibling->ID === $post->ID ) {
171 continue;
172 }
173
174 // if this is the post that comes after our repositioned post, set our repositioned post position and increment menu order
175 if ( $nextid === $sibling->ID ) {
176 wp_update_post(array(
177 'ID' => $post->ID,
178 'menu_order' => $start,
179 'post_parent' => $parent_id,
180 ));
181 $ancestors = get_post_ancestors( $post->ID );
182 $new_pos[$post->ID] = array(
183 'menu_order' => $start,
184 'post_parent' => $parent_id,
185 'depth' => count( $ancestors ),
186 );
187 $start++;
188 }
189
190 // if repositioned post has been set, and new items are already in the right order, we can stop
191 if ( isset( $new_pos[$post->ID] ) && $sibling->menu_order >= $start ) {
192 $return_data->next = false;
193 break;
194 }
195
196 // set the menu order of the current sibling and increment the menu order
197 if ( $sibling->menu_order != $start ) {
198 wp_update_post(array(
199 'ID' => $sibling->ID,
200 'menu_order' => $start,
201 ));
202 }
203 $new_pos[$sibling->ID] = $start;
204 $start++;
205
206 if ( !$nextid && $previd == $sibling->ID ) {
207 wp_update_post(array(
208 'ID' => $post->ID,
209 'menu_order' => $start,
210 'post_parent' => $parent_id
211 ));
212 $ancestors = get_post_ancestors( $post->ID );
213 $new_pos[$post->ID] = array(
214 'menu_order' => $start,
215 'post_parent' => $parent_id,
216 'depth' => count($ancestors) );
217 $start++;
218 }
219
220 endforeach;
221
222 // max per request
223 if ( !isset( $return_data->next ) && $siblings->max_num_pages > 1 ) {
224 $return_data->next = array(
225 'id' => $post->ID,
226 'previd' => $previd,
227 'nextid' => $nextid,
228 'start' => $start,
229 'excluded' => array_merge( array_keys( $new_pos ), $excluded ),
230 );
231 } else {
232 $return_data->next = false;
233 }
234
235 do_action( 'simple_page_ordering_ordered_posts', $post, $new_pos );
236
237 if ( ! $return_data->next ) {
238 // if the moved post has children, we need to refresh the page (unless we're continuing)
239 $children = get_posts(array(
240 'numberposts' => 1,
241 'post_type' => $post->post_type,
242 'post_status' => $post_stati,
243 'post_parent' => $post->ID,
244 'fields' => 'ids',
245 'update_post_term_cache' => false,
246 'update_post_meta_cache' => false,
247 ));
248
249 if ( ! empty( $children ) )
250 die( 'children' );
251 }
252
253 $return_data->new_pos = $new_pos;
254
255 die( json_encode( $return_data ) );
256 }
257
258 /**
259 * Append a sort by order link to the post actions
260 *
261 * @param string $views
262 * @return string
263 */
264 public static function sort_by_order_link( $views ) {
265 $class = ( get_query_var('orderby') == 'menu_order title' ) ? 'current' : '';
266 $query_string = remove_query_arg(array( 'orderby', 'order' ));
267 $query_string = add_query_arg( 'orderby', urlencode('menu_order title'), $query_string );
268 $views['byorder'] = '<a href="'. $query_string . '" class="' . $class . '">Sort by Order</a>';
269 return $views;
270 }
271
272 /**
273 * Checks to see if the current user has the capability to "edit others" for a post type
274 *
275 * @param string $post_type Post type name
276 * @return bool True or false
277 */
278 private static function check_edit_others_caps( $post_type ) {
279 $post_type_object = get_post_type_object( $post_type );
280 $edit_others_cap = empty( $post_type_object ) ? 'edit_others_' . $post_type . 's' : $post_type_object->cap->edit_others_posts;
281 return apply_filters( 'simple_page_ordering_edit_rights', current_user_can( $edit_others_cap ), $post_type );
282 }
283 }
284
285 Simple_Page_Ordering::get_instance();
286
287 endif;