diff --git a/.travis.yml b/.travis.yml index 991cdc9..f3c856a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,6 @@ language: php sudo: false php: - - 5.4 - - 5.5 - 5.6 - 7.0 - 7.1 diff --git a/admin/manager.php b/admin/manager.php index b1ab7df..a86db1f 100644 --- a/admin/manager.php +++ b/admin/manager.php @@ -126,37 +126,8 @@ public function add_scripts( $page ) { wp_register_script( 'bu-jquery-validate', $vendor_url . '/jquery.validate' . $suffix . '.js', array( 'jquery' ), '1.8.1', true ); wp_register_script( 'bu-navman', $scripts_url . '/manage' . $suffix . '.js', array( 'bu-navigation', 'jquery-ui-dialog', 'bu-jquery-validate' ), BU_Navigation_Plugin::VERSION, true ); - // Strings for localization - $nav_menu_label = __( 'Appearance > Primary Navigation', 'bu-navigation' ); - $strings = array( - 'optionsLabel' => __( 'options', 'bu-navigation' ), - 'optionsEditLabel' => __( 'Edit', 'bu-navigation' ), - 'optionsViewLabel' => __( 'View', 'bu-navigation' ), - 'optionsDeleteLabel' => __( 'Delete', 'bu-navigation' ), - 'optionsTrashLabel' => __( 'Move to Trash', 'bu-navigation' ), - 'addLinkDialogTitle' => __( 'Add a Link', 'bu-navigation' ), - 'editLinkDialogTitle' => __( 'Edit Link', 'bu-navigation' ), - 'cancelLinkBtn' => __( 'Cancel', 'bu-navigation' ), - 'confirmLinkBtn' => __( 'Ok', 'bu-navigation' ), - 'noTopLevelNotice' => __( 'You are not allowed to create top level published content.', 'bu-navigation' ), - 'noLinksNotice' => __( 'You are not allowed to add links', 'bu-navigation' ), - 'createLinkNotice' => __( 'Select a page that you can edit and click "Add a Link" to create a new link below the selected page.', 'bu-navigation' ), - 'allowTopNotice' => sprintf( __( 'Site administrators can change this behavior by visiting %s and enabling the "Allow Top-Level Pages" setting.', 'bu-navigation' ), $nav_menu_label ), - 'noChildLinkNotice' => __( 'Links are not permitted to have children.', 'bu-navigation' ), - 'unloadWarning' => __( 'You have made changes to your navigation that have not yet been saved.', 'bu-navigation' ), - 'saveNotice' => __( 'Saving navigation changes...', 'bu-navigation' ), - ); - - // Setup dynamic script context for manage.js - $script_context = array( - 'postTypes' => $this->post_type, - 'postStatuses' => array( 'publish', 'private' ), - 'nodePrefix' => 'nm', - 'lazyLoad' => true, - 'showCounts' => true, - ); // Navigation tree view will handle actual enqueuing of our script - $treeview = new BU_Navigation_Tree_View( 'bu_navman', array_merge( $script_context, $strings ) ); + $treeview = $this->get_navigation_tree(); $treeview->enqueue_script( 'bu-navman' ); // Register custom jQuery UI stylesheet if it isn't already @@ -174,13 +145,62 @@ public function add_scripts( $page ) { } + /** + * Get fully configured instance of BU_Navigation_Tree_View + */ + public function get_navigation_tree() { + // Strings for localization + $nav_menu_label = __( 'Appearance > Primary Navigation', 'bu-navigation' ); + $strings = array( + 'optionsLabel' => __( 'options', 'bu-navigation' ), + 'optionsEditLabel' => __( 'Edit', 'bu-navigation' ), + 'optionsViewLabel' => __( 'View', 'bu-navigation' ), + 'optionsDeleteLabel' => __( 'Delete', 'bu-navigation' ), + 'optionsTrashLabel' => __( 'Move to Trash', 'bu-navigation' ), + 'addLinkDialogTitle' => __( 'Add a Link', 'bu-navigation' ), + 'editLinkDialogTitle' => __( 'Edit Link', 'bu-navigation' ), + 'cancelLinkBtn' => __( 'Cancel', 'bu-navigation' ), + 'confirmLinkBtn' => __( 'Ok', 'bu-navigation' ), + 'noTopLevelNotice' => __( 'You are not allowed to create top level published content.', 'bu-navigation' ), + 'noLinksNotice' => __( 'You are not allowed to add links', 'bu-navigation' ), + 'createLinkNotice' => __( 'Select a page that you can edit and click "Add a Link" to create a new link below the selected page.', 'bu-navigation' ), + 'allowTopNotice' => sprintf( __( 'Site administrators can change this behavior by visiting %s and enabling the "Allow Top-Level Pages" setting.', 'bu-navigation' ), $nav_menu_label ), + 'noChildLinkNotice' => __( 'Links are not permitted to have children.', 'bu-navigation' ), + 'unloadWarning' => __( 'You have made changes to your navigation that have not yet been saved.', 'bu-navigation' ), + 'saveNotice' => __( 'Saving navigation changes...', 'bu-navigation' ), + ); + + // Setup dynamic script context for manage.js + $script_context = array( + 'postTypes' => $this->post_type, + 'postStatuses' => array( 'publish', 'private' ), + 'nodePrefix' => 'nm', + 'lazyLoad' => true, + 'showCounts' => true, + ); + + return new BU_Navigation_Tree_View( 'bu_navman', array_merge( $script_context, $strings ) ); + } + /** * Handle admin page setup */ public function load() { - // Save if post data is present - $saved = $this->save(); + if ( array_key_exists( 'navman-hash', $_POST ) ) { + $tree = $this->get_navigation_tree(); + $hash_stayed_same = $tree->hierarchy->as_hash() == $_POST['navman-hash']; + } + else { + $hash_stayed_same = true; + } + + if ( $hash_stayed_same ) { + $saved = $this->save(); + } + else { + $saved = false; + } // Post/Redirect/Get if ( ! is_null( $saved ) ) { @@ -189,8 +209,16 @@ public function load() { $url = remove_query_arg( array( 'message', 'notice' ), wp_get_referer() ); // Notifications - if ( $saved === true ) { $url = add_query_arg( 'message', 1, $url ); - } else { $url = add_query_arg( 'notice', 1, $url ); } + if ( $saved === true ) { + $url = add_query_arg( 'message', 1, $url ); + } else { + if ( ! $hash_stayed_same ) { + $url = add_query_arg( 'notice', 3, $url ); + } + else { + $url = add_query_arg( 'notice', 1, $url ); + } + } wp_redirect( $url ); @@ -232,6 +260,7 @@ public function setup_notices() { public function get_notice_by_code( $type, $code ) { $user_markup = '%s'; + $post_type = get_post_type_object( $this->post_type ); $notices = array( 'message' => array( @@ -242,6 +271,7 @@ public function get_notice_by_code( $type, $code ) { 0 => '', 1 => __( 'Errors occurred while saving your navigation changes.', 'bu-navigation' ), 2 => sprintf( __( "Warning: %s is currently editing this site's navigation.", 'bu-navigation' ), $user_markup ), + 3 => sprintf( __( '%s order has been modified by someone else. Please retry.', 'bu-navigation' ), $post_type->labels->singular_name), ), ); @@ -321,7 +351,7 @@ public function render() { $notices = $this->get_notice_list(); $include_links = $this->plugin->supports( 'links' ) && 'page' == $this->post_type; $disable_add_link = ! $this->can_publish_top_level( $this->post_type ); - + $tree = $this->get_navigation_tree(); // Render interface include( BU_NAV_PLUGIN_DIR . '/templates/edit-order.php' ); diff --git a/bu-navigation.php b/bu-navigation.php index e61dab0..930e1cc 100644 --- a/bu-navigation.php +++ b/bu-navigation.php @@ -5,7 +5,7 @@ Author: Boston University (IS&T) Author URI: http://sites.bu.edu/web/ Description: Provides alternative navigation elements designed for blogs with large page counts -Version: 1.2.13 +Version: 1.2.14 Text Domain: bu-navigation Domain Path: /languages */ @@ -60,7 +60,7 @@ class BU_Navigation_Plugin { // Plugin settings public $settings; - const VERSION = '1.2.13'; + const VERSION = '1.2.14'; public function __construct() { diff --git a/includes/class-tree-view.php b/includes/class-tree-view.php index eedf577..6e77194 100644 --- a/includes/class-tree-view.php +++ b/includes/class-tree-view.php @@ -12,6 +12,8 @@ class BU_Navigation_Tree_View { private $plugin; private $query; + + public $hierarchy; /** * Setup an object capable of creating the navigation management interface @@ -60,6 +62,7 @@ public function __construct( $instance = 'legacy', $script_context = array() ) { 'suppress_urls' => $this->settings['suppressUrls'] ); $this->query = new BU_Navigation_Tree_Query( $query_args ); + $this->hierarchy = new BU_Navigation_Tree_Hierarchy( $this->query ); // No need to register scripts during AJAX requests if( ! defined('DOING_AJAX') || ! DOING_AJAX ) { @@ -316,6 +319,66 @@ public function add_node_prefix( $id ) { } +/** + * Collection of methods that allow the page hierarchy be represented as + * a hash value. By comparing two hash values, we can tell if there were + * any changes in the hierarchy. + */ +class BU_Navigation_Tree_Hierarchy { + + /** + * Holds the BU_Navigation_Tree_Query instance passed into constructor. + */ + private $tree_query; + + /** + * Post properties that describe hierarchy. If any of these changed, + * the hierarchy changed. + */ + const HIERARCHICAL_PROPERTIES = array( 'ID', 'menu_order', 'post_parent' ); + + /** + * By taking the posts structure and leaving only hierarchy-related + * preperties of it, we get the object that stays the same as long as + * the post hierarchy stays the same. + * + * @return array Object that represents post tree hierarchy + */ + private function as_object() { + $hierarchy = $this->tree_query->posts_by_parent(); + foreach ( $hierarchy as $parent ) { + foreach ( $parent as $child ) { + foreach ( $child as $prop_name => $prop_value ) { + if ( ! in_array( $prop_name, self::HIERARCHICAL_PROPERTIES ) ) { + unset( $child->$prop_name ); + } + } + } + } + + return $hierarchy; + } + + /** + * Constructor. + */ + public function __construct( BU_Navigation_Tree_Query $tree_query ) { + $this->tree_query = $tree_query; + } + + /** + * Gets hashed representation of the BU_Navigation_Tree_Query instance + * passed into the constructor of this class. + * + * @return String hashed representation of the post hierarchy + */ + public function as_hash() { + $obj = $this->as_object(); + $str = json_encode( $obj ); + return md5( $str ); + } +} + /** * WP_Query-like class optimized for querying hierarchical post types * diff --git a/readme.md b/readme.md index 96dc004..e3b72e2 100644 --- a/readme.md +++ b/readme.md @@ -3,7 +3,7 @@ **Tags:** navigation, hierarchical, post type, boston university, bu **Requires at least:** 3.1 **Tested up to:** 4.6.1 -**Stable tag:** 1.2.13 +**Stable tag:** 1.2.14 **License:** GPLv2 or later **License URI:** http://www.gnu.org/licenses/gpl-2.0.html @@ -99,6 +99,9 @@ Please see this page for the details: ## Changelog +### 1.2.14 + +* Add hash comparison before saving changes to post hierarchy in Change Order page. ### 1.2.13 diff --git a/readme.txt b/readme.txt index cee6888..10a95ba 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ Contributors: ntk, mgburns, gcorne, jtwiest, awbauer, inderpreet99 Tags: navigation, hierarchical, post type, boston university, bu Requires at least: 3.1 Tested up to: 4.6.1 -Stable tag: 1.2.13 +Stable tag: 1.2.14 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -78,6 +78,11 @@ Please see this page for the details: == Changelog == += 1.2.14 = + +* Add hash comparison before saving changes to post hierarchy in Change Order page. + + = 1.2.13 = * Add missing parameter to `the_title` filter call. Part 2. diff --git a/templates/edit-order.php b/templates/edit-order.php index 0652559..b87cede 100644 --- a/templates/edit-order.php +++ b/templates/edit-order.php @@ -5,6 +5,7 @@