WordPress.org

Make WordPress Core

Ticket #14662: 14662.b.diff

File 14662.b.diff, 9.4 KB (added by mdawaffe, 9 years ago)

Tweak to fix $_return_loop handling.

  • 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 || $tortoise == $hare )
     4345                        return $_return_loop ? $return : $tortoise;
     4346
     4347                $tortoise = $map[$tortoise]; // Increment tortoise by one step
     4348        }
     4349
     4350        return false;
     4351}