WordPress.org

Make WordPress Core

Ticket #14662: 14662.diff

File 14662.diff, 9.5 KB (added by mdawaffe, 4 years ago)
  • wp-includes/default-filters.php

     
    109109        add_filter( $filter, 'convert_chars' ); 
    110110} 
    111111 
     112// Pre save hierarchy 
     113add_filter( 'wp_insert_post_parent', 'wp_check_post_hierarchy_for_loops', 10, 2 ); 
     114add_filter( 'wp_update_term_parent', 'wp_check_term_hierarchy_for_loops', 10, 3 ); 
     115 
    112116// Display filters 
    113117add_filter( 'the_title', 'wptexturize'   ); 
    114118add_filter( 'the_title', 'convert_chars' ); 
  • wp-includes/taxonomy.php

     
    19361936                } 
    19371937        } 
    19381938 
     1939        // Check $parent to see if it will cause a hierarchy loop 
     1940        $parent = apply_filters( 'wp_update_term_parent', $parent, $term_id, $taxonomy, compact( array_keys( $args ) ), $args ); 
     1941 
    19391942        // Check for duplicate slug 
    19401943        $id = $wpdb->get_var( $wpdb->prepare( "SELECT term_id FROM $wpdb->terms WHERE slug = %s", $slug ) ); 
    19411944        if ( $id && ($id != $term_id) ) { 
     
    26822685 
    26832686        return false; 
    26842687} 
     2688 
     2689/** 
     2690 * Checks the given subset of the term hierarchy for hierarchy loops. 
     2691 * Prevents loops from forming and breaks those that it finds. 
     2692 * 
     2693 * Attached to the wp_update_term_parent filter. 
     2694 * 
     2695 * @since 3.1 
     2696 * @uses WP_Term_Parent_Map 
     2697 * @uses wp_find_hierarchy_loop() 
     2698 * 
     2699 * @param int $parent term_id of the parent for the term we're checking. 
     2700 * @parem int $term_id The term we're checking. 
     2701 * 
     2702 * @return int The new parent for the term. 
     2703 */ 
     2704function wp_check_term_hierarchy_for_loops( $parent, $term_id, $taxonomy ) { 
     2705        // Nothing fancy here - bail 
     2706        if ( !$parent ) 
     2707                return 0; 
     2708 
     2709        // Can't be its own parent 
     2710        if ( $parent == $term_id ) 
     2711                return 0; 
     2712 
     2713        // Now look for larger loops 
     2714 
     2715        $term_parent_map = new WP_Term_Parent_Map( $taxonomy, array( $term_id => $parent ) ); 
     2716 
     2717        if ( !$loop = wp_find_hierarchy_loop( $term_parent_map, $term_id ) ) 
     2718                return $parent; // No loop 
     2719         
     2720        // Setting $parent to the given value causes a loop 
     2721        if ( isset( $loop[$term_id] ) ) 
     2722                return 0; 
     2723 
     2724        // There's a loop, but it doesn't contain $term_id.  Break the loop. 
     2725        foreach ( array_keys( $loop ) as $loop_member ) 
     2726                $term_parent_map[$loop_member] = 0; 
     2727        return $parent; 
     2728} 
     2729 
     2730/** 
     2731 * Simulates array( $term_id => $parent, ... ) without having to load all terms. 
     2732 * 
     2733 * @link http://php.net/manual/class.arrayaccess.php 
     2734 * 
     2735 * @since 3.1 
     2736 */ 
     2737class WP_Term_Parent_Map implements ArrayAccess { 
     2738        public $taxonomy = ''; 
     2739        public $override = array(); 
     2740 
     2741        /** 
     2742         * @param string $taxonomy 
     2743         * @param array $override A list of term_id => parent mappings used to override the results of get_term()->parent. 
     2744         *              Useful when checking for loops in hierarchies that are not yet stored in the DB. 
     2745         */ 
     2746        public function __construct( $taxonomy, $override = array() ) { 
     2747                $this->taxonomy = $taxonomy; 
     2748                $this->override = $override; 
     2749        } 
     2750 
     2751        /* ArrayAccess */ 
     2752        public function offsetExists( $offset ) { 
     2753                if ( isset( $this->override[$offset] ) ) 
     2754                        return true; 
     2755                $term = get_term( $offset, $this->taxonomy ); 
     2756                return $term && !is_wp_error( $term ); 
     2757        } 
     2758        public function offsetGet( $offset ) { 
     2759                if ( isset( $this->override[$offset] ) ) 
     2760                        return $this->override[$offset]; 
     2761 
     2762                $term = get_term( $offset, $this->taxonomy ); 
     2763                if ( !$term || is_wp_error( $term ) ) 
     2764                        return; 
     2765                return (int) $term->parent; 
     2766        } 
     2767        public function offsetSet( $offset, $value ) { 
     2768                if ( isset( $this->override[$offset] ) ) 
     2769                        $this->override[$offset] = $value; 
     2770                else 
     2771                        wp_update_term( $offset, $this->taxonomy, array( 'parent' => $value ) ); 
     2772        } 
     2773        public function offsetUnset( $offset ) { 
     2774                if ( isset( $this->override[$offset] ) ) 
     2775                        unset( $this->override[$offset] ); 
     2776                // else noop 
     2777        } 
     2778} 
  • wp-includes/post.php

     
    22732273        else 
    22742274                $post_parent = 0; 
    22752275 
    2276         if ( !empty($post_ID) ) { 
    2277                 if ( $post_parent == $post_ID ) { 
    2278                         // Post can't be its own parent 
    2279                         $post_parent = 0; 
    2280                 } elseif ( !empty($post_parent) ) { 
    2281                         $parent_post = get_post($post_parent); 
    2282                         // Check for circular dependency 
    2283                         if ( isset( $parent_post->post_parent ) && $parent_post->post_parent == $post_ID ) 
    2284                                 $post_parent = 0; 
    2285                 } 
    2286         } 
     2276        // Check the post_parent to see if it will cause a hierarchy loop 
     2277        $post_parent = apply_filters( 'wp_insert_post_parent', $post_parent, $post_ID, compact( array_keys( $postarr ) ), $postarr ); 
    22872278 
    22882279        if ( isset($menu_order) ) 
    22892280                $menu_order = (int) $menu_order; 
     
    47244715                add_filter('the_preview', '_set_preview'); 
    47254716        } 
    47264717} 
     4718 
     4719/** 
     4720 * Checks the given subset of the post hierarchy for hierarchy loops. 
     4721 * Prevents loops from forming and breaks those that it finds. 
     4722 * 
     4723 * Attached to the wp_insert_post_parent filter. 
     4724 * 
     4725 * @since 3.1 
     4726 * @uses WP_Post_Parent_Map 
     4727 * @uses wp_find_hierarchy_loop() 
     4728 * 
     4729 * @param int $post_parent ID of the parent for the post we're checking. 
     4730 * @parem int $post_ID ID of the post we're checking. 
     4731 * 
     4732 * @return int The new post_parent for the post. 
     4733 */ 
     4734function wp_check_post_hierarchy_for_loops( $post_parent, $post_ID ) { 
     4735        // Nothing fancy here - bail 
     4736        if ( !$post_parent ) 
     4737                return 0; 
     4738 
     4739        // New post can't cause a loop 
     4740        if ( empty( $post_ID ) ) 
     4741                return $post_parent; 
     4742 
     4743        // Can't be its own parent 
     4744        if ( $post_parent == $post_ID ) 
     4745                return 0; 
     4746 
     4747        // Now look for larger loops 
     4748 
     4749        $post_parent_map = new WP_Post_Parent_Map( array( $post_ID => $post_parent ) ); 
     4750 
     4751        if ( !$loop = wp_find_hierarchy_loop( $post_parent_map, $post_ID ) ) 
     4752                return $post_parent; // No loop 
     4753 
     4754        // Setting $post_parent to the given value causes a loop 
     4755        if ( isset( $loop[$post_ID] ) ) 
     4756                return 0; 
     4757 
     4758        // There's a loop, but it doesn't contain $post_ID.  Break the loop. 
     4759        foreach ( array_keys( $loop ) as $loop_member ) 
     4760                $post_parent_map[$loop_member] = 0; 
     4761        return $post_parent; 
     4762} 
     4763 
     4764/** 
     4765 * Simulates array( $post_id => $post_parent, ... ) without having to load all posts. 
     4766 * 
     4767 * @link http://php.net/manual/class.arrayaccess.php 
     4768 * 
     4769 * @since 3.1 
     4770 */ 
     4771class WP_Post_Parent_Map implements ArrayAccess { 
     4772        public $override = array(); 
     4773 
     4774        /** 
     4775         * @param array $override A list of post_ID => post_parent mappings used to override the results of get_post()->post_parent. 
     4776         *              Useful when checking for loops in hierarchies that are not yet stored in the DB. 
     4777         */ 
     4778        public function __construct( $override = array() ) { 
     4779                $this->override = $override; 
     4780        } 
     4781 
     4782        /* ArrayAccess */ 
     4783        public function offsetExists( $offset ) { 
     4784                if ( isset( $this->override[$offset] ) ) 
     4785                        return true; 
     4786                return (bool) get_post( $offset ); 
     4787        } 
     4788        public function offsetGet( $offset ) { 
     4789                if ( isset( $this->override[$offset] ) ) 
     4790                        return $this->override[$offset]; 
     4791 
     4792                if ( !$post = get_post( $offset ) ) 
     4793                        return; 
     4794                return (int) $post->post_parent; 
     4795        } 
     4796        public function offsetSet( $offset, $value ) { 
     4797                if ( isset( $this->override[$offset] ) ) 
     4798                        $this->override[$offset] = $value; 
     4799                else 
     4800                        wp_update_post( array( 'ID' => $offset, 'post_parent' => $value ) ); 
     4801        } 
     4802        public function offsetUnset( $offset ) { 
     4803                if ( isset( $this->override[$offset] ) ) 
     4804                        unset( $this->override[$offset] ); 
     4805                // else noop 
     4806        } 
     4807} 
  • wp-includes/functions.php

     
    42974297        } 
    42984298} 
    42994299 
    4300 ?> 
     4300/** 
     4301 * Finds hierarchy loops in an array that maps objects to parents. 
     4302 * 
     4303 * @since 3.1 
     4304 * 
     4305 * @param array $map array( ID => parent_ID, ... ) 
     4306 * @param $start The ID to start the loop check at 
     4307 * 
     4308 * @return array IDs of all members of loop 
     4309 */ 
     4310function wp_find_hierarchy_loop( $map, $start ) { 
     4311        if ( !$arbitrary_loop_member = wp_find_hierarchy_loop_tortoise_hare( $map, $start ) ) 
     4312                return array(); 
     4313 
     4314        return wp_find_hierarchy_loop_tortoise_hare( $map, $arbitrary_loop_member, true ); 
     4315} 
     4316 
     4317/** 
     4318 * Uses the "The Tortoise and the Hare" algorithm to detect loops. 
     4319 * 
     4320 * For every step of the algorithm, the hare takes two steps and the tortoise one. 
     4321 * If the hare ever laps the tortoise, there must be a loop. 
     4322 * 
     4323 * @since 3.1 
     4324 * 
     4325 * @param array $map array( ID => parent_ID, ... ) 
     4326 * @param $start The ID to start the loop check at 
     4327 * @param bool $_return_loop Return loop members or just detect presence of loop? 
     4328 *             Only set to true if you already know the given $start is part of a loop 
     4329 *             (otherwise the returned array might include branches) 
     4330 * 
     4331 * @return mixed scalar ID of some arbitrary member of the loop, or array of IDs of all members of loop if $_return_loop 
     4332 */ 
     4333function wp_find_hierarchy_loop_tortoise_hare( $map, $start, $_return_loop = false ) { 
     4334        $tortoise = $hare = $evanescent_hare = $start; 
     4335        $return = array(); 
     4336 
     4337        // Set evanescent_hare to one past hare 
     4338        // Increment hare two steps 
     4339        while ( $tortoise && ( $evanescent_hare = $map[$hare] ) && ( $hare = $map[$evanescent_hare] ) ) { 
     4340                if ( $_return_loop ) 
     4341                        $return[$tortoise] = $return[$evanescent_hare] = $return[$hare] = true; 
     4342 
     4343                // tortoise got lapped - must be a loop 
     4344                if ( $tortoise == $evanescent_hare ) { 
     4345                        unset( $return[$hare] ); // $hare is not actually in the loop 
     4346                        return $_return_loop ? $return : $tortoise; 
     4347                } else if ( $tortoise == $hare ) { 
     4348                        return $_return_loop ? $return : $tortoise; 
     4349                } 
     4350 
     4351                $tortoise = $map[$tortoise]; // Increment tortoise by one step 
     4352        } 
     4353 
     4354        return false; 
     4355}