Пример #1
0
 public function fetch_entries($args, &$total_count = NULL)
 {
     require_once 'class.mt_entry.php';
     $extras = array();
     if ($sql = $this->include_exclude_blogs($args)) {
         $blog_filter = 'and entry_blog_id ' . $sql;
         $mt = MT::get_instance();
         $ctx = $mt->context();
         $blog = $ctx->stash('blog');
         if (!empty($blog)) {
             $blog_id = $blog->blog_id;
         }
     } elseif (isset($args['blog_id'])) {
         $blog_id = intval($args['blog_id']);
         $blog_filter = 'and entry_blog_id = ' . $blog_id;
         $blog = $this->fetch_blog($blog_id);
     }
     if (empty($blog)) {
         return null;
     }
     // determine any custom fields that we should filter on
     $fields = array();
     foreach ($args as $name => $v) {
         if (preg_match('/^field___(\\w+)$/', $name, $m)) {
             $fields[$m[1]] = $v;
         }
     }
     # automatically include offset if in request
     if ($args['offset'] == 'auto') {
         $args['offset'] = 0;
         if ($args['limit'] || $args['lastn']) {
             if (intval($_REQUEST['offset']) > 0) {
                 $args['offset'] = intval($_REQUEST['offset']);
             }
         }
     }
     if ($args['limit'] > 0) {
         $args['lastn'] = $args['limit'];
     } elseif (!isset($args['days']) && !isset($args['lastn'])) {
         #            if ($days = $blog['blog_days_on_index']) {
         #                if (!isset($args['recently_commented_on'])) {
         #                    $args['days'] = $days;
         #                }
         #            } elseif ($posts = $blog['blog_entries_on_index']) {
         #                $args['lastn'] = $posts;
         #            }
     }
     if ($args['limit'] == 'auto') {
         if (intval($_REQUEST['limit']) > 0 && intval($_REQUEST['limit']) < $args['lastn']) {
             $args['lastn'] = intval($_REQUEST['limit']);
         } elseif (!isset($args['days']) && !isset($args['lastn'])) {
             if ($days = $blog->blog_days_on_index) {
                 if (!isset($args['recently_commented_on'])) {
                     $args['days'] = $days;
                 }
             } elseif ($posts = $blog->blog_entries_on_index) {
                 $args['lastn'] = $posts;
             }
         }
     }
     if (isset($args['include_blogs']) or isset($args['exclude_blogs'])) {
         $blog_ctx_arg = isset($args['include_blogs']) ? array('include_blogs' => $args['include_blogs']) : array('exclude_blogs' => $args['exclude_blogs']);
         if (isset($args['include_blogs']) && isset($args['include_with_website'])) {
             $blog_ctx_arg = array_merge($blog_ctx_arg, array('include_with_website' => $args['include_with_website']));
         }
     }
     # a context hash for filter routines
     $ctx = array();
     $filters = array();
     if (!isset($_REQUEST['entry_ids_published'])) {
         $_REQUEST['entry_ids_published'] = array();
     }
     if (isset($args['unique']) && $args['unique']) {
         $filters[] = create_function('$e,$ctx', 'return !isset($ctx["entry_ids_published"][$e->entry_id]);');
         $ctx['entry_ids_published'] =& $_REQUEST['entry_ids_published'];
     }
     # special case for selecting a particular entry
     if (isset($args['entry_id'])) {
         $entry_filter = 'and entry_id = ' . $args['entry_id'];
         $start = '';
         $end = '';
         $limit = 1;
         $blog_filter = '';
         $day_filter = '';
     } else {
         $entry_filter = '';
     }
     # special case for selecting some particular entries
     if (isset($args['entry_ids'])) {
         $entry_filter .= ' and entry_id IN (' . join(',', preg_grep('/\\A\\d+\\z/', $args['entry_ids'])) . ')';
     }
     # special case for excluding a particular entry
     if (isset($args['not_entry_id'])) {
         $entry_filter .= ' and entry_id != ' . $args['not_entry_id'];
     }
     $entry_list = array();
     # Adds a category filter to the filters list.
     $cat_class = 'category';
     if (!isset($args['class'])) {
         $args['class'] = 'entry';
     }
     if ($args['class'] == 'page') {
         $cat_class = 'folder';
     }
     if (isset($args['category']) or isset($args['categories'])) {
         $category_arg = isset($args['category']) ? $args['category'] : $args['categories'];
         require_once "MTUtil.php";
         if (!preg_match('/\\b(AND|OR|NOT)\\b|\\(|\\)/i', $category_arg)) {
             $not_clause = false;
             $cats = cat_path_to_category($category_arg, $blog_ctx_arg, $cat_class);
             if (empty($cats)) {
                 return null;
             } else {
                 $category_arg = '';
                 foreach ($cats as $cat) {
                     if ($category_arg != '') {
                         $category_arg .= '|| ';
                     }
                     $category_arg .= '#' . $cat->category_id;
                 }
                 $category_arg = '(' . $category_arg . ')';
             }
         } else {
             $not_clause = preg_match('/\\bNOT\\b/i', $category_arg);
             if ($blog_ctx_arg) {
                 $cats = $this->fetch_categories(array_merge($blog_ctx_arg, array('show_empty' => 1, 'class' => $cat_class)));
             } else {
                 $cats = $this->fetch_categories(array('blog_id' => $blog_id, 'show_empty' => 1, 'class' => $cat_class));
             }
         }
         if (!empty($cats)) {
             $cexpr = create_cat_expr_function($category_arg, $cats, array('children' => $args['include_subcategories']));
             if ($cexpr) {
                 $cmap = array();
                 $cat_list = array();
                 foreach ($cats as $cat) {
                     $cat_list[] = $cat->category_id;
                 }
                 $pl = $this->fetch_placements(array('category_id' => $cat_list));
                 if (!empty($pl)) {
                     foreach ($pl as $p) {
                         $cmap[$p->placement_entry_id][$p->placement_category_id]++;
                         if (!$not_clause) {
                             $entry_list[$p->placement_entry_id] = 1;
                         }
                     }
                 }
                 $ctx['p'] =& $cmap;
                 $filters[] = $cexpr;
             } else {
                 return null;
             }
         }
     } elseif (isset($args['category_id'])) {
         require_once "MTUtil.php";
         $cat = $this->fetch_category($args['category_id']);
         if (!empty($cat)) {
             $cats = array($cat);
             $cmap = array();
             $cexpr = create_cat_expr_function($cat->category_label, $cats, array('children' => $args['include_subcategories']));
             $pl = $this->fetch_placements(array('category_id' => array($cat->category_id)));
             if (!empty($pl)) {
                 foreach ($pl as $p) {
                     $cmap[$p->placement_entry_id][$p->placement_category_id]++;
                 }
                 $ctx['p'] =& $cmap;
                 $filters[] = $cexpr;
             } else {
                 # this category have no entries (or pages)
                 return null;
             }
         } else {
             # this category have no entries (or pages)
             return null;
         }
     }
     if (0 == count($filters) && (isset($args['show_empty']) && 1 == $args['show_empty'])) {
         return null;
     }
     # Adds a tag filter to the filters list.
     if (isset($args['tags']) or isset($args['tag'])) {
         $tag_arg = isset($args['tag']) ? $args['tag'] : $args['tags'];
         require_once "MTUtil.php";
         $not_clause = preg_match('/\\bNOT\\b/i', $tag_arg);
         $include_private = 0;
         $tag_array = tag_split($tag_arg);
         foreach ($tag_array as $tag) {
             if ($tag && substr($tag, 0, 1) == '@') {
                 $include_private = 1;
             }
         }
         if (isset($blog_ctx_arg)) {
             $tags = $this->fetch_entry_tags(array_merge($blog_ctx_arg, array('tag' => $tag_arg, 'include_private' => $include_private, 'class' => $args['class'])));
         } else {
             $tags = $this->fetch_entry_tags(array('blog_id' => $blog_id, 'tag' => $tag_arg, 'include_private' => $include_private, 'class' => $args['class']));
         }
         if (!is_array($tags)) {
             $tags = array();
         }
         $cexpr = create_tag_expr_function($tag_arg, $tags);
         if ($cexpr) {
             $tmap = array();
             $tag_list = array();
             foreach ($tags as $tag) {
                 $tag_list[] = $tag->tag_id;
             }
             if (isset($blog_ctx_arg)) {
                 $ot = $this->fetch_objecttags(array_merge($blog_ctx_arg, array('tag_id' => $tag_list, 'datasource' => 'entry')));
             } else {
                 $ot = $this->fetch_objecttags(array('tag_id' => $tag_list, 'datasource' => 'entry', 'blog_id' => $blog_id));
             }
             if ($ot) {
                 foreach ($ot as $o) {
                     $tmap[$o->objecttag_object_id][$o->objecttag_tag_id]++;
                     if (!$not_clause) {
                         $entry_list[$o->objecttag_object_id] = 1;
                     }
                 }
             }
             $ctx['t'] =& $tmap;
             $filters[] = $cexpr;
         } else {
             return null;
         }
     }
     # Adds a score or rate filter to the filters list.
     if (isset($args['namespace'])) {
         require_once "MTUtil.php";
         $arg_names = array('min_score', 'max_score', 'min_rate', 'max_rate', 'min_count', 'max_count');
         foreach ($arg_names as $n) {
             if (isset($args[$n])) {
                 $rating_args = $args[$n];
                 $cexpr = create_rating_expr_function($rating_args, $n, $args['namespace']);
                 if ($cexpr) {
                     $filters[] = $cexpr;
                 } else {
                     return null;
                 }
             }
         }
         if (isset($args['scored_by'])) {
             $voter = $this->fetch_author_by_name($args['scored_by']);
             if (empty($voter)) {
                 echo "Invalid scored by filter: " . $args['scored_by'];
                 return null;
             }
             $cexpr = create_rating_expr_function($voter->author_id, 'scored_by', $args['namespace']);
             if ($cexpr) {
                 $filters[] = $cexpr;
             } else {
                 return null;
             }
         }
     }
     # Adds an count of comment filter
     if (isset($args['max_comment']) && is_numeric($args['max_comment'])) {
         $max_comment_filter = 'and entry_comment_count <= ' . intval($args['max_comment']);
     }
     if (isset($args['min_comment']) && is_numeric($args['min_comment'])) {
         $min_comment_filter = 'and entry_comment_count >= ' . intval($args['min_comment']);
     }
     if (count($entry_list) && $entry_filter == '') {
         $entry_list = implode(",", array_keys($entry_list));
         # set a reasonable cap on the entry list cache. if
         # user is selecting something too big, then they'll
         # just have to wait through a scan.
         if (strlen($entry_list) < 2048) {
             $entry_filter = "and entry_id in ({$entry_list})";
         }
     }
     if (isset($args['author'])) {
         $author_filter = 'and author_name = \'' . $this->escape($args['author']) . "'";
         $extras['join']['mt_author'] = array('condition' => "entry_author_id = author_id");
     } elseif (isset($args['author_id']) && preg_match('/^\\d+$/', $args['author_id']) && $args['author_id'] > 0) {
         $author_filter = "and entry_author_id = '" . $args['author_id'] . "'";
     }
     if (isset($args['current_timestamp']) || isset($args['current_timestamp_end'])) {
         $timestamp_field = $args['class'] == 'page' ? 'entry_modified_on' : 'entry_authored_on';
     }
     $date_filter = $this->build_date_filter($args, $timestamp_field);
     if (isset($args['lastn'])) {
         if (!isset($args['entry_id'])) {
             $limit = $args['lastn'];
         }
     } elseif (isset($args['days']) && !$date_filter) {
         $day_filter = 'and ' . $this->limit_by_day_sql('entry_authored_on', intval($args['days']));
     } else {
         $found_valid_args = 0;
         foreach (array('lastn', 'days', 'category', 'categories', 'category_id', 'tag', 'tags', 'author', 'min_score', 'max_score', 'min_rate', 'max_rate', 'min_count', 'max_count', 'min_comment', 'max_comment') as $valid_key) {
             if (array_key_exists($valid_key, $args)) {
                 $found_valid_args = 1;
                 break;
             }
         }
         if (!isset($args['current_timestamp']) && !isset($args['current_timestamp_end']) && $limit <= 0 && !$found_valid_args && isset($blog)) {
             if ($days = $blog->blog_days_on_index) {
                 if (!isset($args['recently_commented_on'])) {
                     $day_filter = 'and ' . $this->limit_by_day_sql('entry_authored_on', $days);
                 }
             } elseif ($posts = $blog->blog_entries_on_index) {
                 $limit = $posts;
             }
         }
     }
     if (isset($args['sort_order'])) {
         if ($args['sort_order'] == 'ascend') {
             $order = 'asc';
         } elseif ($args['sort_order'] == 'descend') {
             $order = 'desc';
         }
     }
     if (!isset($order)) {
         $order = 'desc';
         if (isset($blog) && isset($blog->blog_sort_order_posts)) {
             if ($blog->blog_sort_order_posts == 'ascend') {
                 $order = 'asc';
             }
         }
     }
     if (isset($args['class'])) {
         $class = $this->escape($args['class']);
     } else {
         $class = 'entry';
     }
     $class_filter = "and entry_class='{$class}'";
     if ($args['class'] == '*') {
         $class_filter = '';
     }
     if (isset($args['sort_by']) && ($args['sort_by'] == 'score' || $args['sort_by'] == 'rate')) {
         $extras['join'] = array('mt_objectscore' => array('type' => 'left', 'condition' => "objectscore_object_id = entry_id and objectscore_namespace='" . $args['namespace'] . "' and objectscore_object_ds='" . $class . "'"));
         $extras['distinct'] = 1;
     }
     if (isset($args['offset'])) {
         $offset = $args['offset'];
     }
     if (isset($args['limit']) || isset($args['offset'])) {
         if (isset($args['sort_by'])) {
             if ($args['sort_by'] == 'title') {
                 $sort_field = 'entry_title';
             } elseif ($args['sort_by'] == 'id') {
                 $sort_field = 'entry_id';
             } elseif ($args['sort_by'] == 'status') {
                 $sort_field = 'entry_status';
             } elseif ($args['sort_by'] == 'modified_on') {
                 $sort_field = 'entry_modified_on';
             } elseif ($args['sort_by'] == 'author_id') {
                 $sort_field = 'entry_author_id';
             } elseif ($args['sort_by'] == 'excerpt') {
                 $sort_field = 'entry_excerpt';
             } elseif ($args['sort_by'] == 'comment_created_on') {
                 $sort_field = $args['sort_by'];
             } elseif ($args['sort_by'] == 'trackback_count') {
                 $sort_field = 'entry_ping_count';
             } elseif (preg_match('/field[:\\.]/', $args['sort_by'])) {
                 $post_sort_limit = $limit ? $limit : 0;
                 $post_sort_offset = $offset ? $offset : 0;
                 $limit = 0;
                 $offset = 0;
                 $no_resort = 0;
             } else {
                 $sort_field = 'entry_' . $args['sort_by'];
             }
             if ($sort_field) {
                 $no_resort = 1;
             }
             if ($args['sort_by'] == 'score' || $args['sort_by'] == 'rate') {
                 $post_sort_limit = $limit;
                 $post_sort_offset = $offset;
                 $limit = 0;
                 $offset = 0;
                 $no_resort = 0;
                 $sort_field = "entry_modified_on";
             }
         } else {
             $sort_field = isset($timestamp_field) ? $timestamp_field : 'entry_authored_on';
         }
     } else {
         $sort_field = isset($timestamp_field) ? $timestamp_field : 'entry_authored_on';
         $no_resort = 0;
     }
     if ($sort_field) {
         $base_order = (isset($args['sort_order']) ? $args['sort_order'] : (isset($args['base_sort_order']) ? $args['base_sort_order'] : '')) === 'ascend' ? 'asc' : 'desc';
     }
     if (count($filters) || !is_null($total_count)) {
         $post_select_limit = $limit;
         $post_select_offset = $offset;
         $limit = 0;
         $offset = 0;
     }
     if (count($fields)) {
         $meta_join_num = 1;
         $entry_meta_info = Entry::get_meta_info('entry');
         if (!empty($entry_meta_info)) {
             foreach ($fields as $name => $value) {
                 if (isset($entry_meta_info['field.' . $name])) {
                     $meta_col = $entry_meta_info['field.' . $name];
                     $value = $this->escape($value);
                     $table = "mt_entry_meta entry_meta{$meta_join_num}";
                     $extras['join'][$table] = array('condition' => "(entry_meta{$meta_join_num}.entry_meta_entry_id = entry_id\n                                and entry_meta{$meta_join_num}.entry_meta_type = 'field.{$name}'\n                                and entry_meta{$meta_join_num}.entry_meta_{$meta_col}='{$value}')\n");
                     $meta_join_num++;
                 }
             }
         }
     }
     $join_clause = '';
     if (isset($extras['join'])) {
         $joins = $extras['join'];
         $keys = array_keys($joins);
         foreach ($keys as $key) {
             $table = $key;
             $cond = $joins[$key]['condition'];
             $type = '';
             if (isset($joins[$key]['type'])) {
                 $type = $joins[$key]['type'];
             }
             $join_clause .= ' ' . strtolower($type) . ' JOIN ' . $table . ' ON ' . $cond;
         }
     }
     $sql = "select\n                    mt_entry.*\n                from mt_entry\n                    {$join_clause}\n                where\n                    entry_status = 2\n                    {$blog_filter}\n                    {$entry_filter}\n                    {$author_filter}\n                    {$date_filter}\n                    {$day_filter}\n                    {$class_filter}\n                    {$max_comment_filter}\n                    {$min_comment_filter}";
     if ($sort_field) {
         $sql .= "order by {$sort_field} {$base_order}";
         if ($sort_field == 'entry_authored_on') {
             $sql .= ",entry_id {$base_order}";
         }
     }
     if (isset($args['recently_commented_on'])) {
         $rco = $args['recently_commented_on'];
         $sql = $this->entries_recently_commented_on_sql($sql);
         $args['sort_by'] or $args['sort_by'] = 'comment_created_on';
         $args['sort_order'] or $args['sort_order'] = 'descend';
         $post_select_limit = $rco;
         $no_resort = 1;
     } elseif (!is_null($total_count)) {
         $orig_offset = $post_select_offset ? $post_select_offset : $offset;
         $orig_limit = $post_select_limit ? $post_select_limit : $limit;
     }
     if ($limit <= 0) {
         $limit = -1;
     }
     if ($offset <= 0) {
         $offset = -1;
     }
     $result = $this->db()->SelectLimit($sql, $limit, $offset);
     if ($result->EOF) {
         return null;
     }
     $field_names = array_keys($result->fields);
     $entries = array();
     $j = 0;
     $offset = $post_select_offset ? $post_select_offset : $orig_offset;
     $limit = $post_select_limit ? $post_select_limit : 0;
     $id_list = array();
     $_total_count = 0;
     while (!$result->EOF) {
         $e = new Entry();
         foreach ($field_names as $key) {
             $key = strtolower($key);
             $e->{$key} = $result->fields($key);
         }
         $result->MoveNext();
         if (empty($e)) {
             break;
         }
         if (count($filters)) {
             foreach ($filters as $f) {
                 if (!$f($e, $ctx)) {
                     continue 2;
                 }
             }
         }
         $_total_count++;
         if (!is_null($total_count)) {
             if ($orig_limit > 0 && $_total_count - $offset > $orig_limit) {
                 // collected all the entries; only count numbers;
                 continue;
             }
         }
         if ($offset && $j++ < $offset) {
             continue;
         }
         $e->entry_authored_on = $this->db2ts($e->entry_authored_on);
         $e->entry_modified_on = $this->db2ts($e->entry_modified_on);
         $id_list[] = $e->entry_id;
         $entries[] = $e;
         $this->_comment_count_cache[$e->entry_id] = $e->entry_comment_count;
         $this->_ping_count_cache[$e->entry_id] = $e->entry_ping_count;
         if (is_null($total_count)) {
             // the request does not want total count; break early
             if ($limit > 0 && count($entries) >= $limit) {
                 break;
             }
         }
     }
     Entry::bulk_load_meta($entries);
     if (!is_null($total_count)) {
         $total_count = $_total_count;
     }
     if (!$no_resort) {
         $sort_field = '';
         if (isset($args['sort_by'])) {
             if ($args['sort_by'] == 'title') {
                 $sort_field = 'entry_title';
             } elseif ($args['sort_by'] == 'id') {
                 $sort_field = 'entry_id';
             } elseif ($args['sort_by'] == 'status') {
                 $sort_field = 'entry_status';
             } elseif ($args['sort_by'] == 'modified_on') {
                 $sort_field = 'entry_modified_on';
             } elseif ($args['sort_by'] == 'author_id') {
                 $sort_field = 'entry_author_id';
             } elseif ($args['sort_by'] == 'excerpt') {
                 $sort_field = 'entry_excerpt';
             } elseif ($args['sort_by'] == 'comment_created_on') {
                 $sort_field = $args['sort_by'];
             } elseif ($args['sort_by'] == 'score') {
                 $sort_field = $args['sort_by'];
             } elseif ($args['sort_by'] == 'rate') {
                 $sort_field = $args['sort_by'];
             } elseif ($args['sort_by'] == 'trackback_count') {
                 $sort_field = 'entry_ping_count';
             } elseif (preg_match('/^field[:\\.](.+)$/', $args['sort_by'], $match)) {
                 $sort_field = 'entry_field.' . $match[1];
             } else {
                 $sort_field = 'entry_' . $args['sort_by'];
             }
         } else {
             $sort_field = 'entry_authored_on';
         }
         if ($sort_field) {
             if ($sort_field == 'score') {
                 $offset = $post_sort_offset ? $post_sort_offset : 0;
                 $limit = $post_sort_limit ? $post_sort_limit : 0;
                 $entries_tmp = array();
                 foreach ($entries as $e) {
                     $entries_tmp[$e->entry_id] = $e;
                 }
                 $scores = $this->fetch_sum_scores($args['namespace'], 'entry', $order, $blog_filter . "\n" . $entry_filter . "\n" . $author_filter . "\n" . $date_filter . "\n" . $day_filter . "\n" . $class_filter . "\n");
                 $entries_sorted = array();
                 foreach ($scores as $score) {
                     if (--$offset >= 0) {
                         continue;
                     }
                     if (array_key_exists($score['objectscore_object_id'], $entries_tmp)) {
                         array_push($entries_sorted, $entries_tmp[$score['objectscore_object_id']]);
                         unset($entries_tmp[$score['objectscore_object_id']]);
                         if (--$limit == 0) {
                             break;
                         }
                     }
                 }
                 foreach ($entries_tmp as $et) {
                     if ($limit == 0) {
                         break;
                     }
                     if ($order == 'asc') {
                         array_unshift($entries_sorted, $et);
                     } else {
                         array_push($entries_sorted, $et);
                     }
                     $limit--;
                 }
                 $entries = $entries_sorted;
             } elseif ($sort_field == 'rate') {
                 $offset = $post_sort_offset ? $post_sort_offset : 0;
                 $limit = $post_sort_limit ? $post_sort_limit : 0;
                 $entries_tmp = array();
                 foreach ($entries as $e) {
                     $entries_tmp[$e->entry_id] = $e;
                 }
                 $scores = $this->fetch_avg_scores($args['namespace'], 'entry', $order, $blog_filter . "\n" . $entry_filter . "\n" . $author_filter . "\n" . $date_filter . "\n" . $day_filter . "\n" . $class_filter . "\n");
                 $entries_sorted = array();
                 foreach ($scores as $score) {
                     if (--$offset >= 0) {
                         continue;
                     }
                     if (array_key_exists($score->objectscore_object_id, $entries_tmp)) {
                         array_push($entries_sorted, $entries_tmp[$score->objectscore_object_id]);
                         unset($entries_tmp[$score->objectscore_object_id]);
                         if (--$limit == 0) {
                             break;
                         }
                     }
                 }
                 foreach ($entries_tmp as $et) {
                     if ($limit == 0) {
                         break;
                     }
                     if ($order == 'asc') {
                         array_unshift($entries_sorted, $et);
                     } else {
                         array_push($entries_sorted, $et);
                     }
                     $limit--;
                 }
                 $entries = $entries_sorted;
             } elseif ($sort_field == 'entry_authored_on') {
                 // already double-sorted by the DB
             } else {
                 if (preg_match('/^entry_(field\\..*)/', $sort_field, $match)) {
                     if (!$entry_meta_info) {
                         if ($class === '*') {
                             $entry_meta_info = array_merge(BaseObject::get_meta_info('entry'), BaseObject::get_meta_info('page'));
                         } else {
                             $entry_meta_info = Entry::get_meta_info($class);
                         }
                     }
                     $sort_by_numeric = preg_match('/integer|float/', $entry_meta_info[$match[1]]);
                 } else {
                     $sort_by_numeric = $sort_field == 'entry_status' || $sort_field == 'entry_author_id' || $sort_field == 'entry_id' || $sort_field == 'entry_comment_count' || $sort_field == 'entry_ping_count';
                 }
                 $sort_fn = "\$f = '" . addslashes($sort_field) . "'; " . ($sort_by_numeric ? 'if ($a->$f == $b->$f) return 0; return $a->$f < $b->$f ? -1 : 1;' : 'return strcmp($a->$f,$b->$f);');
                 $sorter = create_function($order == 'asc' ? '$a,$b' : '$b,$a', $sort_fn);
                 usort($entries, $sorter);
                 if (isset($post_sort_offset)) {
                     $entries = array_slice($entries, $post_sort_offset, $post_sort_limit);
                 }
             }
         }
     }
     if (count($id_list) <= 30) {
         # TODO: find a good upper limit
         # pre-cache comment counts and categories for these entries
         $this->cache_categories($id_list);
         $this->cache_permalinks($id_list);
     }
     return $entries;
 }
Пример #2
0
 function &fetch_entries($args, $total_count = NULL)
 {
     if ($sql = $this->include_exclude_blogs($args)) {
         $blog_filter = 'and entry_blog_id ' . $sql;
     } elseif (isset($args['blog_id'])) {
         $blog_id = intval($args['blog_id']);
         $blog_filter = 'and entry_blog_id = ' . $blog_id;
         $blog = $this->fetch_blog($blog_id);
     }
     if (!$blog) {
         global $mt;
         $blog = $this->fetch_blog($mt->blog_id);
     }
     // determine any custom fields that we should filter on
     $fields = array();
     foreach ($args as $name => $v) {
         if (preg_match('/^field___(\\w+)$/', $name, $m)) {
             $fields[$m[1]] = $v;
         }
     }
     # automatically include offset if in request
     if ($args['offset'] == 'auto') {
         $args['offset'] = 0;
         if ($args['limit'] || $args['lastn']) {
             if ($_REQUEST['offset'] > 0) {
                 $args['offset'] = $_REQUEST['offset'];
             }
         }
     }
     if ($args['limit'] > 0) {
         $args['lastn'] = $args['limit'];
     } elseif (!isset($args['days']) && !isset($args['lastn'])) {
         #            if ($days = $blog['blog_days_on_index']) {
         #                if (!isset($args['recently_commented_on'])) {
         #                    $args['days'] = $days;
         #                }
         #            } elseif ($posts = $blog['blog_entries_on_index']) {
         #                $args['lastn'] = $posts;
         #            }
     }
     if ($args['limit'] == 'auto') {
         if ($_REQUEST['limit'] > 0 && $_REQUEST['limit'] < $args['lastn']) {
             $args['lastn'] = intval($_REQUEST['limit']);
         } elseif (!isset($args['days']) && !isset($args['lastn'])) {
             if ($days = $blog['blog_days_on_index']) {
                 if (!isset($args['recently_commented_on'])) {
                     $args['days'] = $days;
                 }
             } elseif ($posts = $blog['blog_entries_on_index']) {
                 $args['lastn'] = $posts;
             }
         }
     }
     if (isset($args['include_blogs']) or isset($args['exclude_blogs'])) {
         $blog_ctx_arg = isset($args['include_blogs']) ? array('include_blogs' => $args['include_blogs']) : array('exclude_blogs' => $args['exclude_blogs']);
     }
     # a context hash for filter routines
     $ctx = array();
     $filters = array();
     if (!isset($_REQUEST['entry_ids_published'])) {
         $_REQUEST['entry_ids_published'] = array();
     }
     if (isset($args['unique'])) {
         $filters[] = create_function('$e,$ctx', 'return !isset($ctx["entry_ids_published"][$e["entry_id"]]);');
         $ctx['entry_ids_published'] =& $_REQUEST['entry_ids_published'];
     }
     # special case for selecting a particular entry
     if (isset($args['entry_id'])) {
         $entry_filter = 'and entry_id = ' . $args['entry_id'];
         $start = '';
         $end = '';
         $limit = 1;
         $blog_filter = '';
         $day_filter = '';
     } else {
         $entry_filter = '';
     }
     # special case for excluding a particular entry
     if (isset($args['not_entry_id'])) {
         $entry_filter .= ' and entry_id != ' . $args['not_entry_id'];
     }
     $entry_list = array();
     # Adds a category filter to the filters list.
     $cat_class = 'category';
     if (!isset($args['class'])) {
         $args['class'] = 'entry';
     }
     if ($args['class'] == 'page') {
         $cat_class = 'folder';
     }
     if (isset($args['category']) or isset($args['categories'])) {
         $category_arg = isset($args['category']) ? $args['category'] : $args['categories'];
         require_once "MTUtil.php";
         if (!preg_match('/\\b(AND|OR|NOT)\\b|\\(|\\)/i', $category_arg)) {
             $not_clause = false;
             $cats = cat_path_to_category($category_arg, $blog_ctx_arg, $cat_class);
             if (count($cats)) {
                 $category_arg = '';
                 foreach ($cats as $cat) {
                     if ($category_arg != '') {
                         $category_arg .= '|| ';
                     }
                     $category_arg .= '#' . $cat['category_id'];
                 }
                 $category_arg = '(' . $category_arg . ')';
             }
         } else {
             $not_clause = preg_match('/\\bNOT\\b/i', $category_arg);
             if ($blog_ctx_arg) {
                 $cats =& $this->fetch_categories(array_merge($blog_ctx_arg, array('show_empty' => 1, 'class' => $cat_class)));
             } else {
                 $cats =& $this->fetch_categories(array('blog_id' => $blog_id, 'show_empty' => 1, 'class' => $cat_class));
             }
         }
         if (!is_array($cats)) {
             $cats = array();
         }
         $cexpr = create_cat_expr_function($category_arg, $cats, array('children' => $args['include_subcategories']));
         if ($cexpr) {
             $cmap = array();
             $cat_list = array();
             foreach ($cats as $cat) {
                 $cat_list[] = $cat['category_id'];
             }
             $pl =& $this->fetch_placements(array('category_id' => $cat_list));
             if ($pl) {
                 foreach ($pl as $p) {
                     $cmap[$p['placement_entry_id']][$p['placement_category_id']]++;
                     if (!$not_clause) {
                         $entry_list[$p['placement_entry_id']] = 1;
                     }
                 }
             }
             $ctx['p'] =& $cmap;
             $filters[] = $cexpr;
         } else {
             return null;
         }
     } elseif (isset($args['category_id'])) {
         require_once "MTUtil.php";
         $cat = $this->fetch_category($args['category_id']);
         if ($cat) {
             $cats = array($cat);
             $cmap = array();
             $cexpr = create_cat_expr_function($cat['category_label'], $cats, array('children' => $args['include_subcategories']));
             $pl =& $this->fetch_placements(array('category_id' => array($cat['category_id'])));
             if ($pl) {
                 foreach ($pl as $p) {
                     $cmap[$p['placement_entry_id']][$p['placement_category_id']]++;
                 }
                 $ctx['p'] =& $cmap;
                 $filters[] = $cexpr;
             } else {
                 # this category have no entries (or pages)
                 return null;
             }
         }
     }
     if (0 == count($filters) && (isset($args['show_empty']) && 1 == $args['show_empty'])) {
         return null;
     }
     # Adds a tag filter to the filters list.
     if (isset($args['tags']) or isset($args['tag'])) {
         $tag_arg = isset($args['tag']) ? $args['tag'] : $args['tags'];
         require_once "MTUtil.php";
         $not_clause = preg_match('/\\bNOT\\b/i', $tag_arg);
         require_once "MTUtil.php";
         $include_private = 0;
         $tag_array = tag_split($tag_arg);
         foreach ($tag_array as $tag) {
             if ($tag && substr($tag, 0, 1) == '@') {
                 $include_private = 1;
             }
         }
         if (isset($blog_ctx_arg)) {
             $tags =& $this->fetch_entry_tags(array($blog_ctx_arg, 'tag' => $tag_arg, 'include_private' => $include_private, 'class' => $args['class']));
         } else {
             $tags =& $this->fetch_entry_tags(array('blog_id' => $blog_id, 'tag' => $tag_arg, 'include_private' => $include_private, 'class' => $args['class']));
         }
         if (!is_array($tags)) {
             $tags = array();
         }
         $cexpr = create_tag_expr_function($tag_arg, $tags);
         if ($cexpr) {
             $tmap = array();
             $tag_list = array();
             foreach ($tags as $tag) {
                 $tag_list[] = $tag['tag_id'];
             }
             if (isset($blog_ctx_arg)) {
                 $ot =& $this->fetch_objecttags(array('tag_id' => $tag_list, 'datasource' => 'entry', $blog_ctx_arg));
             } elseif ($args['blog_id']) {
                 $ot =& $this->fetch_objecttags(array('tag_id' => $tag_list, 'datasource' => 'entry', 'blog_id' => $args['blog_id']));
             }
             if ($ot) {
                 foreach ($ot as $o) {
                     $tmap[$o['objecttag_object_id']][$o['objecttag_tag_id']]++;
                     if (!$not_clause) {
                         $entry_list[$o['objecttag_object_id']] = 1;
                     }
                 }
             }
             $ctx['t'] =& $tmap;
             $filters[] = $cexpr;
         } else {
             return null;
         }
     }
     # Adds a score or rate filter to the filters list.
     if (isset($args['namespace'])) {
         require_once "MTUtil.php";
         $arg_names = array('min_score', 'max_score', 'min_rate', 'max_rate', 'min_count', 'max_count');
         foreach ($arg_names as $n) {
             if (isset($args[$n])) {
                 $rating_args = $args[$n];
                 $cexpr = create_rating_expr_function($rating_args, $n, $args['namespace']);
                 if ($cexpr) {
                     $filters[] = $cexpr;
                 } else {
                     return null;
                 }
             }
         }
         if (isset($args['scored_by'])) {
             $voter = $this->fetch_author_by_name($args['scored_by']);
             if (!$voter) {
                 echo "Invalid scored by filter: " . $args['scored_by'];
                 return null;
             }
             $cexpr = create_rating_expr_function($voter['author_id'], 'scored_by', $args['namespace']);
             if ($cexpr) {
                 $filters[] = $cexpr;
             } else {
                 return null;
             }
         }
     }
     if (count($entry_list) && $entry_filter == '') {
         $entry_list = implode(",", array_keys($entry_list));
         # set a reasonable cap on the entry list cache. if
         # user is selecting something too big, then they'll
         # just have to wait through a scan.
         if (strlen($entry_list) < 2048) {
             $entry_filter = "and entry_id in ({$entry_list})";
         }
     }
     if (isset($args['author'])) {
         $author_filter = 'and author_name = \'' . $this->escape($args['author']) . "'";
     }
     $start = isset($args['current_timestamp']) ? $args['current_timestamp'] : null;
     $end = isset($args['current_timestamp_end']) ? $args['current_timestamp_end'] : null;
     if ($start and $end) {
         $start = $this->ts2db($start);
         $end = $this->ts2db($end);
         $date_filter = "and entry_authored_on between '{$start}' and '{$end}'";
     } elseif ($start) {
         $start = $this->ts2db($start);
         $date_filter = "and entry_authored_on >= '{$start}'";
     } elseif ($end) {
         $end = $this->ts2db($end);
         $date_filter = "and entry_authored_on <= '{$end}'";
     } else {
         $date_filter = '';
     }
     if (isset($args['lastn'])) {
         if (!isset($args['entry_id'])) {
             $limit = $args['lastn'];
         }
     } elseif (isset($args['days']) && !$date_filter) {
         $day_filter = 'and ' . $this->limit_by_day_sql('entry_authored_on', intval($args['days']));
     } else {
         $found_valid_args = 0;
         foreach (array('lastn', 'days', 'category', 'categories', 'category_id', 'tag', 'tags', 'author', 'min_score', 'max_score', 'min_rate', 'max_rate', 'min_count', 'max_count') as $valid_key) {
             if (array_key_exists($valid_key, $args)) {
                 $found_valid_args = 1;
                 break;
             }
         }
         if (!isset($args['current_timestamp']) && !isset($args['current_timestamp_end']) && $limit <= 0 && !$found_valid_args && isset($blog)) {
             if ($days = $blog['blog_days_on_index']) {
                 if (!isset($args['recently_commented_on'])) {
                     $day_filter = 'and ' . $this->limit_by_day_sql('entry_authored_on', $days);
                 }
             } elseif ($posts = $blog['blog_entries_on_index']) {
                 $limit = $posts;
             }
         }
     }
     if (isset($args['sort_order'])) {
         if ($args['sort_order'] == 'ascend') {
             $order = 'asc';
         } else {
             if ($args['sort_order'] == 'descend') {
                 $order = 'desc';
             }
         }
     }
     if (!isset($order)) {
         $order = 'desc';
         if (isset($blog) && isset($blog['blog_sort_order_posts'])) {
             if ($blog['blog_sort_order_posts'] == 'ascend') {
                 $order = 'asc';
             }
         }
     }
     if (isset($args['class'])) {
         $class = $this->escape($args['class']);
     } else {
         $class = 'entry';
     }
     $class_filter = "and entry_class='{$class}'";
     if ($args['class'] == '*') {
         $class_filter = '';
     }
     $join_score = "";
     $distinct = "";
     if (isset($args['sort_by']) && ($args['sort_by'] == 'score' || $args['sort_by'] == 'rate')) {
         $join_score = "left join mt_objectscore on objectscore_object_id = entry_id and objectscore_namespace='" . $args['namespace'] . "' and objectscore_object_ds='" . $class . "'";
         $distinct = " distinct";
     }
     if (isset($args['offset'])) {
         $offset = $args['offset'];
     }
     if (isset($args['limit'])) {
         if (isset($args['sort_by'])) {
             if ($args['sort_by'] == 'title') {
                 $sort_field = 'entry_title';
             } elseif ($args['sort_by'] == 'id') {
                 $sort_field = 'entry_id';
             } elseif ($args['sort_by'] == 'status') {
                 $sort_field = 'entry_status';
             } elseif ($args['sort_by'] == 'modified_on') {
                 $sort_field = 'entry_modified_on';
             } elseif ($args['sort_by'] == 'author_id') {
                 $sort_field = 'entry_author_id';
             } elseif ($args['sort_by'] == 'excerpt') {
                 $sort_field = 'entry_excerpt';
             } elseif ($args['sort_by'] == 'comment_created_on') {
                 $sort_field = $args['sort_by'];
             } elseif ($args['sort_by'] == 'score' || $args['sort_by'] == 'rate') {
                 $post_sort_limit = $limit;
                 $post_sort_offset = $offset;
                 $limit = 0;
                 $offset = 0;
             } elseif ($args['sort_by'] == 'trackback_count') {
                 $sort_field = 'entry_ping_count';
             } elseif (preg_match('/field[:\\.]/', $args['sort_by'])) {
                 $no_resort = 0;
             } else {
                 $sort_field = 'entry_' . $args['sort_by'];
             }
             if ($sort_field) {
                 $no_resort = 1;
             }
         } else {
             $sort_field = 'entry_authored_on';
         }
         if ($sort_field) {
             $base_order = $args['sort_order'] == 'ascend' ? 'asc' : 'desc';
             $base_order or $base_order = 'desc';
         }
     } else {
         $base_order = 'desc';
         if (isset($args['base_sort_order'])) {
             if ($args['base_sort_order'] == 'ascend') {
                 $base_order = 'asc';
             }
         }
         $sort_field = 'entry_authored_on';
         $no_resort = 0;
     }
     if (count($filters)) {
         $post_select_limit = $limit;
         $post_select_offset = $offset;
         $limit = 0;
         $offset = 0;
     }
     if (count($fields)) {
         $meta_join_num = 1;
         $meta_join = "";
         $entry_meta = array();
         foreach ($this->object_meta['entry'] as $meta) {
             list($meta_key, $meta_type) = preg_split('/:/', $meta);
             $entry_meta[$meta_key] = $meta_type;
         }
         foreach ($fields as $name => $value) {
             $meta_col = $entry_meta['field.' . $name];
             if (!$meta_col) {
                 return null;
             }
             # invalid column; can't select
             $value = $this->escape($value);
             $meta_join .= " join mt_entry_meta entry_meta{$meta_join_num} on (entry_meta{$meta_join_num}.entry_meta_entry_id = entry_id\n                and entry_meta{$meta_join_num}.entry_meta_type = 'field.{$name}'\n                and entry_meta{$meta_join_num}.entry_meta_{$meta_col}='{$value}')\n";
             $meta_join_num++;
         }
     }
     $sql = "\n            select{$distinct} mt_entry.*, mt_placement.*, mt_author.*,\n                   mt_trackback.*\n              from mt_entry\n              left outer join mt_trackback on trackback_entry_id = entry_id\n              {$meta_join}\n              {$join_score}\n              left outer join mt_placement on (placement_entry_id = entry_id\n                and placement_is_primary = 1),\n                   mt_author\n             where entry_status = 2\n               and entry_author_id = author_id\n                   {$blog_filter}\n                   {$entry_filter}\n                   {$author_filter}\n                   {$date_filter}\n                   {$day_filter}\n                   {$class_filter}\n        ";
     if ($sort_field) {
         $sql .= "\n                order by {$sort_field} {$base_order}";
     }
     if (isset($args['recently_commented_on'])) {
         $rco = $args['recently_commented_on'];
         $sql = $this->entries_recently_commented_on_sql($sql);
         $sql = $this->apply_limit_sql($sql, count($filters) ? null : $rco);
         $args['sort_by'] or $args['sort_by'] = 'comment_created_on';
         $args['sort_order'] or $args['sort_order'] = 'descend';
         $post_select_limit = $rco;
         $no_resort = 1;
     } elseif (!is_null($total_count)) {
         $orig_offset = $post_select_offset ? $post_select_offset : $offset;
         $orig_limit = $post_select_limit ? $post_select_limit : $limit;
     } else {
         $sql = $this->apply_limit_sql($sql . " <LIMIT>", $limit, $offset);
     }
     $result = $this->query_start($sql);
     if (!$result) {
         return null;
     }
     $entries = array();
     $j = 0;
     $offset = $post_select_offset ? $post_select_offset : $orig_offset;
     $limit = $post_select_limit ? $post_select_limit : 0;
     $id_list = array();
     $_total_count = 0;
     while (true) {
         $e = $this->query_fetch(ARRAY_A);
         if (!isset($e)) {
             break;
         }
         if (count($filters)) {
             foreach ($filters as $f) {
                 $old_result = $this->result;
                 if (!$f($e, $ctx)) {
                     $this->result = $old_result;
                     continue 2;
                 }
                 $this->result = $old_result;
             }
         }
         $_total_count++;
         if (!is_null($total_count)) {
             if ($orig_limit > 0 && $_total_count - $offset > $orig_limit) {
                 // collected all the entries; only count numbers;
                 continue;
             }
         }
         if ($offset && $j++ < $offset) {
             continue;
         }
         $e['entry_authored_on'] = $this->db2ts($e['entry_authored_on']);
         $e['entry_modified_on'] = $this->db2ts($e['entry_modified_on']);
         $e = $this->expand_meta($e);
         $id_list[] = $e['entry_id'];
         $entries[] = $e;
         $this->_comment_count_cache[$e['entry_id']] = $e['entry_comment_count'];
         $this->_ping_count_cache[$e['entry_id']] = $e['entry_ping_count'];
         if (is_null($total_count)) {
             // the request does not want total count; break early
             if ($limit > 0 && count($entries) >= $limit) {
                 break;
             }
         }
     }
     if (!is_null($total_count)) {
         $total_count = $_total_count;
     }
     if (!$no_resort) {
         $sort_field = '';
         if (isset($args['sort_by'])) {
             if ($args['sort_by'] == 'title') {
                 $sort_field = 'entry_title';
             } elseif ($args['sort_by'] == 'id') {
                 $sort_field = 'entry_id';
             } elseif ($args['sort_by'] == 'status') {
                 $sort_field = 'entry_status';
             } elseif ($args['sort_by'] == 'modified_on') {
                 $sort_field = 'entry_modified_on';
             } elseif ($args['sort_by'] == 'author_id') {
                 $sort_field = 'entry_author_id';
             } elseif ($args['sort_by'] == 'excerpt') {
                 $sort_field = 'entry_excerpt';
             } elseif ($args['sort_by'] == 'comment_created_on') {
                 $sort_field = $args['sort_by'];
             } elseif ($args['sort_by'] == 'score') {
                 $sort_field = $args['sort_by'];
             } elseif ($args['sort_by'] == 'rate') {
                 $sort_field = $args['sort_by'];
             } elseif ($args['sort_by'] == 'trackback_count') {
                 $sort_field = 'entry_ping_count';
             } elseif (preg_match('/^field[:\\.](.+)$/', $args['sort_by'], $match)) {
                 $sort_field = 'entry_field.' . $match[1];
             } else {
                 $sort_field = 'entry_' . $args['sort_by'];
             }
         } else {
             $sort_field = 'entry_authored_on';
         }
         if ($sort_field) {
             if ($sort_field == 'score') {
                 $offset = $post_sort_offset ? $post_sort_offset : 0;
                 $limit = $post_sort_limit ? $post_sort_limit : 0;
                 $entries_tmp = array();
                 foreach ($entries as $e) {
                     $entries_tmp[$e['entry_id']] = $e;
                 }
                 $scores = $this->fetch_sum_scores($args['namespace'], 'entry', $order, $blog_filter . "\n" . $entry_filter . "\n" . $author_filter . "\n" . $date_filter . "\n" . $day_filter . "\n" . $class_filter . "\n");
                 $entries_sorted = array();
                 foreach ($scores as $score) {
                     if (--$offset >= 0) {
                         continue;
                     }
                     if (array_key_exists($score['objectscore_object_id'], $entries_tmp)) {
                         array_push($entries_sorted, $entries_tmp[$score['objectscore_object_id']]);
                         unset($entries_tmp[$score['objectscore_object_id']]);
                         if (--$limit == 0) {
                             break;
                         }
                     }
                 }
                 foreach ($entries_tmp as $et) {
                     if ($limit == 0) {
                         break;
                     }
                     if ($order == 'asc') {
                         array_unshift($entries_sorted, $et);
                     } else {
                         array_push($entries_sorted, $et);
                     }
                     $limit--;
                 }
                 $entries = $entries_sorted;
             } elseif ($sort_field == 'rate') {
                 $offset = $post_sort_offset ? $post_sort_offset : 0;
                 $limit = $post_sort_limit ? $post_sort_limit : 0;
                 $entries_tmp = array();
                 foreach ($entries as $e) {
                     $entries_tmp[$e['entry_id']] = $e;
                 }
                 $scores = $this->fetch_avg_scores($args['namespace'], 'entry', $order, $blog_filter . "\n" . $entry_filter . "\n" . $author_filter . "\n" . $date_filter . "\n" . $day_filter . "\n" . $class_filter . "\n");
                 $entries_sorted = array();
                 foreach ($scores as $score) {
                     if (--$offset >= 0) {
                         continue;
                     }
                     if (array_key_exists($score['objectscore_object_id'], $entries_tmp)) {
                         array_push($entries_sorted, $entries_tmp[$score['objectscore_object_id']]);
                         unset($entries_tmp[$score['objectscore_object_id']]);
                         if (--$limit == 0) {
                             break;
                         }
                     }
                 }
                 foreach ($entries_tmp as $et) {
                     if ($limit == 0) {
                         break;
                     }
                     if ($order == 'asc') {
                         array_unshift($entries_sorted, $et);
                     } else {
                         array_push($entries_sorted, $et);
                     }
                     $limit--;
                 }
                 $entries = $entries_sorted;
             } else {
                 if ($sort_field == 'entry_status' || $sort_field == 'entry_author_id' || $sort_field == 'entry_id' || $sort_field == 'entry_comment_count' || $sort_field == 'entry_ping_count') {
                     $sort_fn = "if (\$a['{$sort_field}'] == \$b['{$sort_field}']) return 0; return \$a['{$sort_field}'] < \$b['{$sort_field}'] ? -1 : 1;";
                 } else {
                     $sort_fn = "return strcmp(\$a['{$sort_field}'],\$b['{$sort_field}']);";
                 }
                 $sorter = create_function($order == 'asc' ? '$a,$b' : '$b,$a', $sort_fn);
                 usort($entries, $sorter);
             }
         }
     }
     if (count($id_list) <= 30) {
         # TODO: find a good upper limit
         # pre-cache comment counts and categories for these entries
         $this->cache_categories($id_list);
         $this->cache_permalinks($id_list);
     }
     return $entries;
 }
function smarty_block_mtsubcategories($args, $content, &$ctx, &$repeat)
{
    $localvars = array('subCatTokens', 'subCatsSortOrder', 'subCatsSortBy', 'subCatsSortMethod', '__categories', 'inside_mt_categories', '_subcats_counter', 'entries', 'subCatIsFirst', 'subCatIsLast', 'category', 'current_archive_type', 'subFolderHead', 'subFolderFoot');
    if (!isset($content)) {
        $ctx->localize($localvars);
        $token_fn = $args['token_fn'];
        $blog_id = $ctx->stash('blog_id');
        $class = 'category';
        if (isset($args['class'])) {
            $class = $args['class'];
        }
        # Do we want the current category?
        $include_current = $args['include_current'];
        $top = $args['top'];
        # Sorting information#   sort_order ::= 'ascend' | 'descend'
        #   sort_method ::= method name (e.g. package::method)
        #
        # sort_method takes precedence
        $sort_order = isset($args['sort_order']) ? $args['sort_order'] : 'ascend';
        $sort_method = $args['sort_method'];
        $sort_by = isset($args['sort_by']) ? $args['sort_by'] : 'user_custom';
        # Store the tokens for recursion
        $ctx->stash('subCatTokens', $token_fn);
        $ctx->stash('current_archive_type', 'Category');
        # If we find ourselves in a category context
        if (!$top) {
            if ($args['category']) {
                require_once "MTUtil.php";
                $current_cat = cat_path_to_category($args['category'], $blog_id);
                if (is_array($current_cat)) {
                    $current_cat = $current_cat[0];
                }
            }
            if ($current_cat == NULL) {
                $current_cat = $ctx->stash('category') or $ctx->stash('archive_category');
            }
        }
        if (!$top && !$args['top_level_categories'] && $current_cat) {
            if ($include_current) {
                # If we're to include it, just use it to seed the category list
                $cats = array($current_cat);
            } else {
                # Otherwise, use its children
                $cats = $ctx->mt->db()->fetch_categories(array('blog_id' => $blog_id, 'category_id' => $current_cat->category_id, 'children' => 1, 'show_empty' => 1, 'sort_order' => $sort_order, 'class' => $class, 'sort_by' => $sort_by));
            }
        }
        if (($top || $args['top_level_categories']) && !$cats) {
            # Otherwise, use the top level categories
            $cats = $ctx->mt->db()->fetch_categories(array('blog_id' => $blog_id, 'top_level_categories' => 1, 'show_empty' => 1, 'sort_order' => $sort_order, 'class' => $class, 'sort_by' => $sort_by));
        }
        if (!$cats) {
            $ctx->restore($localvars);
            $repeat = false;
            return '';
        }
        $ctx->stash('__categories', $cats);
        # Be sure the regular MT tags know we're in a category context
        $ctx->stash('inside_mt_categories', 1);
        $ctx->stash('subCatsSortOrder', $sort_order);
        $ctx->stash('subCatsSortBy', $sort_by);
        $ctx->stash('subCatsSortMethod', $sort_method);
        $ctx->stash('_subcats_counter', 0);
        $count = 0;
    } else {
        # Init variables
        $cats = $ctx->stash('__categories');
        $count = $ctx->stash('_subcats_counter');
    }
    # Loop through the immediate children (or the current cat,
    # depending on the arguments
    if ($count < count($cats)) {
        $category = $cats[$count];
        $ctx->stash('category', $category);
        $ctx->stash('entries', null);
        $ctx->stash('subCatIsFirst', $count == 0);
        $ctx->stash('subCatIsLast', $count == count($cats) - 1);
        $ctx->stash('subFolderHead', $count == 0);
        $ctx->stash('subFolderFoot', $count == count($cats) - 1);
        $ctx->stash('_subcats_counter', $count + 1);
        $repeat = true;
    } else {
        $ctx->restore($localvars);
        $repeat = false;
    }
    return $content;
}