# # CatEntries 3.0 for Movable Type # Mark Paschal # # Displays entries from the given categories. Properly shows N entries # when asked for lastn="N". # # To use: # 1. Put this catentries.pl in your Movable Type plugins directory. # 2. Modify your template to use the tag. The attributes # it recognizes are: # # days="N" The number of days to display. # offset="N" The number of entries (with 'lastn') or days (with # 'days') to skip before counting entries to display. # lastn="N" By itself or with 'offset,' the number of entries # to display. With 'days,' the number of entries at # most to display. This means you can write: # # to get the last three entries posted a week ago. # # include="cat,cat,cat" Displays only items that are in at least # one of the given categories. If not # given, all entries, including those in # no category, will be shown. # exclude="cat,cat,cat" Omits items found in at least one of the # given categories. If not given, entries # in all included categories will be shown. # # Excludes are "stronger" than includes, so 'include="Cats" exclude= # "Mice"' will *not* show entries posted to both Cats and Mice. # # # Versions: # 1.0, 23 February 2003 # 2.0, 4 March 2003: Rewritten quite a bit to support lastn properly. # Describes CatEntries in top comment instead of # RandomOTDEntry. # 2.1, 9 March 2003: Correctly removes entry context; this made my # RandomOTDEntry plugin think the day of the last # entry selected in *this* plugin was 'today.' # 2.2, 20 March 2003: Use MTEntries' code itself to do the building, so # eg MTDateHeader works. # 2.3, 8 May 2003: Infinite loop bug when lastn exceeds available entries # quashed (thanks, Alex Nobert). # 2.4, 13 June 2003: Added "use MT::Template::Context;" which some # apparently need. Fixed 'offset' attribute to correctly # count only entries that would have been shown. # 2.5, 29 June 2003: Does not show "Draft" entries. Honors an entry list # context (eg, a date-based archive). # 2.6, 3 July 2003: Honors lastn and offset even on pages with natural # entry contexts, like category pages. # 2.7, 3 January 2004: Fixed 'days' attribute across year boundary. # 2.8, 27 January 2004: 'offset' with 'days' is a number of days; 'lastn' # with 'days' limits to 'lastn' entries. # 3.0, 19 July 2004: Works with Movable Type 3.0D. # # # Copyright 2003-2004 Mark Paschal # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. # package MT::Plugin::CatEntries; use vars qw( $VERSION ); $VERSION = 3.0; ## Say hello to MT 3. eval { require MT::Plugin; }; unless($@) { my $pl = MT::Plugin->new({ name => sprintf('CatEntries %.01f', $VERSION), description => 'Display entries from the given categories.', doc_link => 'http://markpasc.org/code/mt/CatEntries/', }); MT->add_plugin($pl); }; use POSIX qw(strftime); use MT::Template::Context; MT::Template::Context->add_container_tag(CatEntries => \&MTCatEntries); sub filterByCategories { ($entriesToFilter, $catsIn, $catsEx) = @_; my @entries = (); ENTRY: foreach my $e (@$entriesToFilter) { foreach my $cat (@$catsEx) { next ENTRY if $e->is_in_category($cat); }; if(@$catsIn) { foreach my $cat (@$catsIn) { if($e->is_in_category($cat)) { push @entries, $e; next ENTRY; }; }; } else { push @entries, $e; }; }; return @entries; } sub MTCatEntries { my ($ctx, $args) = @_; my $blog_id = $ctx->stash('blog_id'); my %entryTerms = ('blog_id' => $blog_id, 'status' => 2); # 2 == Publish my %entryArgs = ('sort' => $args->{'sort_by'} || 'created_on', 'direction' => $args->{'sort_order'} || 'descend'); # Cats my @catsIn = (); my @catsEx = (); @catsIn = map { MT::Category->load({ blog_id => $blog_id, label => $_ }, {}) } split /,/, $args->{'include'} if $args->{'include'}; @catsEx = map { MT::Category->load({ blog_id => $blog_id, label => $_ }, {}) } split /,/, $args->{'exclude'} if $args->{'exclude'}; # lastn or days? my @entries; if($args->{'days'}) { $entryArgs{'sort'} = 'created_on'; $entryArgs{'direction'} = 'descend'; my $daysOffset = $args->{'offset'} || 0; my @daysPast = localtime(time - 86400 * ($args->{'days'} + $daysOffset)); my @offsetNow = localtime(time - 86400 * $daysOffset); $entryTerms{'created_on'} = [strftime("%Y%m%d%H%M%S", @daysPast), strftime("%Y%m%d%H%M%S", @offsetNow)]; $entryArgs{'range'} = {'created_on' => 1}; @someEntries = MT::Entry->load(\%entryTerms, \%entryArgs); @entries = filterByCategories(\@someEntries, \@catsIn, \@catsEx) if @someEntries; if($args->{'lastn'}) { while(scalar(@entries) > $args->{'lastn'}) { pop @entries; }; }; } elsif($args->{'lastn'}) { my $offset = $args->{'offset'} || 0; # Number of entries to ignore from @entries $entryArgs{'limit'} = $args->{'lastn'} + $offset; # Number of entries to fetch $entryArgs{'offset'} = 0; # Number of entries 'into' the blog we're fetching $entryArgs{'sort'} = 'created_on'; $entryArgs{'direction'} = 'descend'; @entries = (); if(defined $ctx->{'__stash'}{'entries'}) { @entries = filterByCategories($ctx->stash('entries'), \@catsIn, \@catsEx); @entries = reverse @entries; } else { while(scalar(@entries) < $entryArgs{'limit'}) { my @newEntries = MT::Entry->load(\%entryTerms, \%entryArgs); last unless @newEntries; push @entries, filterByCategories(\@newEntries, \@catsIn, \@catsEx); $entryArgs{'offset'} += $entryArgs{'limit'}; }; }; while($offset--) { shift @entries; }; while(scalar(@entries) > $args->{'lastn'}) { pop @entries; }; } else { @someEntries = MT::Entry->load(\%entryTerms, \%entryArgs); @entries = filterByCategories(\@someEntries, \@catsIn, \@catsEx) if @someEntries; }; # Have entries, so build my $oldEntries = $ctx->{'__stash'}{'entries'}; # May be undef; that's OK $ctx->{'__stash'}{'entries'} = \@entries; my $ret = MT::Template::Context::_hdlr_entries($ctx, {}, {}); $ctx->{'__stash'}{'entries'} = $oldEntries; return $ret; }