This commit is contained in:
Hanson.xyz Dev
2026-01-04 17:50:08 -06:00
parent 7e45ce0756
commit acc8ac87a0
4131 changed files with 232562 additions and 250244 deletions
@@ -0,0 +1,22 @@
#!/bin/bash
# Script directory and filename
SCRIPT_DIR="$(dirname "$0")"
SCRIPT_NAME="$(basename "$0")"
# Check for the required argument
if [ "$#" -ne 1 ]; then
echo "Usage: $0 New_Namespace"
exit 1
fi
NEW_NAMESPACE="$1"
# Use find to get all files recursively from the script's directory, excluding the script itself
find "$SCRIPT_DIR" -type f \( -name "*.php" -o -name "*.json" \) ! -name "$SCRIPT_NAME" | while read -r file; do
echo $file
# Use perl for the replacement in each file
perl -pi -e "s/WP_Compat_Validation_Tool/$NEW_NAMESPACE/g" "$file"
done
cd 10up-lib/wp-compat-validation-tool && rm -rf .git .github .gitignore composer.json composer.lock CHANGELOG.md CONTRIBUTING.md README.md LICENSE.md CODE_OF_CONDUCT.md CREDITS.md
@@ -0,0 +1,169 @@
<?php
namespace Simple_Page_Ordering_Validator;
class Validator {
/**
* Array of checks.
*
* @var array
*/
private $checklist = array();
/**
* Array of error messages
*
* @var string[]
*/
private $messages = array();
/**
* Constructor function.
*/
public function __construct() {
$this->checklist = array(
'plugin_name' => array(
'value' => '',
'required' => true,
),
'php_min_required_version' => array(
'value' => '',
'required' => false,
),
'php_max_required_version' => array(
'value' => '',
'required' => false,
),
'wp_min_required_version' => array(
'value' => '',
'required' => false,
),
'wp_max_required_version' => array(
'value' => '',
'required' => false,
),
);
}
/**
* Sets the plugin name.
*
* @param string $value Plugin name.
* @return Validator
*/
public function set_plugin_name( $value = '' ) {
$this->checklist['plugin_name']['value'] = $value;
return $this;
}
/**
* Sets the minimum PHP version supported by a plugin.
*
* @param string $value Minimum PHP version.
* @return Validator
*/
public function set_php_min_required_version( $value = '' ) {
$this->checklist['php_min_required_version']['value'] = $value;
return $this;
}
/**
* Sets the maximum PHP version supported by a plugin.
*
* @param string $value Maximum PHP version.
* @return Validator
*/
public function set_php_max_required_version( $value = '' ) {
$this->checklist['php_max_required_version']['value'] = $value;
return $this;
}
/**
* Sets the minimum WordPress version supported by a plugin.
*
* @param string $value Minimum WordPress version.
* @return Validator
*/
public function set_wordpress_min_required_version( $value = '' ) {
$this->checklist['wp_min_required_version']['value'] = $value;
return $this;
}
/**
* Sets the maximum WordPress version supported by a plugin.
*
* @param string $value Maximum WordPress version.
* @return Validator
*/
public function set_wordpress_max_required_version( $value = '' ) {
$this->checklist['wp_max_required_version']['value'] = $value;
return $this;
}
/**
* Returns true if the plugin meets all compatibility checks, false otherwise.
*
* @return boolean
*/
public function is_plugin_compatible() {
foreach ( $this->checklist as $item_name => $item_details ) {
if ( $item_details['required'] && empty( $item_details['value'] ) ) {
return false;
}
switch ( $item_name ) {
case 'php_min_required_version':
if ( ! empty( $item_details['value'] ) && version_compare( phpversion(), $item_details['value'], '<' ) ) {
$this->messages[] = sprintf( esc_html__( 'The minimum PHP version required is %s' ), $item_details['value'] );
}
break;
case 'php_max_required_version':
if ( ! empty( $item_details['value'] ) && version_compare( phpversion(), $item_details['value'], '>' ) ) {
$this->messages[] = sprintf( esc_html__( 'The maximum PHP version supported is %s' ), $item_details['value'] );
}
break;
default:
break;
}
}
if ( ! empty( $this->messages ) ) {
add_action( 'admin_notices', array( $this, 'render_php_compat_error' ) );
return false;
}
return true;
}
/**
* Renders the error messages as notice.
*/
public function render_php_compat_error() {
?>
<div class="notice notice-error">
<p>
<strong>
<?php printf( esc_html__( '%s error:' ), $this->checklist['plugin_name']['value'] ); ?>
</strong>
</p>
<?php if ( count( $this->messages ) > 1 ) : ?>
<ul>
<?php foreach ( $this->messages as $message ) : ?>
<li><?php echo esc_html( $message ); ?></li>
<?php endforeach; ?>
</ul>
<?php elseif ( 1 === count( $this->messages ) ): ?>
<p>
<?php echo esc_html( $this->messages[0] ); ?>
</p>
<?php endif; ?>
</div>
<?php
}
}
@@ -0,0 +1,900 @@
<?php
namespace SimplePageOrdering;
use stdClass;
use WP_Error;
use WP_Post;
use WP_REST_Response;
use WP_Query;
// Useful global constants.
define( 'SIMPLE_PAGE_ORDERING_VERSION', '2.7.4' );
if ( ! class_exists( 'Simple_Page_Ordering' ) ) :
/**
* Simple_Page_Ordering class
*/
class Simple_Page_Ordering {
/**
* Handles initializing this class and returning the singleton instance after it's been cached.
*
* @return null|Simple_Page_Ordering
*/
public static function get_instance() {
// Store the instance locally to avoid private static replication
static $instance = null;
if ( null === $instance ) {
$instance = new self();
self::add_actions();
}
return $instance;
}
/**
* An empty constructor
*
* Purposely do nothing here
*/
public function __construct() {}
/**
* Handles registering hooks that initialize this plugin.
*/
public static function add_actions() {
add_action( 'load-edit.php', array( __CLASS__, 'load_edit_screen' ) );
add_action( 'wp_ajax_simple_page_ordering', array( __CLASS__, 'ajax_simple_page_ordering' ) );
add_action( 'wp_ajax_reset_simple_page_ordering', array( __CLASS__, 'ajax_reset_simple_page_ordering' ) );
add_action( 'plugins_loaded', array( __CLASS__, 'load_textdomain' ) );
add_action( 'rest_api_init', array( __CLASS__, 'rest_api_init' ) );
// Custom edit page actions.
add_action( 'post_action_spo-move-under-grandparent', array( __CLASS__, 'handle_move_under_grandparent' ) );
add_action( 'post_action_spo-move-under-sibling', array( __CLASS__, 'handle_move_under_sibling' ) );
}
/**
* Move a post in/up the post parent tree.
*
* This is a custom action on the edit page to modify the post parent
* to be the child it's current grandparent post. If no grandparent
* exists, the post becomes a top level page.
*
* @param int $post_id The post ID.
*/
public static function handle_move_under_grandparent( $post_id ) {
$post = get_post( $post_id );
if ( ! $post ) {
self::redirect_to_referer();
}
check_admin_referer( "simple-page-ordering-nonce-move-{$post->ID}", 'spo_nonce' );
if ( ! current_user_can( 'edit_post', $post->ID ) ) {
wp_die( esc_html__( 'You are not allowed to edit this item.', 'simple-page-ordering' ) );
}
if ( 0 === $post->post_parent ) {
// Top level. Politely continue without doing anything.
self::redirect_to_referer();
}
$ancestors = get_post_ancestors( $post );
// If only one ancestor, set to top level page.
if ( 1 === count( $ancestors ) ) {
$parent_id = 0;
} else {
$parent_id = $ancestors[1];
}
// Update the post.
wp_update_post(
array(
'ID' => $post->ID,
'post_parent' => $parent_id,
)
);
self::redirect_to_referer();
}
/**
* Move a post out/down the post parent tree.
*
* This is a custom action on the edit page to modify the post parent
* to be the child of it's previous sibling post on the current post
* tree.
*
* @param int $post_id The post ID.
*/
public static function handle_move_under_sibling( $post_id ) {
$post = get_post( $post_id );
if ( ! $post ) {
self::redirect_to_referer();
}
check_admin_referer( "simple-page-ordering-nonce-move-{$post->ID}", 'spo_nonce' );
if ( ! current_user_can( 'edit_post', $post->ID ) ) {
wp_die( esc_html__( 'You are not allowed to edit this item.', 'simple-page-ordering' ) );
}
list( 'top_level_pages' => $top_level_pages, 'children_pages' => $children_pages ) = self::get_walked_pages( $post->post_type );
// Get the relevant siblings.
if ( 0 === $post->post_parent ) {
$siblings = $top_level_pages;
} else {
$siblings = $children_pages[ $post->post_parent ];
}
// Check if the post being moved is a top level page.
$filtered_siblings = wp_list_filter( $siblings, array( 'ID' => $post->ID ) );
if ( empty( $filtered_siblings ) ) {
// Something went wrong. Do nothing.
self::redirect_to_referer();
}
// Find the previous page in the sibling tree
$key = array_key_first( $filtered_siblings );
if ( 0 === $key ) {
// It's the first page. Do nothing.
self::redirect_to_referer();
}
$previous_page = $siblings[ $key - 1 ];
$previous_page_id = $previous_page->ID;
// Update the post with the previous page as the parent.
wp_update_post(
array(
'ID' => $post->ID,
'post_parent' => $previous_page_id,
)
);
self::redirect_to_referer();
}
/**
* Redirect the user after modifying the post parent.
*/
public static function redirect_to_referer() {
global $post_type;
$send_back = wp_get_referer();
if ( ! $send_back ||
str_contains( $send_back, 'post.php' ) ||
str_contains( $send_back, 'post-new.php' ) ) {
if ( 'attachment' === $post_type ) {
$send_back = admin_url( 'upload.php' );
} else {
$send_back = admin_url( 'edit.php' );
if ( ! empty( $post_type ) ) {
$send_back = add_query_arg( 'post_type', $post_type, $send_back );
}
}
} else {
$send_back = remove_query_arg( array( 'trashed', 'untrashed', 'deleted', 'ids' ), $send_back );
}
wp_safe_redirect( $send_back );
exit;
}
/**
* Walk the pages and return top level and children pages.
*
* @param string $post_type Post type to walk.
*
* @return array {
* @type WP_Post[] $top_level_pages Top level pages.
* @type WP_Post[] $children_pages Children pages.
* }
*/
public static function get_walked_pages( $post_type = 'page' ) {
global $wpdb;
$pages = get_pages(
array(
'sort_column' => 'menu_order title',
'post_type' => $post_type,
)
);
$top_level_pages = array();
$children_pages = array();
$bad_parents = array();
foreach ( $pages as $page ) {
// Catch and repair bad pages.
if ( $page->post_parent === $page->ID ) {
$page->post_parent = 0;
$wpdb->update( $wpdb->posts, array( 'post_parent' => 0 ), array( 'ID' => $page->ID ) );
clean_post_cache( $page );
$bad_parents[] = $page->ID;
}
if ( $page->post_parent > 0 ) {
$children_pages[ $page->post_parent ][] = $page;
} else {
$top_level_pages[] = $page;
}
}
// Reprime post cache for bad parents.
_prime_post_caches( $bad_parents, false, false );
return array(
'top_level_pages' => $top_level_pages,
'children_pages' => $children_pages,
);
}
/**
* Loads the plugin textdomain
*/
public static function load_textdomain() {
load_plugin_textdomain( 'simple-page-ordering', false, dirname( plugin_basename( __FILE__ ) ) . '/localization/' );
}
/**
* Determine whether given post type is sortable or not.
*
* @param string $post_type Post type to check.
*
* @return boolean
*/
private static function is_post_type_sortable( $post_type = 'post' ) {
$sortable = ( post_type_supports( $post_type, 'page-attributes' ) || is_post_type_hierarchical( $post_type ) );
/**
* Change default ordering support for a post type.
*
* @since 2.0.0
*
* @param boolean $sortable Whether this post type is sortable or not.
* @param string $post_type The post type being checked.
*/
return apply_filters( 'simple_page_ordering_is_sortable', $sortable, $post_type );
}
/**
* Load up page ordering scripts for the edit screen
*/
public static function load_edit_screen() {
$screen = get_current_screen();
$post_type = $screen->post_type;
// is post type sortable?
$sortable = self::is_post_type_sortable( $post_type );
if ( ! $sortable ) {
return;
}
// does user have the right to manage these post objects?
if ( ! self::check_edit_others_caps( $post_type ) ) {
return;
}
// add view by menu order to views
add_filter(
'views_' . $screen->id,
array(
__CLASS__,
'sort_by_order_link',
)
);
add_action( 'pre_get_posts', array( __CLASS__, 'filter_query' ) );
add_action( 'wp', array( __CLASS__, 'wp' ) );
add_action( 'admin_head', array( __CLASS__, 'admin_head' ) );
add_action( 'page_row_actions', array( __CLASS__, 'page_row_actions' ), 10, 2 );
}
/**
* This is to enable pagination.
*
* @param WP_Query $query The WP_Query instance (passed by reference).
*/
public static function filter_query( $query ) {
if ( ! $query->is_main_query() ) {
return;
}
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$is_simple_page_ordering = isset( $_GET['id'] ) ? 'simple-page-ordering' === $_GET['id'] : false;
if ( ! $is_simple_page_ordering ) {
return;
}
$query->set( 'posts_per_page', -1 );
}
/**
* when we load up our posts query, if we're actually sorting by menu order, initialize sorting scripts
*/
public static function wp() {
$orderby = get_query_var( 'orderby' );
$screen = get_current_screen();
$post_type = $screen->post_type ?? 'post';
if ( ( is_string( $orderby ) && 0 === strpos( $orderby, 'menu_order' ) ) || ( isset( $orderby['menu_order'] ) && 'ASC' === $orderby['menu_order'] ) ) {
$script_name = 'dist/js/simple-page-ordering.js';
$script_asset_path = plugin_dir_path( __FILE__ ) . 'dist/js/simple-page-ordering.asset.php';
$script_asset = file_exists( $script_asset_path )
? require $script_asset_path
: false;
if ( false !== $script_asset ) {
$script_url = plugins_url( $script_name, __FILE__ );
wp_enqueue_script( 'simple-page-ordering', $script_url, $script_asset['dependencies'], $script_asset['version'], true );
wp_localize_script(
'simple-page-ordering',
'simple_page_ordering_localized_data',
array(
'_wpnonce' => wp_create_nonce( 'simple-page-ordering-nonce' ),
/* translators: %1$s is replaced with the post type name */
'confirmation_msg' => sprintf( esc_html__( 'Are you sure you want to reset the ordering of the "%1$s" post type?', 'simple-page-ordering' ), $post_type ),
)
);
wp_enqueue_style( 'simple-page-ordering', plugins_url( '/dist/css/simple-page-ordering.css', __FILE__ ), [], $script_asset['version'] );
} else {
add_action(
'admin_notices',
function () {
?>
<div class="notice notice-warning is-dismissible">
<p><?php echo wp_kses_post( __( 'It looks like you are using a development copy of <strong>Simple Page Ordering</strong>. Please run <code>npm i; npm run build</code> to create assets.', 'simple-page-ordering' ) ); ?></p>
</div>
<?php
}
);
}
}
}
/**
* Add page ordering help to the help tab
*/
public static function admin_head() {
$screen = get_current_screen();
$post_type = $screen->post_type ?? 'post';
$screen->add_help_tab(
array(
'id' => 'simple_page_ordering_help_tab',
'title' => esc_html__( 'Simple Page Ordering', 'simple-page-ordering' ),
'content' => sprintf(
'<p>%s</p><a href="#" id="simple-page-ordering-reset" data-posttype="%s">%s</a>',
esc_html__( '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' ),
esc_attr( get_query_var( 'post_type' ) ),
/* translators: %1$s is replaced with the post type name */
sprintf( esc_html__( 'Reset %1$s order', 'simple-page-ordering' ), $post_type )
),
)
);
}
/**
* Modify the row actions for hierarchical post types.
*
* This adds the actions to change the parent/child relationships.
*
* @param array $actions An array of row action links.
* @param WP_Post $post The post object.
*/
public static function page_row_actions( $actions, $post ) {
$post = get_post( $post );
if ( ! $post ) {
return $actions;
}
if ( ! current_user_can( 'edit_post', $post->ID ) ) {
return $actions;
}
list( 'top_level_pages' => $top_level_pages, 'children_pages' => $children_pages ) = self::get_walked_pages( $post->post_type );
$edit_link = get_edit_post_link( $post->ID, 'raw' );
$move_under_grandparent_link = add_query_arg(
array(
'action' => 'spo-move-under-grandparent',
'spo_nonce' => wp_create_nonce( "simple-page-ordering-nonce-move-{$post->ID}" ),
'post_type' => $post->post_type,
),
$edit_link
);
$move_under_sibling_link = add_query_arg(
array(
'action' => 'spo-move-under-sibling',
'spo_nonce' => wp_create_nonce( "simple-page-ordering-nonce-move-{$post->ID}" ),
'post_type' => $post->post_type,
),
$edit_link
);
$parent_id = $post->post_parent;
if ( $parent_id ) {
$actions['spo-move-under-grandparent'] = sprintf(
'<a href="%s">%s</a>',
esc_url( $move_under_grandparent_link ),
sprintf(
/* translators: %s: parent page/post title */
__( 'Move out from under %s', 'simple-page-ordering' ),
get_the_title( $parent_id )
)
);
}
// Get the relevant siblings.
if ( 0 === $post->post_parent ) {
$siblings = $top_level_pages;
} else {
$siblings = $children_pages[ $post->post_parent ] ?? [];
}
// Assume no sibling.
$sibling = 0;
// Check if the post being moved is a top level page.
$filtered_siblings = wp_list_filter( $siblings, array( 'ID' => $post->ID ) );
if ( ! empty( $filtered_siblings ) ) {
// Find the previous page in the sibling tree
$key = array_key_first( $filtered_siblings );
if ( 0 === $key ) {
// It's the first page, can't do anything.
$sibling = 0;
} else {
$previous_page = $siblings[ $key - 1 ];
$sibling = $previous_page->ID;
}
}
if ( $sibling ) {
$actions['spo-move-under-sibling'] = sprintf(
'<a href="%s">%s</a>',
esc_url( $move_under_sibling_link ),
sprintf(
/* translators: %s: sibling page/post title */
__( 'Move under %s', 'simple-page-ordering' ),
get_the_title( $sibling )
)
);
}
return $actions;
}
/**
* Page ordering ajax callback
*
* @return void
*/
public static function ajax_simple_page_ordering() {
// check and make sure we have what we need
if ( empty( $_POST['id'] ) || ( ! isset( $_POST['previd'] ) && ! isset( $_POST['nextid'] ) ) ) {
die( - 1 );
}
$nonce = isset( $_POST['_wpnonce'] ) ? sanitize_key( wp_unslash( $_POST['_wpnonce'] ) ) : '';
if ( ! wp_verify_nonce( $nonce, 'simple-page-ordering-nonce' ) ) {
die( -1 );
}
$post_id = empty( $_POST['id'] ) ? false : (int) $_POST['id'];
$previd = empty( $_POST['previd'] ) ? false : (int) $_POST['previd'];
$nextid = empty( $_POST['nextid'] ) ? false : (int) $_POST['nextid'];
$start = empty( $_POST['start'] ) ? 1 : (int) $_POST['start'];
$excluded = empty( $_POST['excluded'] ) ? array( $_POST['id'] ) : array_filter( (array) json_decode( $_POST['excluded'] ), 'intval' );
// real post?
$post = empty( $post_id ) ? false : get_post( (int) $post_id );
if ( ! $post ) {
die( - 1 );
}
// does user have the right to manage these post objects?
if ( ! self::check_edit_others_caps( $post->post_type ) ) {
die( - 1 );
}
$result = self::page_ordering( $post_id, $previd, $nextid, $start, $excluded );
if ( is_wp_error( $result ) ) {
die( -1 );
}
die( wp_json_encode( $result ) );
}
/**
* Page ordering reset ajax callback
*
* @return void
*/
public static function ajax_reset_simple_page_ordering() {
global $wpdb;
$nonce = isset( $_POST['_wpnonce'] ) ? sanitize_key( wp_unslash( $_POST['_wpnonce'] ) ) : '';
if ( ! wp_verify_nonce( $nonce, 'simple-page-ordering-nonce' ) ) {
die( -1 );
}
// check and make sure we have what we need
$post_type = isset( $_POST['post_type'] ) ? sanitize_text_field( wp_unslash( $_POST['post_type'] ) ) : '';
if ( empty( $post_type ) ) {
die( -1 );
}
// does user have the right to manage these post objects?
if ( ! self::check_edit_others_caps( $post_type ) ) {
die( -1 );
}
// reset the order of all posts of given post type
$wpdb->update( 'wp_posts', array( 'menu_order' => 0 ), array( 'post_type' => $post_type ), array( '%d' ), array( '%s' ) );
die( 0 );
}
/**
* Page ordering function
*
* @param int $post_id The post ID.
* @param int $previd The previous post ID.
* @param int $nextid The next post ID.
* @param int $start The start index.
* @param array $excluded Array of post IDs.
*
* @return object|WP_Error|"children"
*/
public static function page_ordering( $post_id, $previd, $nextid, $start, $excluded ) {
// real post?
$post = empty( $post_id ) ? false : get_post( (int) $post_id );
if ( ! $post ) {
return new WP_Error( 'invalid', __( 'Missing mandatory parameters.', 'simple-page-ordering' ) );
}
// Badly written plug-in hooks for save post can break things.
if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
error_reporting( 0 ); // phpcs:ignore
}
global $wp_version;
$previd = empty( $previd ) ? false : (int) $previd;
$nextid = empty( $nextid ) ? false : (int) $nextid;
$start = empty( $start ) ? 1 : (int) $start;
$excluded = empty( $excluded ) ? array( $post_id ) : array_filter( (array) $excluded, 'intval' );
$new_pos = array(); // store new positions for ajax
$return_data = new stdClass();
do_action( 'simple_page_ordering_pre_order_posts', $post, $start );
// attempt to get the intended parent... if either sibling has a matching parent ID, use that
$parent_id = $post->post_parent;
$next_post_parent = $nextid ? wp_get_post_parent_id( $nextid ) : false;
if ( $previd === $next_post_parent ) { // if the preceding post is the parent of the next post, move it inside
$parent_id = $next_post_parent;
} elseif ( $next_post_parent !== $parent_id ) { // otherwise, if the next post's parent isn't the same as our parent, we need to study
$prev_post_parent = $previd ? wp_get_post_parent_id( $previd ) : false;
if ( $prev_post_parent !== $parent_id ) { // if the previous post is not our parent now, make it so!
$parent_id = ( false !== $prev_post_parent ) ? $prev_post_parent : $next_post_parent;
}
}
// if the next post's parent isn't our parent, it might as well be false (irrelevant to our query)
if ( $next_post_parent !== $parent_id ) {
$nextid = false;
}
$max_sortable_posts = (int) apply_filters( 'simple_page_ordering_limit', 50 ); // should reliably be able to do about 50 at a time
if ( $max_sortable_posts < 5 ) { // don't be ridiculous!
$max_sortable_posts = 50;
}
// we need to handle all post stati, except trash (in case of custom stati)
$post_stati = get_post_stati(
array(
'show_in_admin_all_list' => true,
)
);
$siblings_query = array(
'depth' => 1,
'posts_per_page' => $max_sortable_posts,
'post_type' => $post->post_type,
'post_status' => $post_stati,
'post_parent' => $parent_id,
'post__not_in' => $excluded, // phpcs:ignore
'orderby' => array(
'menu_order' => 'ASC',
'title' => 'ASC',
),
'update_post_term_cache' => false,
'update_post_meta_cache' => false,
'suppress_filters' => true, // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.SuppressFiltersTrue
'ignore_sticky_posts' => true,
);
if ( version_compare( $wp_version, '4.0', '<' ) ) {
$siblings_query['orderby'] = 'menu_order title';
$siblings_query['order'] = 'ASC';
}
$siblings = new WP_Query( $siblings_query ); // fetch all the siblings (relative ordering)
// don't waste overhead of revisions on a menu order change (especially since they can't *all* be rolled back at once)
remove_action( 'post_updated', 'wp_save_post_revision' );
foreach ( $siblings->posts as $sibling ) :
// don't handle the actual post
if ( $sibling->ID === $post->ID ) {
continue;
}
// if this is the post that comes after our repositioned post, set our repositioned post position and increment menu order
if ( $nextid === $sibling->ID ) {
wp_update_post(
array(
'ID' => $post->ID,
'menu_order' => $start,
'post_parent' => $parent_id,
)
);
$ancestors = get_post_ancestors( $post->ID );
$new_pos[ $post->ID ] = array(
'menu_order' => $start,
'post_parent' => $parent_id,
'depth' => count( $ancestors ),
);
$start ++;
}
// if repositioned post has been set, and new items are already in the right order, we can stop
if ( isset( $new_pos[ $post->ID ] ) && $sibling->menu_order >= $start ) {
$return_data->next = false;
break;
}
// set the menu order of the current sibling and increment the menu order
if ( $sibling->menu_order !== $start ) {
wp_update_post(
array(
'ID' => $sibling->ID,
'menu_order' => $start,
)
);
}
$new_pos[ $sibling->ID ] = $start;
$start ++;
if ( ! $nextid && $previd === $sibling->ID ) {
wp_update_post(
array(
'ID' => $post->ID,
'menu_order' => $start,
'post_parent' => $parent_id,
)
);
$ancestors = get_post_ancestors( $post->ID );
$new_pos[ $post->ID ] = array(
'menu_order' => $start,
'post_parent' => $parent_id,
'depth' => count( $ancestors ),
);
$start ++;
}
endforeach;
// max per request
if ( ! isset( $return_data->next ) && $siblings->max_num_pages > 1 ) {
$return_data->next = array(
'id' => $post->ID,
'previd' => $previd,
'nextid' => $nextid,
'start' => $start,
'excluded' => array_merge( array_keys( $new_pos ), $excluded ),
);
} else {
$return_data->next = false;
}
do_action( 'simple_page_ordering_ordered_posts', $post, $new_pos );
if ( ! $return_data->next ) {
// if the moved post has children, we need to refresh the page (unless we're continuing)
$children = new WP_Query(
array(
'posts_per_page' => 1,
'post_type' => $post->post_type,
'post_status' => $post_stati,
'post_parent' => $post->ID,
'fields' => 'ids',
'update_post_term_cache' => false,
'update_post_meta_cache' => false,
'ignore_sticky' => true,
'no_found_rows' => true,
)
);
if ( $children->have_posts() ) {
return 'children';
}
}
$return_data->new_pos = $new_pos;
return $return_data;
}
/**
* Append a sort by order link to the post actions
*
* @param array $views An array of available list table views.
*
* @return array
*/
public static function sort_by_order_link( $views ) {
$class = ( get_query_var( 'orderby' ) === 'menu_order title' ) ? 'current' : '';
$query_string = remove_query_arg( array( 'orderby', 'order' ) );
if ( ! is_post_type_hierarchical( get_post_type() ) ) {
$query_string = add_query_arg( 'orderby', 'menu_order title', $query_string );
$query_string = add_query_arg( 'order', 'asc', $query_string );
$query_string = add_query_arg( 'id', 'simple-page-ordering', $query_string );
}
$views['byorder'] = sprintf( '<a href="%s" class="%s">%s</a>', esc_url( $query_string ), $class, __( 'Sort by Order', 'simple-page-ordering' ) );
return $views;
}
/**
* Checks to see if the current user has the capability to "edit others" for a post type
*
* @param string $post_type Post type name
*
* @return bool True or false
*/
private static function check_edit_others_caps( $post_type ) {
$post_type_object = get_post_type_object( $post_type );
$edit_others_cap = empty( $post_type_object ) ? 'edit_others_' . $post_type . 's' : $post_type_object->cap->edit_others_posts;
return apply_filters( 'simple_page_ordering_edit_rights', current_user_can( $edit_others_cap ), $post_type );
}
/**
* Registers the API endpoint for sorting from the REST endpoint
*/
public static function rest_api_init() {
register_rest_route(
'simple-page-ordering/v1',
'page_ordering',
[
'methods' => 'POST',
'callback' => array( __CLASS__, 'rest_page_ordering' ),
'permission_callback' => array( __CLASS__, 'rest_page_ordering_permissions_check' ),
'args' => [
'id' => [
'description' => __( 'ID of item we want to sort', 'simple-page-ordering' ),
'required' => true,
'type' => 'integer',
'minimum' => 1,
],
'previd' => [
'description' => __( 'ID of item we want to be previous to after sorting', 'simple-page-ordering' ),
'required' => true,
'type' => [ 'boolean', 'integer' ],
],
'nextid' => [
'description' => __( 'ID of item we want to be next to after sorting', 'simple-page-ordering' ),
'required' => true,
'type' => [ 'boolean', 'integer' ],
],
'start' => [
'default' => 1,
'description' => __( 'Index we start with when sorting', 'simple-page-ordering' ),
'required' => false,
'type' => 'integer',
],
'exclude' => [
'default' => [],
'description' => __( 'Array of IDs we want to exclude', 'simple-page-ordering' ),
'required' => false,
'type' => 'array',
'items' => [
'type' => 'integer',
],
],
],
]
);
}
/**
* Check if a given request has access to reorder content.
*
* This check ensures the current user making the request has
* proper permissions to edit the item, that the post type
* is allowed in REST requests and the post type is sortable.
*
* @since 2.5.1
*
* @param WP_REST_Request $request Full data about the request.
* @return bool|WP_Error
*/
public static function rest_page_ordering_permissions_check( \WP_REST_Request $request ) {
$post_id = $request->get_param( 'id' );
// Ensure we have a logged in user that can edit the item.
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return false;
}
$post_type = get_post_type( $post_id );
$post_type_obj = get_post_type_object( $post_type );
// Ensure the post type is allowed in REST endpoints.
if ( ! $post_type || empty( $post_type_obj ) || empty( $post_type_obj->show_in_rest ) ) {
return false;
}
// Ensure this post type is sortable.
if ( ! self::is_post_type_sortable( $post_type ) ) {
return new WP_Error( 'not_enabled', esc_html__( 'This post type is not sortable.', 'simple-page-ordering' ) );
}
return true;
}
/**
* Handle REST page sorting
*
* @param WP_REST_Request $request The REST request object.
*/
public static function rest_page_ordering( \WP_REST_Request $request ) {
$post_id = empty( $request->get_param( 'id' ) ) ? false : (int) $request->get_param( 'id' );
$previd = empty( $request->get_param( 'previd' ) ) ? false : (int) $request->get_param( 'previd' );
$nextid = empty( $request->get_param( 'nextid' ) ) ? false : (int) $request->get_param( 'nextid' );
$start = empty( $request->get_param( 'start' ) ) ? 1 : (int) $request->get_param( 'start' );
$excluded = empty( $request->get_param( 'excluded' ) ) ? array( $request->get_param( 'id' ) ) : array_filter( (array) json_decode( $request->get_param( 'excluded' ) ), 'intval' );
// Check and make sure we have what we need.
if ( false === $post_id || ( false === $previd && false === $nextid ) ) {
return new WP_Error( 'invalid', __( 'Missing mandatory parameters.', 'simple-page-ordering' ) );
}
$page_ordering = self::page_ordering( $post_id, $previd, $nextid, $start, $excluded );
if ( is_wp_error( $page_ordering ) ) {
return $page_ordering;
}
return new WP_REST_Response(
array(
'status' => 200,
'response' => 'success',
'body_response' => $page_ordering,
)
);
}
}
Simple_Page_Ordering::get_instance();
endif;
@@ -0,0 +1 @@
.wp-list-table .ui-sortable tr{cursor:move}.wp-list-table .spo-updating tr,.wp-list-table .ui-sortable tr.inline-editor{cursor:default}.wp-list-table .ui-sortable-placeholder{background:#f1f1f1;outline:1px dashed #bbb;visibility:visible!important}.wp-list-table .ui-sortable-helper{background-color:#fff;outline:1px solid #e1e1e1}.spo-updating-row .check-column{background-position:9px 9px;display:table-cell;float:none;margin:0}.spo-updating-row .check-column input{visibility:hidden}
@@ -0,0 +1 @@
<?php return array('dependencies' => array('jquery-ui-sortable', 'wp-html-entities'), 'version' => '445f49ebf38f83eb9552');
@@ -0,0 +1 @@
!function(){"use strict";var e=window.wp.htmlEntities;window["jquery-ui-sortable"];const t=jQuery(".wp-list-table tbody");function n(o){if("children"===o)return void window.location.reload();const i=jQuery.parseJSON(o),{new_pos:r}=i;for(const t in r){if("next"===t)continue;const n=document.getElementById(`inline_${t}`);if(null!==n&&r.hasOwnProperty(t)){const o=n.querySelector(".menu_order");if(void 0!==r[t].menu_order){null!==o&&(o.textContent=r[t].menu_order);const i=n.querySelector(".post_parent");null!==i&&(i.textContent=r[t].post_parent);let l=null;const a=n.querySelector(".post_title");null!==a&&(l=a.innerHTML);let s=0;for(;s<r[t].depth;)l=`&mdash; ${l}`,s++;const d=n.parentNode.querySelector(".row-title");null!==d&&null!==l&&(d.textContent=(0,e.decodeEntities)(l))}else null!==o&&(o.textContent=r[t])}}i.next?jQuery.post(window.ajaxurl,{action:"simple_page_ordering",id:i.next.id,previd:i.next.previd,nextid:i.next.nextid,start:i.next.start,_wpnonce:window.simple_page_ordering_localized_data._wpnonce,excluded:JSON.stringify(i.next.excluded)},n):(jQuery(".spo-updating-row").removeClass("spo-updating-row").find(".check-column").removeClass("spinner is-active"),t.removeClass("spo-updating").sortable("enable"))}t.sortable({items:"> tr",cursor:"move",axis:"y",containment:"table.widefat",cancel:"input, textarea, button, select, option, .inline-edit-row",distance:2,opacity:.8,tolerance:"pointer",create(){jQuery(document).keydown((function(e){const n=e.key||e.keyCode;"Escape"!==n&&"Esc"!==n&&27!==n||(t.sortable("option","preventUpdate",!0),t.sortable("cancel"))}))},start(e,t){"undefined"!==typeof inlineEditPost&&inlineEditPost.revert(),t.placeholder.height(t.item.height()),t.placeholder.empty()},helper(e,t){const n=t.children();for(let e=0;e<n.length;e++){const t=jQuery(n[e]);t.width(t.width())}return t},stop(e,n){t.sortable("option","preventUpdate")&&t.sortable("option","preventUpdate",!1),n.item.children().css("width","")},update(e,o){if(t.sortable("option","preventUpdate"))return void t.sortable("option","preventUpdate",!1);t.sortable("disable").addClass("spo-updating"),o.item.addClass("spo-updating-row"),o.item.find(".check-column").addClass("spinner is-active");const i=o.item[0].id.substr(5);let r=!1;const l=o.item.prev();l.length>0&&(r=l.attr("id").substr(5));let a=!1;const s=o.item.next();s.length>0&&(a=s.attr("id").substr(5)),jQuery.post(window.ajaxurl,{action:"simple_page_ordering",id:i,previd:r,nextid:a,_wpnonce:window.simple_page_ordering_localized_data._wpnonce},n);const d=document.querySelectorAll("tr.iedit");let p=d.length;for(;p--;)p%2===0?jQuery(d[p]).addClass("alternate"):jQuery(d[p]).removeClass("alternate")}}),jQuery((function(){jQuery("#simple-page-ordering-reset").on("click",(function(e){e.preventDefault();const t=jQuery(this).data("posttype");window.confirm(window.simple_page_ordering_localized_data.confirmation_msg)&&jQuery.post(window.ajaxurl,{action:"reset_simple_page_ordering",post_type:t,_wpnonce:window.simple_page_ordering_localized_data._wpnonce},(function(){window.location.reload()}))}))}))}();
@@ -0,0 +1,108 @@
# Copyright (C) 2025 10up
# This file is distributed under the GPLv2 or later.
msgid ""
msgstr ""
"Project-Id-Version: Simple Page Ordering 2.7.4\n"
"Report-Msgid-Bugs-To: "
"https://wordpress.org/support/plugin/simple-page-ordering\n"
"POT-Creation-Date: 2025-05-19 15:00:02+00:00\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: 2025-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"X-Generator: node-wp-i18n 1.2.7\n"
#: class-simple-page-ordering.php:78 class-simple-page-ordering.php:124
msgid "You are not allowed to edit this item."
msgstr ""
#: class-simple-page-ordering.php:343
#. translators: %1$s is replaced with the post type name
msgid "Are you sure you want to reset the ordering of the \"%1$s\" post type?"
msgstr ""
#: class-simple-page-ordering.php:354
msgid ""
"It looks like you are using a development copy of <strong>Simple Page "
"Ordering</strong>. Please run <code>npm i; npm run build</code> to create "
"assets."
msgstr ""
#. Plugin Name of the plugin/theme
msgid "Simple Page Ordering"
msgstr ""
#: class-simple-page-ordering.php:376
msgid ""
"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."
msgstr ""
#: class-simple-page-ordering.php:379
#. translators: %1$s is replaced with the post type name
msgid "Reset %1$s order"
msgstr ""
#: class-simple-page-ordering.php:430
#. translators: %s: parent page/post title
msgid "Move out from under %s"
msgstr ""
#: class-simple-page-ordering.php:465
#. translators: %s: sibling page/post title
msgid "Move under %s"
msgstr ""
#: class-simple-page-ordering.php:564 class-simple-page-ordering.php:879
msgid "Missing mandatory parameters."
msgstr ""
#: class-simple-page-ordering.php:762
msgid "Sort by Order"
msgstr ""
#: class-simple-page-ordering.php:794
msgid "ID of item we want to sort"
msgstr ""
#: class-simple-page-ordering.php:800
msgid "ID of item we want to be previous to after sorting"
msgstr ""
#: class-simple-page-ordering.php:805
msgid "ID of item we want to be next to after sorting"
msgstr ""
#: class-simple-page-ordering.php:811
msgid "Index we start with when sorting"
msgstr ""
#: class-simple-page-ordering.php:817
msgid "Array of IDs we want to exclude"
msgstr ""
#: class-simple-page-ordering.php:859
msgid "This post type is not sortable."
msgstr ""
#. Plugin URI of the plugin/theme
msgid "http://10up.com/plugins/simple-page-ordering-wordpress/"
msgstr ""
#. Description of the plugin/theme
msgid ""
"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."
msgstr ""
#. Author of the plugin/theme
msgid "10up"
msgstr ""
#. Author URI of the plugin/theme
msgid "https://10up.com"
msgstr ""
+221
View File
@@ -0,0 +1,221 @@
=== Simple Page Ordering ===
Contributors: 10up, jakemgold, welcher, helen, thinkoomph, jeffpaul
Donate link: http://10up.com/plugins/simple-page-ordering-wordpress/
Tags: order, re-order, ordering, page, menu order
Tested up to: 6.8
Stable tag: 2.7.4
License: GPLv2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Order your pages and other custom post types that support "page-attributes" with drag and drop right from the standard page list.
== Description ==
Order your pages, hierarchical custom post types, or custom post types with "page-attributes" with drag and drop right from the built in page list.
Drag and drop the page into the desired position. No new admin menus pages, no clunky, bolted on user interfaces. Drag and drop on the page or post-type screen.
The plug-in is "capabilities aware" - only users with the ability to edit others' pages (editors and administrators) will be able to reorder content.
Integrated help is included: click the "help" tab at the top right of the screen.
Please note that the plug-in is not compatible with Internet Explorer 7 and earlier, due to limitations within those browsers.
=== Contributing ===
We'd love to have you join in on development over on [GitHub](https://github.com/10up/simple-page-ordering).
== Installation ==
1. Install either via the WordPress.org plugin directory, or by uploading the files to your server.
1. Activate the plugin through the 'Plugins' menu in WordPress.
1. Get to work reordering your content!
== Frequently Asked Questions ==
= Why can't I reorder my posts? =
Generic posts are not displayed by menu order - they're displayed by chronology. You can theoretically add menu ordering to posts in your code (theme functions.php, plug-in) by using:
`add_post_type_support( 'post', 'page-attributes' );`
= Can I make my custom post type take advantage of this plug-in? =
Yep. When you register the post type, include the `page-attributes` feature in the support list. This will add a `Sort by Order` option to the filter links above the drop downs. Once you sort by order, you can drag and drop the content.
`'supports' => array( 'title', 'editor', 'page-attributes' ),`
Alternatively, when you register the post type, set `hierarchical` to `true` - hierarchical post types natively order by menu order.
You can also take advantage of the `simple_page_ordering_is_sortable` filter, which passes the result of the default check and the post type name, to override default behavior.
= I want my non-hierarchical post type to be sortable. Help! =
See the previous two answers - just add `page-attributes` to the list of supported post type features.
= I reordered my posts, but the order didn't change on the front end of my site! =
This plug-in doesn't change any *behavior* on the front end, it simply changes the menu order stored in WordPress.
If you want a list of pages or custom post types to display in that defined order, you must change the post query's `orderby` parameter to `menu_order` (if it's not already).
= I reordered my content, it seemed to work, but when I refreshed, it went back to the old order! =
This most likely means the AJAX request - the server side code - failed after you dropped the content into the new position. Some shared hosts aggressively time out and limit AJAX requests. Version 2.0 batches these requests so you can try reducing the number of items it updates on each request using a filter in your theme's functions.php or a custom plug-in:
`add_filter( 'simple_page_ordering_limit', function($number) { return 5; } );`
Where 5 is the number of items to batch on each request (the default is 50). Note that this example uses PHP 5.3+ callback functions, so if you're still on PHP 5.2, you'll need to add a traditional callback.
= What happened to the drop down box that let me change the number of items on each page in the admin? =
This feature is already built into WordPress natively, but a bit tucked away. If you pull down the "Screen Options" tab up top (on the list of post objects) there's a field where you can specify the number of items to show per page. I decided it was not a very good practice to duplicate this.
= How can I modify sortable post types? =
Post types can be included or excluded by using the `simple_page_ordering_is_sortable` filter.
For example, to exclude the `excluded_post_type` custom post type, add the following snippet in the theme function file or custom plugin:
`
add_filter( 'simple_page_ordering_is_sortable', function( $sortable, $post_type ) {
if ( 'excluded_post_type' === $post_type ) {
return false;
}
return $sortable;
}, 10, 2 );
`
To include the `include_post_type` custom post type, add the following snippet in the theme function file or custom plugin:
`
add_filter( 'simple_page_ordering_is_sortable', function( $sortable, $post_type ) {
if ( 'include_post_type' === $post_type ) {
return true;
}
return $sortable;
}, 10, 2 );
`
= Can I use REST to order posts? =
Yes. The plugin registers the REST endpoint `simple-page-ordering/v1/page_ordering`.
== Screenshots ==
1. Dragging the page to its new position
1. Processing indicator
== Changelog ==
= 2.7.4 - 2025-05-19 =
* **Changed:** Bump WordPress "tested up to" version 6.8 (props [@jeffpaul](https://github.com/jeffpaul) via [#239](https://github.com/10up/simple-page-ordering/pull/239), [#240](https://github.com/10up/simple-page-ordering/pull/240)).
* **Changed:** Bump WordPress minimum from 6.5 to 6.6 (props [@jeffpaul](https://github.com/jeffpaul) via [#239](https://github.com/10up/simple-page-ordering/pull/239)).
* **Security:** Bump `tar-fs` from 2.1.1 to 3.0.8 (props [@dependabot](https://github.com/apps/dependabot), [@peterwilsoncc](https://github.com/peterwilsoncc) via [#238](https://github.com/10up/simple-page-ordering/pull/238)).
* **Security:** Bump `@babel/runtime` from 7.23.9 to 7.27.0 (props [@dependabot](https://github.com/apps/dependabot), [@peterwilsoncc](https://github.com/peterwilsoncc) via [#237](https://github.com/10up/simple-page-ordering/pull/237)).
= 2.7.3 - 2025-03-11 =
* **Changed:** Bump WordPress "tested up to" version 6.7 (props [@sudip-md](https://github.com/sudip-md), [@godleman](https://github.com/godleman), [@jeffpaul](https://github.com/jeffpaul) via [#230](https://github.com/10up/simple-page-ordering/pull/230), [#231](https://github.com/10up/simple-page-ordering/pull/231)).
* **Changed:** Bump WordPress minimum from 6.4 to 6.5 (props [@sudip-md](https://github.com/sudip-md), [@godleman](https://github.com/godleman), [@jeffpaul](https://github.com/jeffpaul) via [#230](https://github.com/10up/simple-page-ordering/pull/230), [#231](https://github.com/10up/simple-page-ordering/pull/231)).
* **Security:** Bump `webpack` from 5.90.0 to 5.94.0 (props [@dependabot](https://github.com/apps/dependabot), [@faisal-alvi](https://github.com/faisal-alvi) via [#224](https://github.com/10up/simple-page-ordering/pull/224)).
* **Security:** Bump `serve-static` from 1.15.0 to 1.16.2 and `express` from 4.19.2 to 4.21.0 (props [@dependabot](https://github.com/apps/dependabot), [@peterwilsoncc](https://github.com/peterwilsoncc) via [#226](https://github.com/10up/simple-page-ordering/pull/226)).
* **Security:** Bump `cookie` from 0.6.0 to 0.7.1 and `express` from 4.21.0 to 4.21.1 (props [@dependabot](https://github.com/apps/dependabot), [@Sidsector9](https://github.com/Sidsector9) via [#228](https://github.com/10up/simple-page-ordering/pull/228)).
* **Security:** Bump `serialize-javascript` from 6.0.0 to 6.0.2 and `mocha` from 10.2.0 to 11.1.0 (props [@dependabot](https://github.com/apps/dependabot), [@dkotter](https://github.com/dkotter) via [#232](https://github.com/10up/simple-page-ordering/pull/232)).
= 2.7.2 - 2024-08-21 =
* **Changed:** Bump WordPress "tested up to" version 6.6 (props [@sudip-md](https://github.com/sudip-md), [@ankitguptaindia](https://github.com/ankitguptaindia), [@jeffpaul](https://github.com/jeffpaul) via [#216](https://github.com/10up/simple-page-ordering/pull/216), [#217](https://github.com/10up/simple-page-ordering/pull/217)).
* **Changed:** Bump WordPress minimum from 6.3 to 6.4 (props [@sudip-md](https://github.com/sudip-md), [@ankitguptaindia](https://github.com/ankitguptaindia), [@jeffpaul](https://github.com/jeffpaul) via [#216](https://github.com/10up/simple-page-ordering/pull/216)).
* **Fixed:** Issue where an `Undefined array key` error occurs when a post parent ID does not exist in the `$children_pages` array (props [@xDehy](https://github.com/xDehy), [@peterwilsoncc](https://github.com/peterwilsoncc) via [#219](https://github.com/10up/simple-page-ordering/pull/219)).
* **Security:** Bump `express` from 4.18.2 to 4.19.2, `follow-redirects` from 1.15.5 to 1.15.6, `postcss` from 7.0.39 to 8.4.33, `10up-toolkit` from 5.2.3 to 6.1.0 and `webpack-dev-middleware` from 5.3.3 to 5.3.4 (props [@dependabot](https://github.com/apps/dependabot), [@faisal-alvi](https://github.com/faisal-alvi) via [#208](https://github.com/10up/simple-page-ordering/pull/208)).
* **Security:** Bump `braces` from 3.0.2 to 3.0.3 and `ws` from 7.5.9 to 7.5.10 (props [@dependabot](https://github.com/apps/dependabot), [@iamdharmesh](https://github.com/iamdharmesh) via [#214](https://github.com/10up/simple-page-ordering/pull/214)).
= 2.7.1 - 2024-06-03 =
* **Added:** The missing Text Domain (props [@alexclassroom](https://github.com/alexclassroom), [@dkotter](https://github.com/dkotter) via [#199](https://github.com/10up/simple-page-ordering/pull/199)).
* **Added:** The "Testing" section in the `CONTRIBUTING.md` file (props [@kmgalanakis](https://github.com/kmgalanakis), [@jeffpaul](https://github.com/jeffpaul) via [#202](https://github.com/10up/simple-page-ordering/pull/202)).
* **Changed:** Bump WordPress "tested up to" version 6.5 (props [@jeffpaul](https://github.com/jeffpaul), [@sudip-md](https://github.com/sudip-md), [@dkotter](https://github.com/dkotter) via [#201](https://github.com/10up/simple-page-ordering/pull/201)).
* **Changed:** Bump WordPress minimum from 5.7 to 6.3 (props [@jeffpaul](https://github.com/jeffpaul), [@sudip-md](https://github.com/sudip-md), [@dkotter](https://github.com/dkotter) via [#201](https://github.com/10up/simple-page-ordering/pull/201)).
* **Fixed:** Fixed error in call to `get_walked_pages` for custom post types (props [@sissibieber](https://github.com/sissibieber), [@zachgibb](https://github.com/zachgibb), [@peterwilsoncc](https://github.com/peterwilsoncc), [@mjot](https://github.com/mjot), [@jeffpaul](https://github.com/jeffpaul) via [#200](https://github.com/10up/simple-page-ordering/pull/200)).
= 2.7.0 - 2024-04-03 =
* **Added:** Ability to modify the page hierarchy (props [@amityweb](https://github.com/amityweb), [@jeffpaul](https://github.com/jeffpaul), [@peterwilsoncc](https://github.com/peterwilsoncc), [@shannonmfisher](https://github.com/shannonmfisher), [@ankitguptaindia](https://github.com/ankitguptaindia), [@faisal-alvi](https://github.com/faisal-alvi) via [#172](https://github.com/10up/simple-page-ordering/pull/172)).
* **Added:** Support for the WordPress.org plugin preview (props [@dkotter](https://github.com/dkotter), [@jeffpaul](https://github.com/jeffpaul) via [#183](https://github.com/10up/simple-page-ordering/pull/183)).
* **Changed:** Replaced custom HTML entity decoding code in favor of the `@wordpress/html-entities` package (props [@helen](https://github.com/helen), [@jeffpaul](https://github.com/jeffpaul), [@psorensen](https://github.com/psorensen), [@peterwilsoncc](https://github.com/peterwilsoncc) via [#189](https://github.com/10up/simple-page-ordering/pull/189)).
* **Changed:** Bump minimum `node` version from `16` to `20` and clean up NPM dependencies (props [@Sidsector9](https://github.com/Sidsector9), [@dkotter](https://github.com/dkotter) via [#188](https://github.com/10up/simple-page-ordering/pull/188)).
* **Changed:** Updated CODEOWNERS (props [@jeffpaul](https://github.com/jeffpaul), [@dkotter](https://github.com/dkotter) via [#186](https://github.com/10up/simple-page-ordering/pull/186)).
* **Changed:** Upgrade the download-artifact from v3 to v4 (props [@iamdharmesh](https://github.com/iamdharmesh), [@jeffpaul](https://github.com/jeffpaul) via [#194](https://github.com/10up/simple-page-ordering/pull/194)).
* **Changed:** Replaced [lee-dohm/no-response](https://github.com/lee-dohm/no-response) with [actions/stale](https://github.com/actions/stale) to help with closing no-response/stale issues (props [@jeffpaul](https://github.com/jeffpaul), [@dkotter](https://github.com/dkotter) via [@195](https://github.com/10up/simple-page-ordering/pull/195)).
* **Changed:** Disabled auto sync pull requests with target branch (props [@iamdharmesh](https://github.com/iamdharmesh), [@jeffpaul](https://github.com/jeffpaul) via [#196](https://github.com/10up/simple-page-ordering/pull/196)).
* **Security:** Bump `@babel/traverse` from `7.20.12` to `7.23.6` (props [@dependabot](https://github.com/apps/dependabot), [@ravinderk](https://github.com/ravinderk) via [#184](https://github.com/10up/simple-page-ordering/pull/184)).
* **Security:** Bump `sharp` from `0.30.7` to `0.32.1` (props [@dependabot](https://github.com/apps/dependabot), [@Sidsector9](https://github.com/Sidsector9) via [#182](https://github.com/10up/simple-page-ordering/pull/184)).
* **Security:** Bump `10up-toolkit` from `4.3.1` to `5.2.2` (props [@dependabot](https://github.com/apps/dependabot), [@Sidsector9](https://github.com/Sidsector9) via [#182](https://github.com/10up/simple-page-ordering/pull/182)).
= 2.6.3 - 2023-11-09 =
* **Fix:** Deployment issue with version 2.6.2 (props [@Sidsector9](https://github.com/Sidsector9), [@dkotter](https://github.com/dkotter) via [#181](https://github.com/10up/simple-page-ordering/pull/181))
= 2.6.2 - 2023-11-09 =
* **Changed:** Update the `wp-compat-validation-tool` composer package to version `0.3.1` which properly removes the `.git` directory (props [@Sidsector9](https://github.com/Sidsector9), [@dkotter](https://github.com/dkotter) via [#180](https://github.com/10up/simple-page-ordering/pull/180)).
= 2.6.1 - 2023-11-08 =
* **Changed:** Bump WordPress "tested up to" version 6.4 (props [@jeffpaul](https://github.com/jeffpaul), [@qasumitbagthariya](https://github.com/qasumitbagthariya), [@faisal-alvi](https://github.com/faisal-alvi) via [#177](https://github.com/10up/simple-page-ordering/pull/177)).
* **Changed:** Remove the .git directory from the `10up-lib` directory (props [@Sidsector9](https://github.com/Sidsector9), [@dkotter](https://github.com/dkotter) via [#175](https://github.com/10up/simple-page-ordering/pull/175)).
* **Security:** Bumps `@babel/traverse` from `7.20.12` to `7.23.2` (props [@peterwilsoncc](https://github.com/peterwilsoncc) via [#170](https://github.com/10up/simple-page-ordering/pull/170)).
= 2.6.0 - 2023-10-25 =
* **Added:** A check for minimum required PHP version before loading the plugin (props [@vikrampm1](https://github.com/vikrampm1), [@kmgalanakis](https://github.com/kmgalanakis), [@Sidsector9](https://github.com/Sidsector9) via [#153](https://github.com/10up/simple-page-ordering/pull/153)).
* **Added:** Mochawesome reporter added for Cypress test report (props [@iamdharmesh](https://github.com/iamdharmesh), [@jayedul](https://github.com/jayedul), [@faisal-alvi](https://github.com/faisal-alvi) via [#146](https://github.com/10up/simple-page-ordering/pull/146)).
* **Added:** Repo Automator GitHub Action (props [@iamdharmesh](https://github.com/iamdharmesh), [@jeffpaul](https://github.com/jeffpaul) via [#158](https://github.com/10up/simple-page-ordering/pull/158)).
* **Changed:** Bump WordPress "tested up to" version 6.3 (props [@jeffpaul](https://github.com/jeffpaul), [@QAharshalkadu](https://github.com/QAharshalkadu)).
* **Changed:** Slightly change how some of our text is translated, passing in the post type (props [@dkotter](https://github.com/dkotter), [@ravinderk](https://github.com/ravinderk) via [#149](https://github.com/10up/simple-page-ordering/pull/149)).
* **Changed:** Updates the Dependency Review GitHub Action to check for GPL-compatible licenses (props [@jeffpaul](https://github.com/jeffpaul), [@Sidsector9](https://github.com/Sidsector9) via [#147](https://github.com/10up/simple-page-ordering/pull/147)).
* **Changed:** Updated 10up Cypress Utilities to 0.2.0 (props [@iamdharmesh](https://github.com/iamdharmesh), [@peterwilsoncc](https://github.com/peterwilsoncc) via [#160](https://github.com/10up/simple-page-ordering/pull/160)).
* **Fixed:** The "Are you sure..." popup text to be translatable (props [@kebbet](https://github.com/kebbet), [@bmarshall511](https://github.com/bmarshall511), [@dkotter](https://github.com/dkotter) via [#148](https://github.com/10up/simple-page-ordering/pull/148)).
* **Fixed:** Remove code that was no longer needed (props [@dkotter](https://github.com/dkotter), [@ravinderk](https://github.com/ravinderk) via [#149](https://github.com/10up/simple-page-ordering/pull/149)).
* **Fixed:** Add missing escaping (props [@dkotter](https://github.com/dkotter), [@ravinderk](https://github.com/ravinderk) via [#149](https://github.com/10up/simple-page-ordering/pull/149)).
* **Fixed:** Fatal error following the introduction of a namespace (props [@peterwilsoncc](https://github.com/peterwilsoncc), [@iamdharmesh](https://github.com/iamdharmesh), [@dkotter](https://github.com/dkotter) via [#162](https://github.com/10up/simple-page-ordering/pull/162)).
* **Fixed:** Hidden pagination in admin screen when Sort by Order is clicked (props [@tlovett1](https://github.com/tlovett1), [@dkotter](https://github.com/dkotter), [@Sidsector9](https://github.com/Sidsector9) via [#165](https://github.com/10up/simple-page-ordering/pull/165)).
* **Fixed:** Fatal errors on PHP 5.6 (props [@peterwilsoncc](https://github.com/peterwilsoncc), [@Sidsector9](https://github.com/Sidsector9), [@iamdharmesh](https://github.com/iamdharmesh) via [#166](https://github.com/10up/simple-page-ordering/pull/166)).
* **Security:** Bump `word-wrap` from 1.2.3 to 1.2.4 (props [@dependabot](https://github.com/apps/dependabot), [@peterwilsoncc](https://github.com/peterwilsoncc) via [#](https://github.com/10up/simple-page-ordering/pull/151)).
* **Security:** Bump `tough-cookie` from 4.1.2 to 4.1.3 (props [@faisal-alvi](https://github.com/faisal-alvi) via [#152](https://github.com/10up/simple-page-ordering/pull/152)).
* **Security:** Bump `node-sass` from 7.0.3 to 9.0.0 (props [@faisal-alvi](https://github.com/faisal-alvi) via [#152](https://github.com/10up/simple-page-ordering/pull/152)).
* **Security:** Bump `@cypress/request` from 2.88.11 to 3.0.0 to resolve SSRF issue (props [@faisal-alvi](https://github.com/faisal-alvi), [@iamdharmesh](https://github.com/iamdharmesh), [@peterwilsoncc](https://github.com/peterwilsoncc), [@dkotter](https://github.com/dkotter) via [#152](https://github.com/10up/simple-page-ordering/pull/152), [#160](https://github.com/10up/simple-page-ordering/pull/160)).
= 2.5.1 - 2023-05-16 =
* **Security:** Ensure we check user permissions properly in our REST endpoint (props [@mikhail-net](https://github.com/mikhail-net), [@dkotter](https://github.com/dkotter), [@peterwilsoncc](https://github.com/peterwilsoncc)).
= 2.5.0 - 2023-04-18 =
**Note that this release bumps the minimum required versions of PHP from 5.6 to 7.4 and WordPress from 3.8 to 5.7.**
* **Added:** Feature to reset page order (props [@pattonwebz](https://github.com/pattonwebz), [@ruscoe](https://github.com/ruscoe), [@Sidsector9](https://github.com/Sidsector9), [@dkotter](https://github.com/dkotter)) via [#129](https://github.com/10up/simple-page-ordering/pull/129).
* **Added** JS linting GitHub Action (props [@Sidsector9](https://github.com/Sidsector9), [@kmgalanakis](https://github.com/kmgalanakis), [@peterwilsoncc](https://github.com/peterwilsoncc)) via [#136](https://github.com/10up/simple-page-ordering/pull/136).
* **Changed:** Bump minimum PHP version to 7.4 (props [@vikrampm1](https://github.com/vikrampm1), [@Sidsector9](https://github.com/Sidsector9), [@ravinderk](https://github.com/ravinderk), [@cadic](https://github.com/cadic)) via [#111](https://github.com/10up/simple-page-ordering/pull/111).
* **Changed:** Bump minimum required WordPress version from 3.8 to 5.7 (props [@vikrampm1](https://github.com/vikrampm1), [@Sidsector9](https://github.com/Sidsector9), [@ravinderk](https://github.com/ravinderk), [@cadic](https://github.com/cadic)) via [#111](https://github.com/10up/simple-page-ordering/pull/111).
* **Changed:** Bump WordPress "tested up to" version 6.2 (props [@av3nger](https://github.com/av3nger) via [#138](https://github.com/10up/simple-page-ordering/pull/138)).
* **Changed:** Run E2E tests on the zip generated by "Build release zip" action (props [@iamdharmesh](https://github.com/iamdharmesh), [@jayedul](https://github.com/jayedul), [@dkotter](https://github.com/dkotter)) via [#135](https://github.com/10up/simple-page-ordering/pull/135).
* **Fixed:** Removed a typo in a REST response message (props [@ruscoe](https://github.com/ruscoe), [@Sidsector9](https://github.com/Sidsector9)) via [#133](https://github.com/10up/simple-page-ordering/pull/133).
* **Security:** Removed vulnerable NPM dependencies (props [@vikrampm1](https://github.com/vikrampm1), [@Sidsector9](https://github.com/Sidsector9), [@ravinderk](https://github.com/ravinderk), [@cadic](https://github.com/cadic)) via [#111](https://github.com/10up/simple-page-ordering/pull/111).
* **Security:** Bump `cypress` from `9.5.2` to `11.2.0` (props [@iamdharmesh](https://github.com/iamdharmesh), [@jayedul](https://github.com/jayedul), [@Sidsector9](https://github.com/Sidsector9)) via [#120](https://github.com/10up/simple-page-ordering/pull/120).
* **Security:** Bump `http-cache-semantics` from 4.1.0 to 4.1.1 (props [@peterwilsoncc](https://github.com/peterwilsoncc) via [#131](https://github.com/10up/simple-page-ordering/pull/131)).
* **Security:** Bump `webpack` from `5.75.0` to `5.76.1` (props [@Sidsector9](https://github.com/Sidsector9)) via [#134](https://github.com/10up/simple-page-ordering/pull/134).
= 2.4.4 - 2023-01-10 =
* **Changed:** Update Support Level from `Active` to `Stable` (props [@jeffpaul](https://github.com/jeffpaul), [@dkotter](https://github.com/dkotter) via [#123](https://github.com/10up/simple-page-ordering/pull/123)).
* **Changed:** Bump WordPress "tested up to" version to 6.1 (props [@jayedul](https://github.com/jayedul), [@dkotter](https://github.com/dkotter) via [#118](https://github.com/10up/simple-page-ordering/pull/118)).
* **Changed:** Update the "Build release zip" workflow to use 10up's `build-zip` action (props [@iamdharmesh](https://github.com/iamdharmesh), [@faisal-alvi](https://github.com/faisal-alvi), [@dkotter](https://github.com/dkotter) via [#119](https://github.com/10up/simple-page-ordering/pull/119)).
* **Security:** Bump `loader-utils` from 2.0.3 to 2.0.4 (props [@dependabot](https://github.com/apps/dependabot) via [#115](https://github.com/10up/simple-page-ordering/pull/115)).
* **Security:** Bump `simple-git` from 3.12.0 to 3.15.1 (props [@dependabot](https://github.com/apps/dependabot) via [#121](https://github.com/10up/simple-page-ordering/pull/121)).
[View historical changelog details here](https://github.com/10up/simple-page-ordering/blob/develop/CHANGELOG.md).
== Upgrade Notice ==
= 2.7.4 =
This release bumps the minimum required version of WordPress from 6.5 to 6.6.
= 2.7.3 =
This release bumps the minimum required version of WordPress from 6.4 to 6.5.
= 2.7.2 =
This release bumps the minimum required version of WordPress from 6.3 to 6.4.
= 2.5.0 =
This release bumps the minimum required versions of PHP from 5.6 to 7.4 and WordPress from 3.8 to 5.7.
@@ -0,0 +1,34 @@
<?php
/**
* Plugin Name: Simple Page Ordering
* Plugin URI: http://10up.com/plugins/simple-page-ordering-wordpress/
* 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.
* Version: 2.7.4
* Requires at least: 6.6
* Requires PHP: 7.4
* Author: 10up
* Author URI: https://10up.com
* License: GPLv2 or later
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
* Text Domain: simple-page-ordering
*
* @package simple-page-ordering
*/
if ( ! is_readable( __DIR__ . '/10up-lib/wp-compat-validation-tool/src/Validator.php' ) ) {
return;
}
// Useful global constants.
require_once '10up-lib/wp-compat-validation-tool/src/Validator.php';
$compat_checker = new \Simple_Page_Ordering_Validator\Validator();
$compat_checker
->set_plugin_name( 'Simple Page Ordering' )
->set_php_min_required_version( '7.4' );
if ( ! $compat_checker->is_plugin_compatible() ) {
return;
}
require_once 'class-simple-page-ordering.php';