public static function flt_nav_menu_items($items, $menu_name, $args)
 {
     global $wpdb;
     $item_types = array();
     //d_echo( '********************** enter flt_nav_menu_items <br /> ' );
     foreach ($items as $key => $item) {
         if (!isset($item_types[$item->type])) {
             $item_types["{$item->type}"] = array();
         }
         $item_types[$item->type][$item->object][$key] = $item->object_id;
     }
     $teaser_enabled = apply_filters('pp_teaser_enabled', false, 'post');
     // remove unreadable terms
     if (isset($item_types['taxonomy'])) {
         foreach ($item_types['taxonomy'] as $taxonomy => $item_ids) {
             $hide_empty = defined('PP_NAV_MENU_SHOW_EMPTY_TERMS') ? '0' : '1';
             $okay_ids = get_terms($taxonomy, "fields=ids&hide_empty={$hide_empty}");
             if ($remove_ids = apply_filters('pp_nav_menu_hide_terms', array_diff($item_ids, $okay_ids), $taxonomy)) {
                 $item_types['taxonomy'][$taxonomy] = array_diff($item_types['taxonomy'][$taxonomy], $remove_ids);
                 foreach (array_keys($items) as $key) {
                     if (!empty($items[$key]->type) && 'taxonomy' == $items[$key]->type && in_array($items[$key]->object_id, $remove_ids)) {
                         unset($items[$key]);
                     }
                 }
             }
         }
     }
     // remove or tease unreadable posts
     if (isset($item_types['post_type'])) {
         $post_types = array_keys($item_types['post_type']);
         $post_ids = pp_array_flatten($item_types['post_type']);
     } else {
         $post_types = $post_ids = array();
     }
     $pub_stati = pp_get_post_stati(array('public' => true, 'post_type' => $post_types));
     $pvt_stati = pp_get_post_stati(array('private' => true, 'post_type' => $post_types));
     $stati = array_merge($pub_stati, $pvt_stati);
     $clauses = array_fill_keys(array('distinct', 'join', 'groupby', 'orderby', 'limits'), '');
     $clauses['fields'] = 'ID';
     $clauses['where'] = "AND post_type IN ( '" . implode("','", $post_types) . "' ) AND ID IN ( '" . implode("','", $post_ids) . "') AND post_status IN ('" . implode("','", $stati) . "')";
     $clauses = apply_filters('pp_posts_clauses', $clauses, array('post_types' => $post_types, 'skip_teaser' => true, 'required_operation' => 'read', 'force_types' => true));
     $okay_ids = $wpdb->get_col("SELECT {$clauses['distinct']} ID FROM {$wpdb->posts} {$clauses['join']} WHERE 1=1 {$clauses['where']}");
     foreach ($post_types as $_post_type) {
         $remove_ids = array_diff($item_types['post_type'][$_post_type], $okay_ids);
         if ($remove_ids = apply_filters_ref_array('pp_nav_menu_hide_posts', array($remove_ids, &$items, $_post_type))) {
             foreach (array_keys($items) as $key) {
                 if (!empty($items[$key]->type) && 'post_type' == $items[$key]->type && in_array($items[$key]->object_id, $remove_ids)) {
                     unset($items[$key]);
                 }
             }
         }
     }
     //d_echo( '**************** exit flt_nav_menu_items <br /> ' );
     return $items;
 }
 public function flt_getarchives_where($where)
 {
     global $current_user, $wpdb, $query_interceptor;
     // possible @todo: implement in any other PP filters?
     require_once dirname(__FILE__) . '/lib/sql-tokenizer_pp.php';
     $parser = new SqlTokenizer_PP();
     $post_type = $parser->ParseArg($where, 'post_type');
     $where = str_replace("WHERE ", "WHERE {$wpdb->posts}.post_date > 0 AND ", $where);
     $stati = array_merge(pp_get_post_stati(array('public' => true, 'post_type' => $post_type)), pp_get_post_stati(array('private' => true, 'post_type' => $post_type)));
     if (!empty($current_user->ID)) {
         $where = str_replace("AND post_status = 'publish'", "AND post_status IN ('" . implode("','", $stati) . "')", $where);
     }
     $where = str_replace("WHERE ", "AND ", $where);
     $where = $query_interceptor->flt_posts_where($where, array('skip_teaser' => true, 'post_type' => $post_type));
     $where = 'WHERE 1=1 ' . $where;
     $this->archives_where = $where;
     return $where;
 }
예제 #3
0
 public static function add_exception_clauses($where, $required_operation, $post_type, $args = array())
 {
     $defaults = array('source_alias' => '', 'apply_term_restrictions' => true, 'append_post_type_clause' => true, 'additions_only' => false);
     extract(array_merge($defaults, $args), EXTR_SKIP);
     global $wpdb, $pp_current_user;
     $src_table = $source_alias ? $source_alias : $wpdb->posts;
     $exc_post_type = apply_filters('pp_exception_post_type', $post_type, $required_operation, $args);
     if (!$additions_only) {
         if ($where) {
             // where clause already indicates sitewide caps for one or more statuses (or just want the exceptions clause generated)
             if ($append_clause = apply_filters('pp_append_query_clause', '', $post_type, $required_operation, $args)) {
                 $where .= $append_clause;
             }
             $post_blockage_priority = pp_get_option('post_blockage_priority');
             $post_blockage_clause = '';
             foreach (array('include' => 'IN', 'exclude' => 'NOT IN') as $mod => $logic) {
                 if ($ids = $pp_current_user->get_exception_posts($required_operation, $mod, $exc_post_type)) {
                     $_args = array_merge($args, compact('mod', 'ids', 'src_table', 'logic'));
                     $clause_var = $post_blockage_priority ? 'post_blockage_clause' : 'where';
                     ${$clause_var} .= " AND " . apply_filters('pp_exception_clause', "{$src_table}.ID {$logic} ('" . implode("','", $ids) . "')", $required_operation, $post_type, $_args);
                     break;
                     // don't use both include and exclude clauses
                 }
             }
             // term restrictions which apply only to this post type
             if ($apply_term_restrictions) {
                 $where .= self::add_term_restrictions_clause($required_operation, $post_type, $src_table);
             }
         } else {
             $where = '1=2';
         }
     }
     $additions = array();
     $additional_ids = $pp_current_user->get_exception_posts($required_operation, 'additional', $exc_post_type, array('status' => true));
     foreach ($additional_ids as $_status => $_ids) {
         if ($_status) {
             // db storage is with "post_status:" prefix to allow for implementation of other attributes
             if (0 === strpos($_status, 'post_status:')) {
                 $_status = str_replace('post_status:', '', $_status);
             } else {
                 continue;
             }
         }
         if (!isset($additions[$_status])) {
             $additions[$_status] = array();
         }
         // facilitates user-add on post edit form without dealing with status caps
         $in_clause = "IN ('" . implode("','", $_ids) . "')";
         $additions[$_status][] = apply_filters('pp_additions_clause', "{$src_table}.ID {$in_clause}", $required_operation, $post_type, array('via_item_source' => 'post', 'status' => $_status, 'in_clause' => $in_clause, 'src_table' => $src_table));
     }
     $additional_ttids = array();
     foreach (pp_get_enabled_taxonomies(array('object_type' => $post_type)) as $taxonomy) {
         $tt_ids = $pp_current_user->get_exception_terms($required_operation, 'additional', $post_type, $taxonomy, array('status' => true, 'merge_universals' => true));
         // merge this taxonomy exceptions with other taxonomies
         foreach (array_keys($tt_ids) as $_status) {
             if (!isset($additional_ttids[$_status])) {
                 $additional_ttids[$_status] = array();
             }
             $additional_ttids[$_status] = array_merge($additional_ttids[$_status], $tt_ids[$_status]);
         }
     }
     if ($additional_ttids) {
         foreach ($additional_ttids as $_status => $_ttids) {
             if ($_status) {
                 if (0 === strpos($_status, 'post_status:')) {
                     $_status = str_replace('post_status:', '', $_status);
                 } else {
                     continue;
                 }
             }
             if (!isset($additions[$_status])) {
                 $additions[$_status] = array();
             }
             $in_clause = "IN ( SELECT object_id FROM {$wpdb->term_relationships} WHERE term_taxonomy_id IN ('" . implode("','", $_ttids) . "') )";
             $additions[$_status][] = apply_filters('pp_additions_clause', "{$src_table}.ID {$in_clause}", $required_operation, $post_type, array('via_item_source' => 'term', 'status' => $_status, 'in_clause' => $in_clause, 'src_table' => $src_table));
         }
     }
     foreach (array_keys($additions) as $_status) {
         switch ($_status) {
             case '':
                 $_status_clause = '';
                 break;
             case '{unpublished}':
                 if ('read' != $required_operation) {
                     // sanity check
                     $_stati = array_merge(pp_get_post_stati(array('public' => true, 'post_type' => $post_type)), pp_get_post_stati(array('private' => true, 'post_type' => $post_type)));
                     $_status_clause = "{$src_table}.post_status NOT IN ('" . implode("','", $_stati) . "') AND ";
                     break;
                 }
             default:
                 $_status_clause = "{$src_table}.post_status = '{$_status}' AND ";
                 break;
         }
         $additions[$_status] = $_status_clause . pp_implode(' OR ', $additions[$_status]);
     }
     if ($additions = apply_filters('pp_apply_additions', $additions, $where, $required_operation, $post_type, $args)) {
         $where = "( {$where} ) OR ( " . pp_implode(' OR ', $additions) . " )";
         if ($post_blockage_clause) {
             $post_blockage_clause = "AND ( ( 1=1 {$post_blockage_clause} ) OR ( " . pp_implode(' OR ', $additions) . " ) )";
         }
         /*
         $additions = pp_implode( ' OR ', $additions );
         
         if ( $append_post_type_clause )
         	$where = "$src_table.post_type = '$post_type' AND ( ( $where ) OR ( $additions ) )";
         else
         	$where = "( $where ) OR ( $additions )";
         		
         		} elseif ( $append_post_type_clause ) {
         $where = "$src_table.post_type = '$post_type' AND $where";
         */
     }
     if ($post_blockage_priority) {
         $where = "( {$where} ) {$post_blockage_clause}";
     }
     if ($append_post_type_clause) {
         $where = "{$src_table}.post_type = '{$post_type}' AND ( {$where} )";
     }
     return $where;
 }
예제 #4
0
 function get_typecast_caps($role_name)
 {
     $arr_name = explode(':', $role_name);
     if (empty($arr_name[2])) {
         return array();
     }
     // this role typecast is not db-defined, so generate it
     $base_role_name = $arr_name[0];
     $src_name = $arr_name[1];
     $object_type = $arr_name[2];
     // typecast role assignment stored, but undefined source name or object_type
     if (!($type_obj = pp_get_type_object($src_name, $object_type))) {
         return array();
     }
     // disregard stored Supplemental Roles for Media when Media is no longer enabled for PP filtering (otherwise Post editing caps are granted)
     if ('attachment' == $object_type) {
         static $media_filtering_enabled;
         if (!isset($media_filtering_enabled)) {
             $media_filtering_enabled = pp_get_enabled_post_types(array('name' => 'attachment'));
         }
         if (!$media_filtering_enabled) {
             return array();
         }
     }
     if (empty($this->pattern_role_type_caps)) {
         $this->define_pattern_caps();
     }
     $pattern_role_caps = 'term' == $src_name ? $this->pattern_role_taxonomy_caps : $this->pattern_role_type_caps;
     if (empty($pattern_role_caps[$base_role_name])) {
         // if the role definition is not currently configured for Pattern Role usage, disregard the assignment
         return array();
     }
     if (!defined('PPS_VERSION') && strpos($role_name, 'post_status:private') && isset($pattern_role_caps[$base_role_name]['read'])) {
         $pattern_role_caps[$base_role_name]['read_private_posts'] = true;
     }
     if (!empty($arr_name[3])) {
         if (empty($arr_name[4])) {
             // disregard stored roles with invalid status
             return array();
         } elseif ('post_status' == $arr_name[3]) {
             // ignore supplemental roles for statuses which are no longer active for this post type
             if (!pp_get_post_stati(array('name' => $arr_name[4], 'post_type' => $object_type))) {
                 return array();
             }
         }
     }
     // add all type-specific caps whose base property cap is included in this pattern role
     // i.e. If 'edit_posts' is in the pattern role, grant $type_obj->cap->edit_posts
     //
     if ($caps = array_intersect_key((array) get_object_vars($type_obj->cap), $pattern_role_caps[$base_role_name])) {
         // At least one type-defined cap is being cast from this pattern role for specified object_type
         $status_caps = apply_filters('pp_get_typecast_caps', $caps, $arr_name, $type_obj);
         if (!empty($arr_name[3]) && false === strpos($role_name, 'post_status:private') && $caps == $status_caps) {
             // if stored status value is invalid, don't credit user for "default statuses" type caps (but allow for subscriber-private if PPS inactive
             return array();
         } else {
             return apply_filters('pp_apply_arbitrary_caps', $status_caps, $arr_name, $type_obj);
         }
     }
     return $caps;
 }
예제 #5
0
 function get_posts_where($args)
 {
     $defaults = array('post_types' => array(), 'source_alias' => false, 'src_table' => '', 'apply_term_restrictions' => true, 'include_trash' => 0, 'required_operation' => '', 'limit_statuses' => false, 'skip_teaser' => false, 'query_contexts' => array(), 'force_types' => false);
     $args = array_merge($defaults, (array) $args);
     extract($args, EXTR_SKIP);
     //d_echo ("<br /><strong>get_posts_where:</strong> <br />");
     global $wpdb;
     if (!$src_table) {
         $src_table = $source_alias ? $source_alias : $wpdb->posts;
         $args['src_table'] = $src_table;
     }
     if (!$force_types) {
         $post_types = array_intersect((array) $post_types, pp_get_enabled_post_types());
     }
     $tease_otypes = array_intersect($post_types, $this->_get_teaser_post_types($post_types, $args));
     if (!$required_operation) {
         $required_operation = pp_is_front() && !is_preview() ? 'read' : 'edit';
         $args['required_operation'] = $required_operation;
     }
     if ($query_contexts) {
         $query_contexts = (array) $query_contexts;
     }
     $meta_cap = "{$required_operation}_post";
     if ('read' == $required_operation) {
         $use_statuses = array_merge(pp_get_post_stati(array('public' => true, 'post_type' => $post_types), 'object'), pp_get_post_stati(array('private' => true, 'post_type' => $post_types), 'object'));
         foreach ($use_statuses as $key => $obj) {
             if (!empty($obj->exclude_from_search)) {
                 // example usage is bbPress hidden status
                 unset($use_statuses[$key]);
             }
         }
     } else {
         $use_statuses = pp_get_post_stati(array('internal' => false, 'post_type' => $post_types), 'object');
     }
     if (in_array('attachment', $post_types)) {
         $use_statuses['inherit'] = (object) array();
     }
     if (is_array($limit_statuses)) {
         $use_statuses = array_intersect_key($use_statuses, $limit_statuses);
     }
     if (empty($skip_teaser) && !array_diff($post_types, $tease_otypes)) {
         // All object types potentially returned by this query will have a teaser filter applied to results, so we don't need to use further query filtering
         $status_clause = "AND {$src_table}.post_status IN ('" . implode("','", array_keys($use_statuses)) . "')";
         return $status_clause;
     }
     if (!is_bool($include_trash)) {
         if (!empty($_REQUEST['post_status']) && 'trash' == $_REQUEST['post_status']) {
             $include_trash = true;
         }
     }
     $where_arr = array();
     global $pp_current_user;
     global $pp_meta_caps;
     $flag_meta_caps = !empty($pp_meta_caps);
     foreach ($post_types as $post_type) {
         if (in_array($post_type, $tease_otypes) && empty($skip_teaser)) {
             $where_arr[$post_type] = "{$src_table}.post_type = '{$post_type}' AND 1=1";
         } else {
             $have_site_caps = array();
             $type_obj = get_post_type_object($post_type);
             foreach (array_keys($use_statuses) as $status) {
                 if ('private' == $status) {
                     $cap_property = "{$required_operation}_private_posts";
                     if (empty($type_obj->cap->{$cap_property})) {
                         continue;
                     }
                 }
                 if ($flag_meta_caps) {
                     $pp_meta_caps->do_status_cap_map = true;
                 }
                 $reqd_caps = pp_map_meta_cap($meta_cap, $pp_current_user->ID, 0, compact('post_type', 'status', 'query_contexts'));
                 if ($flag_meta_caps) {
                     $pp_meta_caps->do_status_cap_map = false;
                 }
                 if ($reqd_caps) {
                     // note: this function is called only for listing query filters (not for user_has_cap filter)
                     if ($missing_caps = apply_filters('pp_query_missing_caps', array_diff($reqd_caps, array_keys($pp_current_user->allcaps)), $reqd_caps, $post_type, $meta_cap)) {
                         $owner_reqd_caps = $this->get_base_caps($reqd_caps, $post_type);
                         // remove "others" and "private" cap requirements for post author
                         if ($owner_reqd_caps != $reqd_caps && $pp_current_user->ID) {
                             // && ! $omit_owner_clause
                             if (!array_diff($owner_reqd_caps, array_keys($pp_current_user->allcaps))) {
                                 $have_site_caps['owner'][] = $status;
                             }
                         }
                     } else {
                         $have_site_caps['user'][] = $status;
                     }
                 }
             }
             $have_site_caps = apply_filters('pp_have_site_caps', $have_site_caps, $post_type, $args);
             if ($include_trash) {
                 if ($type_obj = get_post_type_object($post_type)) {
                     if ('edit_post' == $meta_cap && !empty($pp_current_user->allcaps[$type_obj->cap->edit_posts]) || 'delete_post' == $meta_cap && !empty($pp_current_user->allcaps[$type_obj->cap->delete_posts])) {
                         if (!isset($type_obj->cap->delete_others_posts) || !empty($pp_current_user->allcaps[$type_obj->cap->delete_others_posts])) {
                             $have_site_caps['user'][] = 'trash';
                         } else {
                             $have_site_caps['owner'][] = 'trash';
                         }
                     }
                 }
             }
             $where_arr[$post_type] = array();
             if (!empty($have_site_caps['user'])) {
                 $where_arr[$post_type]['user'] = "******" . implode("','", array_unique($have_site_caps['user'])) . "')";
             }
             //dump($have_site_caps);
             if (!empty($have_site_caps['owner'])) {
                 $parent_clause = '';
                 // PPCE may be set to "ID IN (...) OR " to enable post revisors to edit their own pending revisions
                 $args['post_type'] = $post_type;
                 $_vars = apply_filters('pp_generate_where_clause_force_vars', null, 'post', $args);
                 if (is_array($_vars)) {
                     extract($_vars);
                     // possible @todo: intersect keys as with pp_has_cap_force_vars
                 }
                 if (!empty($args['skip_stati_usage_clause']) && !$limit_statuses && !array_diff_key($use_statuses, array_flip($have_site_caps['owner']))) {
                     $where_arr[$post_type]['owner'] = "{$parent_clause} ( {$src_table}.post_author = {$pp_current_user->ID} )";
                 } else {
                     $where_arr[$post_type]['owner'] = "{$parent_clause} ( {$src_table}.post_author = {$pp_current_user->ID} ) AND {$src_table}.post_status IN ('" . implode("','", array_unique($have_site_caps['owner'])) . "')";
                 }
             }
             if (is_array($where_arr[$post_type])) {
                 if ($where_arr[$post_type]) {
                     $where_arr[$post_type] = pp_implode('OR', $where_arr[$post_type]);
                     $where_arr[$post_type] = "1=1 AND ( " . $where_arr[$post_type] . " )";
                 } else {
                     $where_arr[$post_type] = '1=2';
                 }
             }
             if ($modified = apply_filters('pp_adjust_posts_where_clause', false, $where_arr[$post_type], $post_type, $args)) {
                 $where_arr[$post_type] = $modified;
             }
             if ('attachment' == $post_type) {
                 if ('read' == $required_operation || apply_filters('pp_force_attachment_parent_clause', false, $args)) {
                     //if ( ( 'read' == $required_operation ) || ( defined('DOING_AJAX') && DOING_AJAX && ( false != strpos( $_SERVER['REQUEST_URI'], 'async-upload.php' ) ) ) || apply_filters( 'pp_force_attachment_parent_clause', false, $args ) ) {
                     $where_arr[$post_type] = "( " . $this->append_attachment_clause("{$src_table}.post_type = 'attachment'", array(), $args) . " )";
                 }
             }
             if ('delete' == $required_operation) {
                 $const = "PP_EDIT_EXCEPTIONS_ALLOW_" . strtoupper($post_type) . "_DELETION";
                 if (defined('PP_EDIT_EXCEPTIONS_ALLOW_DELETION') || defined($const)) {
                     $required_operation = 'edit';
                 }
             }
             $where_arr[$post_type] = PP_Exceptions::add_exception_clauses($where_arr[$post_type], $required_operation, $post_type, $args);
         }
     }
     // end foreach post_type
     if (!($pp_where = pp_implode('OR', $where_arr))) {
         $pp_where = '1=1';
     }
     // term restrictions which apply to any post type
     if ($apply_term_restrictions) {
         if ($term_exc_where = PP_Exceptions::add_term_restrictions_clause($required_operation, '', $src_table, array('merge_universals' => true, 'merge_additions' => true, 'exempt_post_types' => $tease_otypes))) {
             $pp_where = "( {$pp_where} ) {$term_exc_where}";
         }
     }
     if ($pp_where) {
         $pp_where = " AND ( {$pp_where} )";
     }
     return $pp_where;
 }
예제 #6
0
 public static function flt_get_pages($results, $args = array())
 {
     $results = (array) $results;
     global $wpdb;
     // === BEGIN PP ADDITION: global var; various special case exemption checks ===
     //
     global $pp, $current_user;
     // buffer titles in case they were filtered previously
     $titles = pp_get_property_array($results, 'ID', 'post_title');
     // depth is not really a get_pages arg, but remap exclude arg to exclude_tree if wp_list_terms called with depth=1
     if (!empty($args['exclude']) && empty($args['exclude_tree']) && !empty($args['depth']) && 1 == $args['depth']) {
         if (0 !== strpos($args['exclude'], ',')) {
             // work around wp_list_pages() bug of attaching leading comma if a plugin uses wp_list_pages_excludes filter
             $args['exclude_tree'] = $args['exclude'];
         }
     }
     //
     // === END PP ADDITION ===
     // =================================
     $defaults = array('child_of' => 0, 'sort_order' => 'ASC', 'sort_column' => 'post_title', 'hierarchical' => 1, 'exclude' => array(), 'include' => array(), 'meta_key' => '', 'meta_value' => '', 'authors' => '', 'parent' => -1, 'exclude_tree' => '', 'number' => '', 'offset' => 0, 'post_type' => 'page', 'post_status' => 'publish', 'depth' => 0, 'suppress_filters' => 0, 'required_operation' => '', 'alternate_operation' => '');
     // PP arguments added above
     // === BEGIN PP ADDITION: support front-end optimization
     $post_type = isset($args['post_type']) ? $args['post_type'] : $defaults['post_type'];
     $enabled_post_types = pp_get_enabled_post_types();
     if (defined('PP_UNFILTERED_FRONT')) {
         if (defined('PP_UNFILTERED_FRONT_TYPES')) {
             $unfiltered_types = str_replace(' ', '', PP_UNFILTERED_FRONT_TYPES);
             $unfiltered_types = explode(',', constant($unfiltered_types));
             $enabled_post_types = array_diff($enabled_post_types, $unfiltered_types);
         } else {
             return $results;
         }
     }
     if (!in_array($post_type, $enabled_post_types)) {
         return $results;
     }
     if (pp_is_front()) {
         if ('page' == $post_type && defined('PP_GET_PAGES_LEAN')) {
             // custom types are likely to have custom fields
             $defaults['fields'] = "{$wpdb->posts}.ID, {$wpdb->posts}.post_title, {$wpdb->posts}.post_parent, {$wpdb->posts}.post_date, {$wpdb->posts}.post_date_gmt, {$wpdb->posts}.post_status, {$wpdb->posts}.post_name, {$wpdb->posts}.post_modified, {$wpdb->posts}.post_modified_gmt, {$wpdb->posts}.guid, {$wpdb->posts}.menu_order, {$wpdb->posts}.comment_count";
         } else {
             $defaults['fields'] = "{$wpdb->posts}.*";
         }
     } else {
         // required for xmlrpc getpagelist method
         $defaults['fields'] = "{$wpdb->posts}.*";
     }
     // === END PP MODIFICATION ===
     $r = wp_parse_args($args, $defaults);
     $args['number'] = (int) $r['number'];
     $args['offset'] = absint($r['offset']);
     $args['child_of'] = (int) $r['child_of'];
     extract(apply_filters('pp_get_pages_args', $r), EXTR_SKIP);
     // PPE filter modifies append_page, exclude_tree
     // workaround for CMS Tree Page View (passes post_parent instead of parent)
     if (-1 == $parent && isset($args['post_parent'])) {
         $args['parent'] = $args['post_parent'];
         $parent = $args['post_parent'];
     }
     // Make sure the post type is hierarchical
     $hierarchical_post_types = get_post_types(array('public' => true, 'hierarchical' => true));
     if (!in_array($post_type, $hierarchical_post_types)) {
         return $results;
     }
     // Make sure we have a valid post status
     if (is_admin() && 'any' === $post_status) {
         $post_status = '';
     }
     if ($post_status) {
         if (!is_array($post_status) && strpos($post_status, ',')) {
             $post_status = explode(',', $post_status);
         }
         if (array_diff((array) $post_status, get_post_stati())) {
             return $results;
         }
     }
     $intercepted_pages = apply_filters('pp_get_pages_intercept', false, $results, $args);
     if (is_array($intercepted_pages)) {
         return $intercepted_pages;
     }
     //$pp->last_get_pages_args = $r; // don't copy entire args array unless it proves necessary
     $pp->last_get_pages_depth = $depth;
     $pp->last_get_pages_suppress_filters = $suppress_filters;
     if ($suppress_filters) {
         return $results;
     }
     $orderby_array = array();
     $allowed_keys = array('author', 'post_author', 'date', 'post_date', 'title', 'post_title', 'name', 'post_name', 'modified', 'post_modified', 'modified_gmt', 'post_modified_gmt', 'menu_order', 'parent', 'post_parent', 'ID', 'rand', 'comment_count');
     foreach (explode(',', $sort_column) as $orderby) {
         $orderby = trim($orderby);
         if (!in_array($orderby, $allowed_keys)) {
             continue;
         }
         switch ($orderby) {
             case 'menu_order':
                 break;
             case 'ID':
                 $orderby = "{$wpdb->posts}.ID";
                 break;
             case 'rand':
                 $orderby = 'RAND()';
                 break;
             case 'comment_count':
                 $orderby = "{$wpdb->posts}.comment_count";
                 break;
             default:
                 if (0 === strpos($orderby, 'post_')) {
                     $orderby = "{$wpdb->posts}." . $orderby;
                 } else {
                     $orderby = "{$wpdb->posts}.post_" . $orderby;
                 }
         }
         $orderby_array[] = $orderby;
     }
     $sort_column = !empty($orderby_array) ? implode(',', $orderby_array) : "{$wpdb->posts}.post_title";
     // $args can be whatever, only use the args defined in defaults to compute the key
     $key = md5(serialize(compact(array_keys($defaults))));
     $last_changed = wp_cache_get('last_changed', 'posts');
     if (!$last_changed) {
         $last_changed = microtime();
         wp_cache_set('last_changed', $last_changed, 'posts');
     }
     $cache_key = "pp_get_pages:{$key}:{$last_changed}";
     if ($cache = wp_cache_get($cache_key, 'posts')) {
         // Convert to WP_Post instances
         $pages = array_map('get_post', $cache);
         $pages = apply_filters('pp_get_pages', $pages, $r);
         return $pages;
     }
     $inclusions = '';
     if (!empty($include)) {
         $child_of = 0;
         //ignore child_of, parent, exclude, meta_key, and meta_value params if using include
         $parent = -1;
         $exclude = '';
         $meta_key = '';
         $meta_value = '';
         $hierarchical = false;
         $incpages = wp_parse_id_list($include);
         if (!empty($incpages)) {
             foreach ($incpages as $incpage) {
                 if (empty($inclusions)) {
                     $inclusions = ' AND ( ID = ' . intval($incpage) . ' ';
                 } else {
                     $inclusions .= ' OR ID = ' . intval($incpage) . ' ';
                 }
             }
         }
     }
     if (!empty($inclusions)) {
         $inclusions .= ')';
     }
     $exclusions = '';
     if (!empty($exclude)) {
         $expages = wp_parse_id_list($exclude);
         if (!empty($expages)) {
             foreach ($expages as $expage) {
                 if (empty($exclusions)) {
                     $exclusions = ' AND ( ID <> ' . intval($expage) . ' ';
                 } else {
                     $exclusions .= ' AND ID <> ' . intval($expage) . ' ';
                 }
             }
         }
     }
     if (!empty($exclusions)) {
         $exclusions .= ')';
     }
     $author_query = '';
     if (!empty($authors)) {
         $post_authors = wp_parse_id_list($authors);
         if (!empty($post_authors)) {
             foreach ($post_authors as $post_author) {
                 //Do we have an author id or an author login?
                 if (0 == intval($post_author)) {
                     $post_author = get_user_by('login', $post_author);
                     if (empty($post_author)) {
                         continue;
                     }
                     if (empty($post_author->ID)) {
                         continue;
                     }
                     $post_author = $post_author->ID;
                 }
                 if ('' == $author_query) {
                     $author_query = ' post_author = ' . intval($post_author) . ' ';
                 } else {
                     $author_query .= ' OR post_author = ' . intval($post_author) . ' ';
                 }
             }
             if ('' != $author_query) {
                 $author_query = " AND ({$author_query})";
             }
         }
     }
     $join = '';
     $where = "{$exclusions} {$inclusions} ";
     if (!empty($meta_key) || !empty($meta_value)) {
         $join = " INNER JOIN {$wpdb->postmeta} ON {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id";
         // PP MODIFICATION: was LEFT JOIN in WP 3.0 core
         // meta_key and meta_value might be slashed
         $meta_key = stripslashes($meta_key);
         $meta_value = stripslashes($meta_value);
         if (!empty($meta_key)) {
             $where .= $wpdb->prepare(" AND {$wpdb->postmeta}.meta_key = %s", $meta_key);
         }
         if (!empty($meta_value)) {
             $where .= $wpdb->prepare(" AND {$wpdb->postmeta}.meta_value = %s", $meta_value);
         }
     }
     if ($parent >= 0) {
         $where .= $wpdb->prepare(' AND ' . apply_filters('pp_get_pages_parent', 'post_parent = %d ', $args), $parent);
     }
     // === BEGIN PP MODIFICATION:
     // allow pages of multiple statuses to be displayed (requires default status=publish to be ignored)
     //
     $where_post_type = $wpdb->prepare("post_type = %s", $post_type);
     $where_status = '';
     global $current_user;
     $is_front = pp_is_front();
     if ($is_front && !empty($current_user->ID)) {
         $frontend_list_private = !defined('PP_SUPPRESS_PRIVATE_PAGES');
     } else {
         $frontend_list_private = false;
     }
     $force_publish_status = !$frontend_list_private && 'publish' == $post_status;
     if ($is_front) {
         // since we will be applying status clauses based on content-specific roles, only a sanity check safeguard is needed when post_status is unspecified or defaulted to "publish"
         $safeguard_statuses = array();
         foreach (pp_get_post_stati(array('internal' => false, 'post_type' => $post_type), 'object') as $status_name => $status_obj) {
             if (!$is_front || $status_obj->private || $status_obj->public) {
                 $safeguard_statuses[] = $status_name;
             }
         }
     }
     // WP core does not include private pages in query.  Include private statuses in anticipation of user-specific filtering
     if (is_array($post_status)) {
         $where_status = "AND post_status IN ('" . implode("','", $post_status) . "')";
     } elseif ($post_status && ('publish' != $post_status || $is_front && !$frontend_list_private)) {
         $where_status = $wpdb->prepare("AND post_status = %s", $post_status);
     } elseif ($is_front) {
         $where_status = "AND post_status IN ('" . implode("','", $safeguard_statuses) . "')";
     } else {
         $where_status = "AND post_status NOT IN ('" . implode("','", get_post_stati(array('internal' => true))) . "')";
     }
     $where_id = '';
     global $pagenow;
     if (is_admin() && in_array($pagenow, array('post.php', 'post-new.php'))) {
         global $post;
         if ($post) {
             $where_id = "AND ID != {$post->ID}";
         }
     }
     $where = "AND {$where_post_type} AND ( 1=1 {$where_status} {$where} {$author_query} {$where_id} )";
     $orderby = "ORDER BY {$sort_column} {$sort_order}";
     $limits = !empty($number) ? ' LIMIT ' . $offset . ',' . $number : '';
     $query = "SELECT {$fields} FROM {$wpdb->posts} {$join} WHERE 1=1 {$where} {$orderby} {$limits}";
     if (pp_is_front() && apply_filters('pp_teaser_enabled', false, 'post', $post_type) && !defined('PP_TEASER_HIDE_PAGE_LISTING')) {
         // We are in the front end and the teaser is enabled for pages
         // TODO: move to PPTX
         $query = str_replace("post_status = 'publish'", " post_status IN ('" . implode("','", $safeguard_statuses) . "')", $query);
         $pages = $wpdb->get_results($query);
         // execute unfiltered query
         // Pass results of unfiltered query through the teaser filter.
         // If listing private pages is disabled, they will be omitted completely, but restricted published pages
         // will still be teased.  This is a slight design compromise to satisfy potentially conflicting user goals without yet another option
         $pages = apply_filters('pp_posts_teaser', $pages, $post_type, array('request' => $query, 'force_teaser' => true));
         $tease_all = true;
     } else {
         $_args = array('skip_teaser' => true, 'retain_status' => $force_publish_status);
         $groupby = $distinct = '';
         global $pagenow;
         if (in_array($pagenow, array('post.php', 'post-new.php'))) {
             $clauses = apply_filters('pp_get_pages_clauses', compact('distinct', 'fields', 'join', 'where', 'groupby', 'orderby', 'limits'), $post_type, $args);
         } else {
             // Pass query through the request filter
             $_args['post_types'] = $post_type;
             if ($required_operation) {
                 $_args['required_operation'] = $required_operation;
             } else {
                 $_args['required_operation'] = pp_is_front() && !is_preview() ? 'read' : 'edit';
             }
             if ('edit' == $_args['required_operation'] && isset($args['post_parent']) || 'associate' == $alternate_operation) {
                 // workaround for CMS Page View
                 $_args['alternate_required_ops'] = array('associate');
             }
             $clauses = apply_filters('pp_posts_clauses', compact('distinct', 'fields', 'join', 'where', 'groupby', 'orderby', 'limits'), $_args);
         }
         // Execute the filtered query
         $pages = $wpdb->get_results("SELECT {$distinct} {$clauses['fields']} FROM {$wpdb->posts} {$clauses['join']} WHERE 1=1 {$clauses['where']} {$clauses['orderby']} {$clauses['limits']}");
     }
     if (empty($pages)) {
         // alternate hook name (WP core already applied get_pages filter)
         return apply_filters('pp_get_pages', array(), $r);
     }
     if ($child_of) {
         $pages = get_page_children($child_of, $pages);
     }
     // restore buffered titles in case they were filtered previously
     pp_restore_property_array($pages, $titles, 'ID', 'post_title');
     //
     // === END PP MODIFICATION ===
     // ====================================
     $num_pages = count($pages);
     for ($i = 0; $i < $num_pages; $i++) {
         $pages[$i] = sanitize_post($pages[$i], 'raw');
     }
     // Press Permit note: WP core get_pages has already updated wp_cache and pagecache with unfiltered results.
     update_post_cache($pages);
     // === BEGIN PP MODIFICATION: Support a disjointed pages tree with some parents hidden ========
     if ($child_of || empty($tease_all)) {
         // if we're including all pages with teaser, no need to continue thru tree remapping
         $ancestors = PP_Ancestry::get_page_ancestors();
         // array of all ancestor IDs for keyed page_id, with direct parent first
         $orderby = $sort_column;
         $remap_args = compact('child_of', 'parent', 'exclude', 'depth', 'orderby');
         // one or more of these args may have been modified after extraction
         PP_Ancestry::remap_tree($pages, $ancestors, $remap_args);
     }
     // === END PP MODIFICATION ===
     // ====================================
     if (!empty($exclude_tree)) {
         $exclude = array();
         $exclude = (int) $exclude_tree;
         $children = get_page_children($exclude, $pages);
         // PP note: okay to use unfiltered WP function here since it's only used for excluding
         $excludes = array();
         foreach ($children as $child) {
             $excludes[] = $child->ID;
         }
         $excludes[] = $exclude;
         $total = count($pages);
         for ($i = 0; $i < $total; $i++) {
             if (isset($pages[$i]) && in_array($pages[$i]->ID, $excludes)) {
                 unset($pages[$i]);
             }
         }
     }
     if (!empty($append_page) && !empty($pages)) {
         $found = false;
         foreach (array_keys($pages) as $key) {
             if ($append_page->ID == $pages[$key]->ID) {
                 $found = true;
                 break;
             }
         }
         if (empty($found)) {
             $pages[] = $append_page;
         }
     }
     // re-index the array, just in case anyone cares
     $pages = array_values($pages);
     $page_structure = array();
     foreach ($pages as $page) {
         $page_structure[] = $page->ID;
     }
     wp_cache_set($cache_key, $page_structure, 'posts');
     // Convert to WP_Post instances
     $pages = array_map('get_post', $pages);
     // alternate hook name (WP core already applied get_pages filter)
     return apply_filters('pp_get_pages', $pages, $r);
 }