PluginProbe ʕ •ᴥ•ʔ
Admin and Site Enhancements (ASE) / 7.2.0
Admin and Site Enhancements (ASE) v7.2.0
9.1.0 9.0.2 9.0.1 9.0.0 8.9.2 8.9.1 8.9.0 8.8.8 8.8.7 8.8.6 8.8.5 8.8.4 8.8.3 8.8.2 8.8.1 8.8.0 8.7.3 8.7.2 8.7.1 8.2.1 8.2.2 8.2.3 8.3.0 8.3.1 8.3.2 8.4.0 8.4.1 8.4.2 8.5.0 8.5.1 8.5.2 8.6.0 8.6.1 8.6.2 8.7.0 5.0.1 5.0.2 5.0.2.1 5.0.2.2 5.0.2.3 5.0.2.4 5.1.0 5.2.0 5.2.1 5.2.10 5.2.11 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.8.0 5.8.1 6.0.0 6.0.3 6.0.4 6.0.5 6.0.5.1 6.0.6 6.0.7 6.0.8.1 6.1.0 6.1.3 6.2.0 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.2.6 6.2.7 6.3.0 6.3.1 6.3.2 6.4.0 6.5.0 6.5.1 6.6.0 6.7.0 6.8.0 6.8.2 6.8.3 6.9.0 6.9.1 6.9.10 6.9.11 6.9.12 6.9.13.1 6.9.13.2 6.9.2 6.9.3 6.9.4 6.9.5 6.9.6 6.9.7 6.9.8 6.9.9 7.0.0 7.0.2 7.0.2.1 7.0.2.2 7.0.2.3 7.0.3 7.1.0 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2.0 7.2.1 7.3.0 7.3.1 7.3.2 7.3.3 7.4.0 7.4.2 7.4.4 7.4.5 7.4.6 7.4.7 7.4.8 7.5.0 7.5.1 7.5.2 7.5.3 7.5.4 7.6.0 7.6.1 7.6.1.1 7.6.10 7.6.11 7.6.2 7.6.3 7.6.4 7.6.5 7.6.6 7.6.7 7.6.7.1 7.6.8 7.6.9 7.7.0 7.8.0 7.8.1 7.8.10 7.8.11 7.8.12 7.8.13 7.8.14 7.8.15 7.8.16 7.8.17 7.8.18 7.8.2 7.8.3 7.8.4 7.8.5 7.8.5.1 7.8.6 7.8.7 7.8.8 7.8.9 7.9.0 7.9.1 7.9.10 7.9.11 7.9.2 7.9.3 7.9.4 7.9.5 7.9.6 7.9.7 7.9.8 7.9.9 8.0.0 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.0.6 8.0.7 8.0.8 8.1.0 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 trunk 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 1.9.0 2.0.0 2.1.0 2.2.0 2.3.0 2.4.0 2.5.0 2.6.0 2.7.0 2.8.0 2.8.1 2.8.2 2.8.3 2.9.0 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.2.0 3.3.0 3.4.0 3.5.0 3.6.1 3.7.0 3.8.0 3.9.0 3.9.1 3.9.2 4.0.0 4.0.1 4.1.0 4.2.0 4.2.1 4.2.2 4.3.0 4.3.1 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.1 4.8.2 4.8.3 4.9.0 4.9.1 4.9.2 4.9.3 5.0.0
admin-site-enhancements / classes / class-content-order.php
admin-site-enhancements / classes Last commit date
class-activation.php 2 years ago class-admin-columns-manager.php 2 years ago class-admin-menu-organizer.php 2 years ago class-auto-publish-posts-with-missed-schedule.php 2 years ago class-avif-upload.php 2 years ago class-change-login-url.php 2 years ago class-cleanup-admin-bar.php 2 years ago class-code-snippets-manager.php 2 years ago class-common-methods.php 2 years ago class-content-duplication.php 2 years ago class-content-order.php 2 years ago class-custom-admin-footer-text.php 2 years ago class-custom-body-class.php 2 years ago class-custom-content-types.php 2 years ago class-custom-css.php 2 years ago class-custom-nav-menu-items-in-new-tab.php 2 years ago class-deactivation.php 2 years ago class-disable-comments.php 2 years ago class-disable-dashboard-widgets.php 2 years ago class-disable-feeds.php 2 years ago class-disable-gutenberg.php 2 years ago class-disable-rest-api.php 2 years ago class-disable-smaller-components.php 2 years ago class-disable-updates.php 2 years ago class-disable-xml-rpc.php 2 years ago class-display-system-summary.php 2 years ago class-email-address-obfuscator.php 2 years ago class-email-delivery.php 2 years ago class-enhance-list-tables.php 2 years ago class-external-permalinks.php 2 years ago class-heartbeat-control.php 2 years ago class-hide-admin-bar.php 2 years ago class-hide-admin-notices.php 2 years ago class-image-sizes-panel.php 2 years ago class-image-upload-control.php 2 years ago class-insert-head-body-footer-code.php 2 years ago class-last-login-column.php 2 years ago class-limit-login-attempts.php 2 years ago class-login-id-type.php 2 years ago class-login-logout-menu.php 2 years ago class-maintenance-mode.php 2 years ago class-manage-ads-appads-txt.php 2 years ago class-manage-robots-txt.php 2 years ago class-media-replacement.php 2 years ago class-multiple-user-roles.php 2 years ago class-obfuscate-author-slugs.php 2 years ago class-open-external-links-in-new-tab.php 2 years ago class-password-protection.php 2 years ago class-redirect-after-login.php 2 years ago class-redirect-after-logout.php 2 years ago class-redirect-fourofour.php 2 years ago class-revisions-control.php 2 years ago class-search-engines-visibility.php 2 years ago class-settings-fields-render.php 2 years ago class-settings-sanitization.php 2 years ago class-settings-sections-fields.php 2 years ago class-show-custom-taxonomy-filters.php 2 years ago class-site-identity-on-login-page.php 2 years ago class-svg-upload.php 2 years ago class-various-admin-ui-enhancements.php 2 years ago class-view-admin-as-role.php 2 years ago class-wider-admin-menu.php 2 years ago
class-content-order.php
456 lines
1 <?php
2
3 namespace ASENHA\Classes;
4
5 use WP_Query;
6 /**
7 * Class for Content Order module
8 *
9 * @since 6.9.5
10 */
11 class Content_Order {
12 /**
13 * Add "Custom Order" sub-menu for post types
14 *
15 * @since 5.0.0
16 */
17 public function add_content_order_submenu( $context ) {
18 $options = get_option( ASENHA_SLUG_U, array() );
19 $content_order_for = ( isset( $options['content_order_for'] ) ? $options['content_order_for'] : array() );
20 $content_order_enabled_post_types = array();
21 if ( is_array( $content_order_for ) && count( $content_order_for ) > 0 ) {
22 foreach ( $content_order_for as $post_type_slug => $is_custom_order_enabled ) {
23 if ( $is_custom_order_enabled ) {
24 $post_type_object = get_post_type_object( $post_type_slug );
25 if ( is_object( $post_type_object ) && property_exists( $post_type_object, 'labels' ) ) {
26 $post_type_name_plural = $post_type_object->labels->name;
27 if ( 'post' == $post_type_slug ) {
28 $hook_suffix = add_posts_page(
29 $post_type_name_plural . ' Order',
30 // Page title
31 'Order',
32 // Menu title
33 'edit_pages',
34 // Capability required
35 'custom-order-posts',
36 // Menu and page slug
37 [$this, 'custom_order_page_output']
38 );
39 } else {
40 $hook_suffix = add_submenu_page(
41 'edit.php?post_type=' . $post_type_slug,
42 // Parent (menu) slug. Ref: https://developer.wordpress.org/reference/functions/add_submenu_page/#comment-1404
43 $post_type_name_plural . ' Order',
44 // Page title
45 'Order',
46 // Menu title
47 'edit_pages',
48 // Capability required
49 'custom-order-' . $post_type_slug,
50 // Menu and page slug
51 [$this, 'custom_order_page_output'],
52 // Callback function that outputs page content
53 9999
54 );
55 }
56 add_action( 'admin_print_styles-' . $hook_suffix, [$this, 'enqueue_content_order_styles'] );
57 add_action( 'admin_print_scripts-' . $hook_suffix, [$this, 'enqueue_content_order_scripts'] );
58 }
59 }
60 }
61 }
62 }
63
64 /**
65 * Output content for the custom order page for each enabled post types
66 * Not using settings API because all done via AJAX
67 *
68 * @since 5.0.0
69 */
70 public function custom_order_page_output() {
71 $post_status = array(
72 'publish',
73 'future',
74 'draft',
75 'pending',
76 'private'
77 );
78 $parent_slug = get_admin_page_parent();
79 if ( 'edit.php' == $parent_slug ) {
80 $post_type_slug = 'post';
81 } elseif ( 'upload.php' == $parent_slug ) {
82 $post_type_slug = 'attachment';
83 $post_status = array('inherit', 'private');
84 } else {
85 $post_type_slug = str_replace( 'edit.php?post_type=', '', $parent_slug );
86 }
87 // Object with properties for each post status and the count of posts for each status
88 // $post_count_object = wp_count_posts( $post_type_slug );
89 // Number of items with the status 'publish(ed)', 'future' (scheduled), 'draft', 'pending' and 'private'
90 // $post_count = absint( $post_count_object->publish )
91 // + absint( $post_count_object->future )
92 // + absint( $post_count_object->draft )
93 // + absint( $post_count_object->pending )
94 // + absint( $post_count_object->private );
95 ?>
96 <div class="wrap">
97 <div class="page-header">
98 <h2>
99 <?php
100 echo esc_html( get_admin_page_title() );
101 ?>
102 </h2>
103 <div id="toggles" style="display:none;">
104 <input type="checkbox" id="toggle-taxonomy-terms" name="terms" value="" /><label for="toggle-taxonomy-terms">Show taxonomy terms</label>
105 <input type="checkbox" id="toggle-excerpt" name="excerpt" value="" /><label for="toggle-excerpt">Show excerpt</label>
106 </div>
107 </div>
108 <?php
109 // Get posts
110 $args = array(
111 'post_type' => $post_type_slug,
112 'posts_per_page' => -1,
113 'orderby' => 'menu_order title',
114 'order' => 'ASC',
115 'post_status' => $post_status,
116 );
117 // Add the following to non-attachment post types
118 if ( 'attachment' != $post_type_slug ) {
119 // In hierarchical post types, only return non-child posts as we currently only sort parent posts
120 $args['post_parent'] = 0;
121 }
122 $query = new WP_Query($args);
123 if ( $query->have_posts() ) {
124 ?>
125 <ul id="item-list">
126 <?php
127 while ( $query->have_posts() ) {
128 $query->the_post();
129 $post = get_post( get_the_ID() );
130 $this->custom_order_single_item_output( $post );
131 }
132 ?>
133 </ul>
134 <div id="updating-order-notice" class="updating-order-notice" style="display: none;"><img src="<?php
135 echo esc_attr( ASENHA_URL ) . 'assets/img/oval.svg';
136 ?>" id="spinner-img" class="spinner-img" /><span class="dashicons dashicons-saved" style="display:none;"></span>Updating order...</div>
137 <?php
138 } else {
139 ?>
140 <h3>There is nothing to sort for this post type.</h3>
141 <?php
142 }
143 ?>
144 </div> <!-- End of div.wrap -->
145 <?php
146 wp_reset_postdata();
147 }
148
149 /**
150 * Output single item sortable for custom content order
151 *
152 * @since 5.0.0
153 */
154 private function custom_order_single_item_output( $post ) {
155 if ( is_post_type_hierarchical( $post->post_type ) ) {
156 $post_type_object = get_post_type_object( $post->post_type );
157 $children = get_pages( array(
158 'child_of' => $post->ID,
159 'post_type' => $post->post_type,
160 ) );
161 if ( count( $children ) > 0 ) {
162 $has_child_label = '<span class="has-child-label"> <span class="dashicons dashicons-arrow-right"></span> Has child ' . strtolower( $post_type_object->label ) . '</span>';
163 $has_child = 'true';
164 } else {
165 $has_child_label = '';
166 $has_child = 'false';
167 }
168 } else {
169 $has_child_label = '';
170 $has_child = 'false';
171 }
172 $post_status_label_class = ( $post->post_status == 'publish' ? ' item-status-hidden' : '' );
173 $post_status_object = get_post_status_object( $post->post_status );
174 if ( 'attachment' == $post->post_type ) {
175 $post_status_label_separator = '';
176 $post_status_label = '';
177 // Attachments / media only has the post status 'inherit'. Let's not show it.
178 } else {
179 $post_status_label_separator = '';
180 $post_status_label = $post_status_object->label;
181 }
182 if ( empty( wp_trim_excerpt( '', $post ) ) ) {
183 $short_excerpt = '';
184 } else {
185 $excerpt_trimmed = implode( " ", array_slice( explode( " ", wp_trim_excerpt( '', $post ) ), 0, 30 ) );
186 $short_excerpt = '<span class="item-excerpt"> | ' . $excerpt_trimmed . '</span>';
187 }
188 $taxonomies = get_object_taxonomies( $post->post_type, 'objects' );
189 // vi( $taxonomies );
190 $taxonomies_and_terms = '';
191 foreach ( $taxonomies as $taxonomy ) {
192 $terms = array();
193 if ( $taxonomy->hierarchical ) {
194 $taxonomy_terms = get_the_terms( $post->ID, $taxonomy->name );
195 if ( is_array( $taxonomy_terms ) && !empty( $taxonomy_terms ) ) {
196 foreach ( $taxonomy_terms as $term ) {
197 $terms[] = $term->name;
198 }
199 }
200 }
201 $terms = implode( ', ', $terms );
202 $taxonomies_and_terms .= ' | ' . $taxonomy->label . ': ' . $terms;
203 }
204 if ( !empty( $taxonomies_and_terms ) ) {
205 $taxonomies_and_terms = '<span class="item-taxonomy-terms">' . $taxonomies_and_terms . '</span>';
206 }
207 ?>
208 <li id="list_<?php
209 echo esc_attr( $post->ID );
210 ?>" data-id="<?php
211 echo esc_attr( $post->ID );
212 ?>" data-menu-order="<?php
213 echo esc_attr( $post->menu_order );
214 ?>" data-parent="<?php
215 echo esc_attr( $post->post_parent );
216 ?>" data-has-child="<?php
217 echo esc_attr( $has_child );
218 ?>" data-post-type="<?php
219 echo esc_attr( $post->post_type );
220 ?>">
221 <div class="row">
222 <div class="row-content">
223 <?php
224 echo '<div class="content-main">
225 <span class="dashicons dashicons-menu"></span><a href="' . esc_attr( get_edit_post_link( $post->ID ) ) . '" class="item-title">' . esc_html( $post->post_title ) . '</a><span class="item-status' . esc_attr( $post_status_label_class ) . '">' . esc_html( $post_status_label_separator ) . esc_html( $post_status_label ) . '</span>' . wp_kses_post( $has_child_label ) . wp_kses_post( $taxonomies_and_terms ) . wp_kses_post( $short_excerpt ) . '<div class="fader"></div>
226 </div>
227 <div class="content-additional">
228 <a href="' . esc_attr( get_the_permalink( $post->ID ) ) . '" target="_blank" class="button item-view-link">View</a>
229 </div>';
230 ?>
231 </div>
232 </div>
233 </li>
234 <?php
235 }
236
237 /**
238 * Enqueue styles for content order pages
239 *
240 * @since 5.0.0
241 */
242 public function enqueue_content_order_styles() {
243 wp_enqueue_style(
244 'content-order-style',
245 ASENHA_URL . 'assets/css/content-order.css',
246 array(),
247 ASENHA_VERSION
248 );
249 }
250
251 /**
252 * Enqueue scripts for content order pages
253 *
254 * @since 5.0.0
255 */
256 public function enqueue_content_order_scripts() {
257 global $typenow;
258 wp_enqueue_script(
259 'content-order-jquery-ui-touch-punch',
260 ASENHA_URL . 'assets/js/jquery.ui.touch-punch.min.js',
261 array('jquery-ui-sortable'),
262 '0.2.3',
263 true
264 );
265 wp_register_script(
266 'content-order-nested-sortable',
267 ASENHA_URL . 'assets/js/jquery.mjs.nestedSortable.js',
268 array('content-order-jquery-ui-touch-punch'),
269 '2.0.0',
270 true
271 );
272 wp_enqueue_script(
273 'content-order-sort',
274 ASENHA_URL . 'assets/js/content-order-sort.js',
275 array('content-order-nested-sortable'),
276 ASENHA_VERSION,
277 true
278 );
279 wp_localize_script( 'content-order-sort', 'contentOrderSort', array(
280 'action' => 'save_custom_order',
281 'nonce' => wp_create_nonce( 'order_sorting_nonce' ),
282 'hirarchical' => ( is_post_type_hierarchical( $typenow ) ? 'true' : 'false' ),
283 ) );
284 }
285
286 /**
287 * Save custom content order coming from ajax call
288 *
289 * @since 5.0.0
290 */
291 public function save_custom_content_order() {
292 global $wpdb;
293 // Check user capabilities
294 if ( !current_user_can( 'edit_pages' ) ) {
295 wp_send_json( 'Something went wrong.' );
296 }
297 // Verify nonce
298 if ( !wp_verify_nonce( $_POST['nonce'], 'order_sorting_nonce' ) ) {
299 wp_send_json( 'Something went wrong.' );
300 }
301 // Get ajax variables
302 $action = ( isset( $_POST['action'] ) ? $_POST['action'] : '' );
303 // Item parent is currently 0, as we only handle sorting of non-child posts
304 $item_parent = ( isset( $_POST['item_parent'] ) ? absint( $_POST['item_parent'] ) : 0 );
305 $menu_order_start = ( isset( $_POST['start'] ) ? absint( $_POST['start'] ) : 0 );
306 $post_id = ( isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0 );
307 $item_menu_order = ( isset( $_POST['menu_order'] ) ? absint( $_POST['menu_order'] ) : 0 );
308 $items_to_exclude = ( isset( $_POST['excluded_items'] ) ? absint( $_POST['excluded_items'] ) : array() );
309 $post_type = ( isset( $_POST['post_type'] ) ? $_POST['post_type'] : false );
310 // Make processing faster by removing certain actions
311 remove_action( 'pre_post_update', 'wp_save_post_revision' );
312 // $response array for ajax response
313 $response = array();
314 // Update the item whose order/position was moved
315 if ( $post_id > 0 && !isset( $_POST['more_posts'] ) ) {
316 // https://developer.wordpress.org/reference/classes/wpdb/update/
317 $wpdb->update(
318 $wpdb->posts,
319 // The table
320 array(
321 'menu_order' => $item_menu_order,
322 ),
323 array(
324 'ID' => $post_id,
325 )
326 );
327 clean_post_cache( $post_id );
328 $items_to_exclude[] = $post_id;
329 }
330 if ( 'attachment' == $post_type ) {
331 $post_status = array('inherit', 'private');
332 } else {
333 $post_status = array(
334 'publish',
335 'future',
336 'draft',
337 'pending',
338 'private'
339 );
340 }
341 // Get all posts from the post type related to ajax request
342 $query_args = array(
343 'post_type' => $post_type,
344 'orderby' => 'menu_order title',
345 'order' => 'ASC',
346 'posts_per_page' => -1,
347 'suppress_filters' => true,
348 'ignore_sticky_posts' => true,
349 'post_status' => $post_status,
350 'post__not_in' => $items_to_exclude,
351 'update_post_term_cache' => false,
352 'update_post_meta_cache' => false,
353 );
354 if ( 'attachment' == $post_type ) {
355 // do nothing, we do not add post_parent parameter as media items can be attached to other posts, making them the parent.
356 } else {
357 // Item parent is currently 0, as we only handle sorting of non-child posts
358 $query_args['post_parent'] = $item_parent;
359 }
360 $posts = new WP_Query($query_args);
361 if ( $posts->have_posts() ) {
362 // Iterate through posts and update menu order and post parent
363 foreach ( $posts->posts as $post ) {
364 // If the $post is the one being displaced (shited downward) by the moved item, increment it's menu_order by one
365 if ( $menu_order_start == $item_menu_order && $post_id > 0 ) {
366 $menu_order_start++;
367 }
368 // Only process posts other than the moved item, which has been processed earlier outside this loop
369 if ( $post_id != $post->ID ) {
370 // Update menu_order
371 $wpdb->update( $wpdb->posts, array(
372 'menu_order' => $menu_order_start,
373 ), array(
374 'ID' => $post->ID,
375 ) );
376 clean_post_cache( $post->ID );
377 }
378 $items_to_exclude[] = $post->ID;
379 $menu_order_start++;
380 }
381 die( json_encode( $response ) );
382 } else {
383 die( json_encode( $response ) );
384 }
385 }
386
387 /**
388 * Set default ordering of list tables of sortable post types by 'menu_order'
389 *
390 * @link https://developer.wordpress.org/reference/classes/wp_query/#methods
391 * @since 5.0.0
392 */
393 public function orderby_menu_order( $query ) {
394 global $pagenow, $typenow;
395 $options = get_option( ASENHA_SLUG_U, array() );
396 $content_order_for = ( isset( $options['content_order_for'] ) ? $options['content_order_for'] : array() );
397 $content_order_enabled_post_types = array();
398 if ( is_array( $content_order_for ) && count( $content_order_for ) > 0 ) {
399 foreach ( $content_order_for as $post_type_slug => $is_custom_order_enabled ) {
400 if ( $is_custom_order_enabled ) {
401 $content_order_enabled_post_types[] = $post_type_slug;
402 }
403 }
404 }
405 $should_be_custom_sorted = false;
406 if ( in_array( $typenow, $content_order_enabled_post_types ) ) {
407 $should_be_custom_sorted = true;
408 }
409 // Use custom order in wp-admin listing pages/tables for enabled post types
410 if ( is_admin() && ('edit.php' == $pagenow || 'upload.php' == $pagenow) && !isset( $_GET['orderby'] ) ) {
411 if ( $should_be_custom_sorted ) {
412 $query->set( 'orderby', 'menu_order title' );
413 $query->set( 'order', 'ASC' );
414 // vi( $query, '', 'for ' . $pagenow );
415 }
416 }
417 }
418
419 /**
420 * Make sure newly created posts are assigned the highest menu_order so it's added at the bottom of the existing order
421 *
422 * @since 6.2.1
423 */
424 public function set_menu_order_for_new_posts( $post_id, $post, $update ) {
425 $options = get_option( ASENHA_SLUG_U, array() );
426 $content_order_for = ( isset( $options['content_order_for'] ) ? $options['content_order_for'] : array() );
427 $content_order_enabled_post_types = array();
428 if ( is_array( $content_order_for ) && count( $content_order_for ) > 0 ) {
429 foreach ( $content_order_for as $post_type_slug => $is_custom_order_enabled ) {
430 if ( $is_custom_order_enabled ) {
431 $content_order_enabled_post_types[] = $post_type_slug;
432 }
433 }
434 }
435 // Only assign menu_order if there are none assigned when creating the post, i.e. menu_order is 0
436 if ( in_array( $post->post_type, $content_order_enabled_post_types ) && ('auto-draft' == $post->post_status || 'publish' == $post->post_status) && $post->menu_order == '0' && false === $update ) {
437 $post_with_highest_menu_order = get_posts( array(
438 'post_type' => $post->post_type,
439 'posts_per_page' => 1,
440 'orderby' => 'menu_order',
441 'order' => 'DESC',
442 ) );
443 if ( $post_with_highest_menu_order ) {
444 $new_menu_order = (int) $post_with_highest_menu_order[0]->menu_order + 1;
445 // Assign the one higher menu_order to the new post
446 $args = array(
447 'ID' => $post_id,
448 'menu_order' => $new_menu_order,
449 );
450 wp_update_post( $args );
451 }
452 }
453 }
454
455 }
456