Make WordPress Core

Ticket #32077: post.php.patch

File post.php.patch, 18.7 KB (added by LewisCowles, 10 years ago)

Initial re-factor

  • post.php

     
    44214421}
    44224422
    44234423/**
    4424  * Retrieve a list of pages.
    4425  *
    4426  * @global wpdb $wpdb WordPress database abstraction object.
    4427  *
    4428  * @since 1.5.0
    4429  *
    4430  * @param array|string $args {
    4431  *     Optional. Array or string of arguments to retrieve pages.
    4432  *
    4433  *     @type int          $child_of     Page ID to return child and grandchild pages of.
    4434  *                                      Default 0, or no restriction.
    4435  *     @type string       $sort_order   How to sort retrieved pages. Accepts 'ASC', 'DESC'. Default 'ASC'.
    4436  *     @type string       $sort_column  What columns to sort pages by, comma-separated. Accepts 'post_author',
    4437  *                                      'post_date', 'post_title', 'post_name', 'post_modified', 'menu_order',
    4438  *                                      'post_modified_gmt', 'post_parent', 'ID', 'rand', 'comment_count'.
    4439  *                                      'post_' can be omitted for any values that start with it.
    4440  *                                      Default 'post_title'.
    4441  *     @type bool         $hierarchical Whether to return pages hierarchically. Default true.
    4442  *     @type array        $exclude      Array of page IDs to exclude. Default empty array.
    4443  *     @type array        $include      Array of page IDs to include. Cannot be used with `$child_of`,
    4444  *                                      `$parent`, `$exclude`, `$meta_key`, `$meta_value`, or `$hierarchical`.
    4445  *                                      Default empty array.
    4446  *     @type string       $meta_key     Only include pages with this meta key. Default empty.
    4447  *     @type string       $meta_value   Only include pages with this meta value. Requires `$meta_key`.
    4448  *                                      Default empty.
    4449  *     @type string       $authors      A comma-separated list of author IDs. Default empty.
    4450  *     @type int          $parent       Page ID to return direct children of. `$hierarchical` must be false.
    4451  *                                      Default -1, or no restriction.
    4452  *     @type string|array $exclude_tree Comma-separated string or array of page IDs to exclude.
    4453  *                                      Default empty array.
    4454  *     @type int          $number       The number of pages to return. Default 0, or all pages.
    4455  *     @type int          $offset       The number of pages to skip before returning. Requires `$number`.
    4456  *                                      Default 0.
    4457  *     @type string       $post_type    The post type to query. Default 'page'.
    4458  *     @type string       $post_status  A comma-separated list of post status types to include.
    4459  *                                      Default 'publish'.
    4460  * }
    4461  * @return array List of pages matching defaults or `$args`.
     4424 * Force input to be an array if not already
     4425 * @param       mixed   $input  input variable to be coerced into array (not designed as a universal conversion, just the standard WP input strings)
     4426 * @return      array   an array, even if invalid input given
    44624427 */
    4463 function get_pages( $args = array() ) {
    4464         global $wpdb;
     4428function wp_coerce_to_array( $input ) {
     4429        if( is_array( $input ) ){ return $input; } // jump out if nothing to do
     4430        if ( is_string( $post_status ) ) { // we should check if the status is string, if not there is nothing we can do
     4431                return explode( ',', $post_status );
     4432        }
     4433        return array();
     4434}
    44654435
    4466         $defaults = array(
     4436/**
     4437 * check if post stati are all valid
     4438 * @param       array   $stati  an array of post stati to verify against all post stati
     4439 * @return      bool    true if stati is an array and it matches elements within all post stati
     4440 */
     4441function post_stati_valid( $stati ) {
     4442        // Make sure we have a valid post status.
     4443       
     4444        // first lets deal with strings that can become arrays
     4445        $stati = wp_coerce_to_array( $stati );
     4446
     4447        if ( !array_diff( $stati, get_post_stati() ) && !empty($stati) ) {
     4448                return true;
     4449        }
     4450        return false;
     4451}
     4452
     4453/**
     4454 * provide default options for get_pages to try to make function more managable and process-descriptable
     4455 */
     4456function get_pages_defaults() {
     4457        return  array(
    44674458                'child_of' => 0, 'sort_order' => 'ASC',
    44684459                'sort_column' => 'post_title', 'hierarchical' => 1,
    44694460                'exclude' => array(), 'include' => array(),
     
    44724463                'number' => '', 'offset' => 0,
    44734464                'post_type' => 'page', 'post_status' => 'publish',
    44744465        );
     4466}
    44754467
    4476         $r = wp_parse_args( $args, $defaults );
     4468/**
     4469 * provides parsing of $args input for get_pages
     4470 * @param       string|array    &$args
     4471 */
     4472function get_pages_process_args( &$args ) {
     4473        $args = wp_parse_args( $args, get_pages_defaults() );
     4474        $args['number'] = intval($args['number']);
     4475        $args['offset'] = intval($args['offset']);
     4476        $args['child_of'] = intval($args['child_of']);
     4477}
    44774478
    4478         $number = (int) $r['number'];
    4479         $offset = (int) $r['offset'];
    4480         $child_of = (int) $r['child_of'];
    4481         $hierarchical = $r['hierarchical'];
    4482         $exclude = $r['exclude'];
    4483         $meta_key = $r['meta_key'];
    4484         $meta_value = $r['meta_value'];
    4485         $parent = $r['parent'];
    4486         $post_status = $r['post_status'];
    4487 
    4488         // Make sure the post type is hierarchical.
    4489         $hierarchical_post_types = get_post_types( array( 'hierarchical' => true ) );
    4490         if ( ! in_array( $r['post_type'], $hierarchical_post_types ) ) {
    4491                 return false;
    4492         }
    4493 
    4494         if ( $parent > 0 && ! $child_of ) {
    4495                 $hierarchical = false;
    4496         }
    4497 
    4498         // Make sure we have a valid post status.
    4499         if ( ! is_array( $post_status ) ) {
    4500                 $post_status = explode( ',', $post_status );
    4501         }
    4502         if ( array_diff( $post_status, get_post_stati() ) ) {
    4503                 return false;
    4504         }
    4505 
    4506         // $args can be whatever, only use the args defined in defaults to compute the key.
    4507         $key = md5( serialize( wp_array_slice_assoc( $r, array_keys( $defaults ) ) ) );
     4479/**
     4480 * provides boxed caching for get_pages
     4481 * @param       array|string    $args   the arguments for get_pages, used to build the cache hash key
     4482 */
     4483function get_pages_cached( $args ) {
     4484        global $cache_key;
     4485       
     4486        $key = md5( serialize( wp_array_slice_assoc( $args, array_keys( get_pages_defaults() ) ) ) );
    45084487        $last_changed = wp_cache_get( 'last_changed', 'posts' );
    45094488        if ( ! $last_changed ) {
    45104489                $last_changed = microtime();
     
    45164495                // Convert to WP_Post instances.
    45174496                $pages = array_map( 'get_post', $cache );
    45184497                /** This filter is documented in wp-includes/post.php */
    4519                 $pages = apply_filters( 'get_pages', $pages, $r );
     4498                $pages = apply_filters( 'get_pages', $pages, $args );
    45204499                return $pages;
    45214500        }
     4501        return false;
     4502}
    45224503
     4504/**
     4505 * provides updating of cache input for get_pages based upon cache_key global hash key
     4506 * @param       array   &$args  arguments (in parsed form), to get_pages as value
     4507 * @param       array   &$posts posts returned from get_pages as reference
     4508 */
     4509function get_pages_update_cache( $args, &$posts ) {
     4510        global $cache_key;
     4511        // Sanitize before caching so it'll only get done once.
     4512        $num_pages = count( $pages );
     4513        for ( $i = 0; $i < $num_pages; $i++ ) {
     4514                $pages[ $i ] = sanitize_post( $pages[ $i ], 'raw' );
     4515        }
     4516
     4517        // Update cache.
     4518        update_post_cache( $pages );
     4519
     4520        if ( $args[ 'child_of' ] || $args[ 'heirarchical' ] ) {
     4521                $pages = get_page_children( $args[ 'child_of' ], $pages );
     4522        }
     4523
     4524        if ( ! empty( $args[ 'exclude_tree' ] ) ) {
     4525                $args[ 'exclude' ] = wp_parse_id_list( $args[ 'exclude_tree' ] );
     4526                foreach( $args[ 'exclude' ] as $id ) {
     4527                        $children = get_page_children( $id, $pages );
     4528                        foreach ( $children as $child ) {
     4529                                $args[ 'exclude' ][] = $child->ID;
     4530                        }
     4531                }
     4532
     4533                $num_pages = count( $pages );
     4534                for ( $i = 0; $i < $num_pages; $i++ ) {
     4535                        if ( in_array( $pages[ $i ]->ID, $args[ 'exclude' ] ) ) {
     4536                                unset( $pages[ $i ] );
     4537                        }
     4538                }
     4539        }
     4540
     4541        $page_structure = array();
     4542        foreach ( $pages as $page ) {
     4543                $page_structure[] = $page->ID;
     4544        }
     4545       
     4546        wp_cache_set( $cache_key, $page_structure, 'posts' );
     4547       
     4548        // Convert to WP_Post instances
     4549        $pages = array_map( 'get_post', $pages );
     4550}
     4551
     4552/**
     4553 * provides / generates includes string for get_pages
     4554 * @param       array   &$args  arguments (in parsed form), to get_pages as reference
     4555 * @return      string  a string of SQL / WP_SQL compatible with querying the WP DB
     4556 */
     4557function build_get_pages_includes( &$args ) {
    45234558        $inclusions = '';
    4524         if ( ! empty( $r['include'] ) ) {
    4525                 $child_of = 0; //ignore child_of, parent, exclude, meta_key, and meta_value params if using include
    4526                 $parent = -1;
    4527                 $exclude = '';
    4528                 $meta_key = '';
    4529                 $meta_value = '';
    4530                 $hierarchical = false;
    4531                 $incpages = wp_parse_id_list( $r['include'] );
     4559        if ( ! empty( $args[ 'include' ] ) ) {
     4560                $args[ 'child_of' ] = 0; //ignore child_of, parent, exclude, meta_key, and meta_value params if using include
     4561                $args[ 'parent' ] = -1;
     4562                $args[ 'exclude' ] = '';
     4563                $args[ 'meta_key' ] = '';
     4564                $args[ 'meta_value' ] = '';
     4565                $args[ 'heirarchical' ] = false;
     4566                $incpages = wp_parse_id_list( $args[ 'include' ] );
    45324567                if ( ! empty( $incpages ) ) {
    45334568                        $inclusions = ' AND ID IN (' . implode( ',', $incpages ) .  ')';
    45344569                }
    45354570        }
     4571        return $inclusions;
     4572}
    45364573
     4574/**
     4575 * provides / generates excludes string for get_pages
     4576 * @param       array|string    $exclude        list of excludes as value
     4577 * @return      string  a string of SQL / WP_SQL compatible with querying the WP DB
     4578 */
     4579function build_get_pages_excludes( $exclude ) {
    45374580        $exclusions = '';
    45384581        if ( ! empty( $exclude ) ) {
    45394582                $expages = wp_parse_id_list( $exclude );
     
    45414584                        $exclusions = ' AND ID NOT IN (' . implode( ',', $expages ) .  ')';
    45424585                }
    45434586        }
     4587        return $exclusions;
     4588}
    45444589
     4590/**
     4591 * provides / generates authors SQL / WP_SQL string for get_pages
     4592 * @param       array   $authors        list of authors as value
     4593 * @return      string  a string of SQL / WP_SQL compatible with querying the WP DB
     4594 */
     4595function build_get_pages_authors( $authors ) {
    45454596        $author_query = '';
    4546         if ( ! empty( $r['authors'] ) ) {
    4547                 $post_authors = preg_split( '/[\s,]+/', $r['authors'] );
     4597        if ( ! empty( $authors ) ) {
     4598                $post_authors = preg_split( '/[\s,]+/', $authors );
    45484599
    45494600                if ( ! empty( $post_authors ) ) {
    45504601                        foreach ( $post_authors as $post_author ) {
     
    45714622                        }
    45724623                }
    45734624        }
     4625        return $author_query;
     4626}
    45744627
     4628/**
     4629 * logic for retreival of pages and building of SQL / WPSQL string based upon criteria from $args
     4630 * @param       array   $args   arguments (in parsed form), to get_pages as value
     4631 * @return      array   an array of posts or empty array if no matched found
     4632 */
     4633function build_get_pages_DB( $args ) {
     4634        global $wpdb;
     4635
     4636        $inclusions = build_get_pages_includes( $args );
     4637        $exclusions = build_get_pages_excludes( $args['exclude'] );
     4638        $author_query = build_get_pages_authors( $args['authors'] );
     4639       
    45754640        $join = '';
    45764641        $where = "$exclusions $inclusions ";
    4577         if ( '' !== $meta_key || '' !== $meta_value ) {
     4642        if ( '' !== $args['meta_key'] || '' !== $args['meta_value'] ) {
    45784643                $join = " LEFT JOIN $wpdb->postmeta ON ( $wpdb->posts.ID = $wpdb->postmeta.post_id )";
    45794644
    45804645                // meta_key and meta_value might be slashed
    4581                 $meta_key = wp_unslash($meta_key);
    4582                 $meta_value = wp_unslash($meta_value);
    4583                 if ( '' !== $meta_key ) {
    4584                         $where .= $wpdb->prepare(" AND $wpdb->postmeta.meta_key = %s", $meta_key);
     4646                $args['meta_key'] = wp_unslash($args['meta_key']);
     4647                $args['meta_value'] = wp_unslash($args['meta_value']);
     4648                if ( '' !== $args['meta_key'] ) {
     4649                        $where .= $wpdb->prepare(" AND $wpdb->postmeta.meta_key = %s", $args['meta_key']);
    45854650                }
    4586                 if ( '' !== $meta_value ) {
    4587                         $where .= $wpdb->prepare(" AND $wpdb->postmeta.meta_value = %s", $meta_value);
     4651                if ( '' !== $args['meta_value'] ) {
     4652                        $where .= $wpdb->prepare(" AND $wpdb->postmeta.meta_value = %s", $args['meta_value']);
    45884653                }
    45894654
    45904655        }
    45914656
    4592         if ( is_array( $parent ) ) {
    4593                 $post_parent__in = implode( ',', array_map( 'absint', (array) $parent ) );
     4657        if ( is_array( $args['parent'] ) ) {
     4658                $post_parent__in = implode( ',', array_map( 'absint', (array) $args['parent'] ) );
    45944659                if ( ! empty( $post_parent__in ) ) {
    45954660                        $where .= " AND post_parent IN ($post_parent__in)";
    45964661                }
    4597         } elseif ( $parent >= 0 ) {
    4598                 $where .= $wpdb->prepare(' AND post_parent = %d ', $parent);
     4662        } elseif ( $args['parent'] >= 0 ) {
     4663                $where .= $wpdb->prepare(' AND post_parent = %d ', $args['parent']);
    45994664        }
    46004665
    4601         if ( 1 == count( $post_status ) ) {
    4602                 $where_post_type = $wpdb->prepare( "post_type = %s AND post_status = %s", $r['post_type'], reset( $post_status ) );
     4666        if ( 1 == count( $args['post_status'] ) ) {
     4667                $where_post_type = $wpdb->prepare( "post_type = %s AND post_status = %s", $args['post_type'], reset( $args['post_status'] ) );
    46034668        } else {
    4604                 $post_status = implode( "', '", $post_status );
    4605                 $where_post_type = $wpdb->prepare( "post_type = %s AND post_status IN ('$post_status')", $r['post_type'] );
     4669                $args['post_status'] = implode( "', '", $args['post_status'] );
     4670                $where_post_type = $wpdb->prepare( "post_type = %s AND post_status IN ('".$args['post_status']."')", $args['post_type'] );
    46064671        }
    46074672
    46084673        $orderby_array = array();
     
    46104675                'post_modified', 'modified_gmt', 'post_modified_gmt', 'menu_order', 'parent', 'post_parent',
    46114676                'ID', 'rand', 'comment_count' );
    46124677
    4613         foreach ( explode( ',', $r['sort_column'] ) as $orderby ) {
     4678        foreach ( explode( ',', $args['sort_column'] ) as $orderby ) {
    46144679                $orderby = trim( $orderby );
    46154680                if ( ! in_array( $orderby, $allowed_keys ) ) {
    46164681                        continue;
     
    46414706        }
    46424707        $sort_column = ! empty( $orderby_array ) ? implode( ',', $orderby_array ) : "$wpdb->posts.post_title";
    46434708
    4644         $sort_order = strtoupper( $r['sort_order'] );
     4709        $sort_order = strtoupper( $args['sort_order'] );
    46454710        if ( '' !== $sort_order && ! in_array( $sort_order, array( 'ASC', 'DESC' ) ) ) {
    46464711                $sort_order = 'ASC';
    46474712        }
     
    46504715        $query .= $author_query;
    46514716        $query .= " ORDER BY " . $sort_column . " " . $sort_order ;
    46524717
    4653         if ( ! empty( $number ) ) {
    4654                 $query .= ' LIMIT ' . $offset . ',' . $number;
     4718        if ( ! empty( $args['number'] ) ) {
     4719                $query .= ' LIMIT ' . $args['offset'] . ',' . $args['number'];
    46554720        }
    46564721
    4657         $pages = $wpdb->get_results($query);
     4722        return $wpdb->get_results($query);
     4723}
    46584724
    4659         if ( empty($pages) ) {
    4660                 /** This filter is documented in wp-includes/post.php */
    4661                 $pages = apply_filters( 'get_pages', array(), $r );
    4662                 return $pages;
    4663         }
     4725/**
     4726 * Retrieve a list of pages.
     4727 *
     4728 * @global wpdb $wpdb WordPress database abstraction object.
     4729 *
     4730 * @since 1.5.0
     4731 *
     4732 * @param array|string $args {
     4733 *     Optional. Array or string of arguments to retrieve pages.
     4734 *
     4735 *     @type int          $child_of     Page ID to return child and grandchild pages of.
     4736 *                                      Default 0, or no restriction.
     4737 *     @type string       $sort_order   How to sort retrieved pages. Accepts 'ASC', 'DESC'. Default 'ASC'.
     4738 *     @type string       $sort_column  What columns to sort pages by, comma-separated. Accepts 'post_author',
     4739 *                                      'post_date', 'post_title', 'post_name', 'post_modified', 'menu_order',
     4740 *                                      'post_modified_gmt', 'post_parent', 'ID', 'rand', 'comment_count'.
     4741 *                                      'post_' can be omitted for any values that start with it.
     4742 *                                      Default 'post_title'.
     4743 *     @type bool         $hierarchical Whether to return pages hierarchically. Default true.
     4744 *     @type array        $exclude      Array of page IDs to exclude. Default empty array.
     4745 *     @type array        $include      Array of page IDs to include. Cannot be used with `$child_of`,
     4746 *                                      `$parent`, `$exclude`, `$meta_key`, `$meta_value`, or `$hierarchical`.
     4747 *                                      Default empty array.
     4748 *     @type string       $meta_key     Only include pages with this meta key. Default empty.
     4749 *     @type string       $meta_value   Only include pages with this meta value. Requires `$meta_key`.
     4750 *                                      Default empty.
     4751 *     @type string       $authors      A comma-separated list of author IDs. Default empty.
     4752 *     @type int          $parent       Page ID to return direct children of. `$hierarchical` must be false.
     4753 *                                      Default -1, or no restriction.
     4754 *     @type string|array $exclude_tree Comma-separated string or array of page IDs to exclude.
     4755 *                                      Default empty array.
     4756 *     @type int          $number       The number of pages to return. Default 0, or all pages.
     4757 *     @type int          $offset       The number of pages to skip before returning. Requires `$number`.
     4758 *                                      Default 0.
     4759 *     @type string       $post_type    The post type to query. Default 'page'.
     4760 *     @type string       $post_status  A comma-separated list of post status types to include.
     4761 *                                      Default 'publish'.
     4762 * }
     4763 * @return array List of pages matching defaults or `$args`.
     4764 */
     4765function get_pages( $args = array() ) {
    46644766
    4665         // Sanitize before caching so it'll only get done once.
    4666         $num_pages = count($pages);
    4667         for ($i = 0; $i < $num_pages; $i++) {
    4668                 $pages[$i] = sanitize_post($pages[$i], 'raw');
    4669         }
     4767        // moved key here to preserve caching
     4768        $pages = get_pages_cached( $args ); // if pages from cache
     4769        if( !$pages ) {
     4770                get_pages_process_args( $args );
    46704771
    4671         // Update cache.
    4672         update_post_cache( $pages );
     4772                // Make sure the post type is hierarchical before wasting too much energy.
     4773                $heirarchical_post_types = get_post_types( array( 'hierarchical' => true ) );
     4774                if ( ! in_array( $args['post_type'], $heirarchical_post_types ) ) {
     4775                        return false;
     4776                }
    46734777
    4674         if ( $child_of || $hierarchical ) {
    4675                 $pages = get_page_children($child_of, $pages);
    4676         }
    4677 
    4678         if ( ! empty( $r['exclude_tree'] ) ) {
    4679                 $exclude = wp_parse_id_list( $r['exclude_tree'] );
    4680                 foreach( $exclude as $id ) {
    4681                         $children = get_page_children( $id, $pages );
    4682                         foreach ( $children as $child ) {
    4683                                 $exclude[] = $child->ID;
    4684                         }
     4778                if ( $args[ 'parent' ] > 0 && ! $args[ 'child_of' ] ) {
     4779                        $args[ 'heirarchical' ] = false;
    46854780                }
    46864781
    4687                 $num_pages = count( $pages );
    4688                 for ( $i = 0; $i < $num_pages; $i++ ) {
    4689                         if ( in_array( $pages[$i]->ID, $exclude ) ) {
    4690                                 unset( $pages[$i] );
    4691                         }
    4692                 }
     4782                if ( post_stati_valid( $args['post_status'] ) ) { return false; } // checking if post status is valid function added to DRY out this code
     4783               
     4784                $pages = build_get_pages_DB( $args );
    46934785        }
    46944786
    4695         $page_structure = array();
    4696         foreach ( $pages as $page ) {
    4697                 $page_structure[] = $page->ID;
     4787        if( !empty( $pages ) ) {
     4788                get_pages_update_cache( $args, $pages );
     4789        } else {
     4790                // this was a really strange check on this, here we simplify
     4791                $pages = array();
    46984792        }
    4699 
    4700         wp_cache_set( $cache_key, $page_structure, 'posts' );
    4701 
    4702         // Convert to WP_Post instances
    4703         $pages = array_map( 'get_post', $pages );
    4704 
     4793       
    47054794        /**
    47064795         * Filter the retrieved list of pages.
    47074796         *
     
    47084797         * @since 2.1.0
    47094798         *
    47104799         * @param array $pages List of pages to retrieve.
    4711          * @param array $r     Array of get_pages() arguments.
     4800         * @param array $args     Array of get_pages() arguments.
    47124801         */
    4713         $pages = apply_filters( 'get_pages', $pages, $r );
     4802        $pages = apply_filters( 'get_pages', $pages, $args );
    47144803
    47154804        return $pages;
    47164805}