. */ if ( ! is_admin() ) { return; } define( 'AMTPV_VERSION', '2.8.11' ); require 'includes/settings.php'; add_action( 'admin_menu', 'admin_menu_tree_page_view_admin_menu' ); add_action( 'admin_enqueue_scripts', 'admin_menu_tree_page_view_admin_init' ); add_action( 'wp_ajax_admin_menu_tree_page_view_add_page', 'admin_menu_tree_page_view_add_page' ); add_action( 'wp_ajax_admin_menu_tree_page_view_move_page', 'admin_menu_tree_page_view_move_page' ); function admin_menu_tree_page_view_admin_init() { wp_enqueue_style( 'admin_menu_tree_page_view_styles', plugins_url( '/css/styles.css', __FILE__ ), [], AMTPV_VERSION ); wp_enqueue_script( 'jquery.highlight', plugins_url( '/js/jquery.highlight.js', __FILE__ ), [ 'jquery' ], AMTPV_VERSION, true ); // Renamed from .cookie to fix problems with mod_security wp_enqueue_script( 'jquery-cookie', plugins_url( '/js/jquery.biscuit.js', __FILE__ ), [ 'jquery' ], AMTPV_VERSION, true ); wp_enqueue_script( 'jquery.ui.nestedSortable', plugins_url( '/js/jquery.ui.nestedSortable.js', __FILE__ ), [ 'jquery', 'jquery-ui-sortable' ], AMTPV_VERSION, true ); wp_enqueue_script( 'admin_menu_tree_page_view', plugins_url( '/js/scripts.js', __FILE__ ), [ 'jquery', 'jquery-cookie', 'jquery.highlight', 'jquery.ui.nestedSortable' ], AMTPV_VERSION, true ); wp_add_inline_script( 'admin_menu_tree_page_view', 'const amtpv_l10n = ' . json_encode( [ 'Edit' => __( 'Edit', 'admin-menu-tree-page-view' ), 'View' => __( 'View', 'admin-menu-tree-page-view' ), 'Add_new_page_here' => __( 'Add new page after', 'admin-menu-tree-page-view' ), 'Add_new_page_inside' => __( 'Add new page inside', 'admin-menu-tree-page-view' ), 'Untitled' => __( 'Untitled', 'admin-menu-tree-page-view' ), 'nonce' => wp_create_nonce( 'admin-menu-tree-page-view' ), ] ), 'before' ); } // Custom settings link inside Plugins section function amtpv_settings_link( $links ) { $settings_link = '' . __( 'Settings', 'admin-menu-tree-page-view' ) . ''; array_unshift( $links, $settings_link ); return $links; } $plugin = plugin_basename( __FILE__ ); add_filter( "plugin_action_links_$plugin", 'amtpv_settings_link' ); class admin_menu_tree_page_view { public static $arr_all_pages_id_parent; public static $one_page_parents; static function get_all_pages_id_parent() { if ( ! isset( admin_menu_tree_page_view::$arr_all_pages_id_parent ) ) { // Get all pages, once, to spare some queries looking for children $all_pages = get_posts( [ 'numberposts' => -1, 'post_type' => 'page', 'post_status' => 'any', 'fields' => 'id=>parent', ] ); admin_menu_tree_page_view::$arr_all_pages_id_parent = $all_pages; } return admin_menu_tree_page_view::$arr_all_pages_id_parent; } static function get_post_ancestors( $post_to_check_parents_for ) { if ( ! isset( admin_menu_tree_page_view::$one_page_parents ) ) { wp_cache_delete( $post_to_check_parents_for, 'posts' ); $one_page_parents = get_post_ancestors( $post_to_check_parents_for ); admin_menu_tree_page_view::$one_page_parents = $one_page_parents; } return admin_menu_tree_page_view::$one_page_parents; } } function admin_menu_tree_page_view_get_pages( $args ) { $defaults = [ 'post_type' => 'page', 'parent' => 0, 'post_parent' => 0, 'numberposts' => -1, 'orderby' => 'menu_order', 'order' => 'ASC', 'post_status' => 'any', 'suppress_filters' => 0, // suppose to fix problems with WPML ]; $args = wp_parse_args( $args, $defaults ); // contains all page ids as keys and their parent as the val $arr_all_pages_id_parent = admin_menu_tree_page_view::get_all_pages_id_parent(); $pages = get_posts( $args ); $output = ''; $str_child_output = ''; foreach ( $pages as $one_page ) { $edit_link = get_edit_post_link( $one_page->ID ); $title = get_the_title( $one_page->ID ); $title = esc_html( $title ); // add num of children to the title // @done: this is still being done for each page, even if it does not have children. can we check if it has before? // we could fetch all pages once and store them in an array and then just check if the array has our id in it. yeah. let's do that. // if our page id exists in $arr_all_pages_id_parent and has a value // so result is from 690 queries > 474 = 216 queries less. still many.. // from 474 to 259 = 215 less // so total from 690 to 259 = 431 queries less! grrroooovy if ( in_array( $one_page->ID, $arr_all_pages_id_parent ) ) { $post_children = get_children( [ 'post_parent' => $one_page->ID, 'post_type' => 'page', ] ); $post_children_count = sizeof( $post_children ); $title .= " ($post_children_count)"; } else { $post_children_count = 0; } $class = ''; if ( isset( $_GET['action'] ) && $_GET['action'] == 'edit' && isset( $_GET['post'] ) && $_GET['post'] == $one_page->ID ) { $class = 'current'; } $status_span = ''; if ( $one_page->post_password ) { $status_span .= ""; } if ( $one_page->post_status != 'publish' ) { $status_span .= "'; } // add css if we have childs $args_childs = $args; $args_childs['parent'] = $one_page->ID; $args_childs['post_parent'] = $one_page->ID; $args_childs['child_of'] = $one_page->ID; // can we run this only if the page actually has children? is there a property in the result of get_children for this? // eh, you moron, we already got that info in $post_children_count! // so result is from 690 queries > 474 = 216 queries less. still many.. $str_child_output = ''; if ( $post_children_count > 0 ) { $str_child_output = admin_menu_tree_page_view_get_pages( $args_childs ); $class .= ' admin-menu-tree-page-view-has-childs'; } // determine if ul should be opened or closed $isOpened = false; // check cookie first $cookie_opened = isset( $_COOKIE['admin-menu-tree-page-view-open-posts'] ) ? $_COOKIE['admin-menu-tree-page-view-open-posts'] : ''; // 2,95,n $cookie_opened = explode( ',', $cookie_opened ); // if we are editing a post, we should see it in the tree, right? // don't use on bulk edit, then post is an array and not a single post id if ( isset( $_GET['action'] ) && 'edit' == $_GET['action'] && isset( $_GET['post'] ) && is_integer( $_GET['post'] ) ) { // if post with id get[post] is a parent of the current post, show it if ( $_GET['post'] != $one_page->ID ) { $post_to_check_parents_for = $_GET['post']; // seems to be a problem with get_post_ancestors (yes, it's in the trac too) // Long time since I wrote this, but perhaps this is the problem (adding for future reference): // http://core.trac.wordpress.org/ticket/10381 // @done: this is done several times. only do it once please // before: 441. after: 43 $one_page_parents = admin_menu_tree_page_view::get_post_ancestors( $post_to_check_parents_for ); if ( in_array( $one_page->ID, $one_page_parents ) ) { $isOpened = true; } } } if ( in_array( $one_page->ID, $cookie_opened ) || $isOpened && $post_children_count > 0 ) { $class .= ' admin-menu-tree-page-view-opened'; } elseif ( $post_children_count > 0 ) { $class .= ' admin-menu-tree-page-view-closed'; } $class .= ' nestedSortable'; $output .= "
Nothing to see here. Move along! :)
cms_tpv_add_page [pageID] => cms-tpv-1318 type ) action admin_menu_tree_page_view_add_page pageID 448 page_titles[] pending inside post_status pending post_type page type inside */ $type = $_POST['type']; $pageID = (int) $_POST['pageID']; $post_type = $_POST['post_type']; $wpml_lang = isset( $_POST['wpml_lang'] ) ? $_POST['wpml_lang'] : ''; $page_titles = (array) $_POST['page_titles']; $ref_post = get_post( $pageID ); $post_status = $_POST['post_status']; if ( ! $post_status ) { $post_status = 'draft'; } $post_id_to_return = null; if ( 'after' == $type ) { /* add page under/below ref_post */ if ( ! function_exists( 'admin_menu_tree_page_view_add_page_after' ) ) { function admin_menu_tree_page_view_add_page_after( $ref_post_id, $page_title, $post_type, $post_status = 'draft' ) { global $wpdb; $ref_post = get_post( $ref_post_id ); $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET menu_order = menu_order+2 WHERE post_type = %s AND post_parent = %d AND menu_order >= %d AND id <> %d ", $ref_post->post_type, $ref_post->post_parent, $ref_post->menu_order, $ref_post->ID ) ); // create a new page and then goto it $post_new = []; $post_new['menu_order'] = $ref_post->menu_order + 1; $post_new['post_parent'] = $ref_post->post_parent; $post_new['post_type'] = 'page'; $post_new['post_status'] = $post_status; $post_new['post_title'] = $page_title; $post_new['post_content'] = ''; $post_new['post_type'] = $post_type; $newPostID = wp_insert_post( $post_new ); return $newPostID; } } $ref_post_id = $ref_post->ID; $loopNum = 0; foreach ( $page_titles as $one_page_title ) { $newPostID = admin_menu_tree_page_view_add_page_after( $ref_post_id, $one_page_title, $post_type, $post_status ); $new_post = get_post( $newPostID ); $ref_post_id = $new_post->ID; if ( $loopNum == 0 ) { $post_id_to_return = $newPostID; } ++$loopNum; } } elseif ( 'inside' == $type ) { /* add page inside ref_post */ if ( ! function_exists( 'admin_menu_tree_page_view_add_page_inside' ) ) { function admin_menu_tree_page_view_add_page_inside( $ref_post_id, $page_title, $post_type, $post_status = 'draft' ) { global $wpdb; $ref_post = get_post( $ref_post_id ); $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET menu_order = menu_order+1 WHERE post_type = %s AND post_parent = %d", $ref_post->post_type, $ref_post->ID ) ); $post_new = []; $post_new['menu_order'] = 0; $post_new['post_parent'] = $ref_post->ID; $post_new['post_type'] = 'page'; $post_new['post_status'] = $post_status; $post_new['post_title'] = $page_title; $post_new['post_content'] = ''; $post_new['post_type'] = $post_type; $newPostID = wp_insert_post( $post_new ); return $newPostID; } } // add reversed $ref_post_id = $ref_post->ID; $page_titles = array_reverse( $page_titles ); $loopNum = 0; foreach ( $page_titles as $one_page_title ) { $newPostID = admin_menu_tree_page_view_add_page_inside( $ref_post_id, $one_page_title, $post_type, $post_status ); if ( $loopNum == 0 ) { $post_id_to_return = $newPostID; } ++$loopNum; } $post_id_to_return = $newPostID; } if ( $post_id_to_return ) { // return editlink for the newly created page $editLink = get_edit_post_link( $post_id_to_return, '' ); if ( $wpml_lang ) { $editLink = add_query_arg( 'lang', $wpml_lang, $editLink ); } echo $editLink; } else { // fail, tell js echo '0'; } #print_r($post_new); exit; } // move a post up or down // code from my other plugin cms tree page view function admin_menu_tree_page_view_move_page() { check_ajax_referer( 'admin-menu-tree-page-view', 'amtpv-nonce' ); if ( ! current_user_can( 'edit_pages' ) ) { wp_die( -1 ); } /* Array ( [action] => admin_menu_tree_page_view_move_page [post_to_update_id] => 567 [direction] => down ) */ // fetch all info we need from $_GET-params $post_to_update_id = (int) $_POST['post_to_update_id']; $direction = $_POST['direction']; $post_to_update = get_post( $post_to_update_id ); $aboveOrNextPostID = $_POST['aboveOrNextPostID']; $post_aboveOrNext = get_post( $aboveOrNextPostID ); /* the node that was moved, the reference node in the move, the new position relative to the reference node (one of "before", "after" or "inside"), inside = man placerar den under en sida som inte har några barn? */ global $wpdb; $node_id = (int) $_POST['post_to_update_id']; // the node that was moved $ref_node_id = (int) $_POST['aboveOrNextPostID']; $type = $_POST['direction']; $_POST['skip_sitepress_actions'] = true; // sitepress.class.php->save_post_actions if ( $node_id && $ref_node_id ) { #echo "\nnode_id: $node_id"; #echo "\ntype: $type"; $post_node = get_post( $node_id ); $post_ref_node = get_post( $ref_node_id ); // first check that post_node (moved post) is not in trash. we do not move them if ( $post_node->post_status == 'trash' ) { exit; } if ( 'inside' == $type ) { // note: inside does not exist for Admin Menu Tree Page View // post_node is moved inside ref_post_node // add ref_post_node as parent to post_node and set post_nodes menu_order to 0 // @todo: shouldn't menu order of existing items be changed? $post_to_save = [ 'ID' => $post_node->ID, 'menu_order' => 0, 'post_parent' => $post_ref_node->ID, ]; wp_update_post( $post_to_save ); echo 'did inside'; } elseif ( 'up' == $type ) { // post_node is placed before ref_post_node $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET menu_order = menu_order+1 WHERE post_type = %s AND post_parent = %d", $post_ref_node->post_type, $post_ref_node->post_parent ) ); // update menu order with +1 for all pages below ref_node, this should fix the problem with "unmovable" pages because of // multiple pages with the same menu order (...which is not the fault of this plugin!) $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET menu_order = menu_order+1 WHERE post_type = %s AND menu_order >= %d", $post_ref_node->post_type, $post_ref_node->menu_order + 1 ) ); $post_to_save = [ 'ID' => $post_node->ID, 'menu_order' => $post_ref_node->menu_order, 'post_parent' => $post_ref_node->post_parent, ]; wp_update_post( $post_to_save ); echo 'did before'; } elseif ( 'down' == $type ) { // post_node is placed after ref_post_node // update menu_order of all posts with the same parent ref_post_node and with a menu_order of the same as ref_post_node, but do not include ref_post_node // +2 since multiple can have same menu order and we want our moved post to have a unique "spot" //$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET menu_order = menu_order+2 WHERE post_parent = %d AND menu_order >= %d AND id <> %d ", $post_ref_node->post_parent, $post_ref_node->menu_order, $post_ref_node->ID ) ); $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET menu_order = menu_order+2 WHERE post_type = %s AND post_parent = %d AND menu_order >= %d AND id <> %d ", $post_ref_node->post_type, $post_ref_node->post_parent, $post_ref_node->menu_order, $post_ref_node->ID ) ); // update menu_order of post_node to the same that ref_post_node_had+1 #$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET menu_order = %d, post_parent = %d WHERE ID = %d", $post_ref_node->menu_order+1, $post_ref_node->post_parent, $post_node->ID ) ); $post_to_save = [ 'ID' => $post_node->ID, 'menu_order' => $post_ref_node->menu_order + 1, 'post_parent' => $post_ref_node->post_parent, ]; wp_update_post( $post_to_save ); echo 'did after'; } #echo "ok"; // I'm done here! } else { // error } echo 1; die(); } // move post