|
Server : Apache/2.4.62 System : FreeBSD fbsdweb2.web.rcn.net 14.1-RELEASE FreeBSD 14.1-RELEASE releng/14.1-n267679-10e31f0946d8 GENERIC amd64 User : www ( 80) PHP Version : 8.3.8 Disable Function : NONE Directory : /domains/fatshado/cgi-bin/MT/lib/ |
Upload File : |
# Copyright 2001, 2002 Benjamin Trott. This code cannot be redistributed without
# permission from www.movabletype.org.
#
# $Id: MT.pm,v 1.108 2002/10/08 05:38:48 btrott Exp $
package MT;
use strict;
use vars qw( $VERSION );
$VERSION = '2.5';
use MT::ConfigMgr;
use MT::Object;
use MT::Blog;
use MT::Util qw( start_end_day start_end_week start_end_month
archive_file_for get_entry );
use File::Spec;
use Fcntl qw( LOCK_EX );
use MT::ErrorHandler;
@MT::ISA = qw( MT::ErrorHandler );
sub version_number {
(my $ver = $VERSION) =~ s/[^\d\.].*$//;
$ver;
}
sub version_slug {
return <<SLUG;
Powered by Movable Type
Version $VERSION
http://www.movabletype.org/
SLUG
}
sub new {
my $class = shift;
my $mt = bless { }, $class;
$mt->init(@_) or
return $class->error($mt->errstr);
$mt;
}
sub init {
my $mt = shift;
my %param = @_;
## Initialize the language to English in case any errors occur in
## the rest of the initialization process.
$mt->set_language('en_us');
my $cfg = $mt->{cfg} = MT::ConfigMgr->instance;
my($cfg_file);
unless ($cfg_file = $param{Config}) {
for my $f (qw( mt.cfg )) {
$cfg_file = $f, last if -r $f;
}
}
if ($cfg_file) {
$cfg->read_config($cfg_file) or
return $mt->error($cfg->errstr);
}
if (my $dir = $param{Directory}) {
$mt->{mt_dir} = $dir;
} elsif ($cfg_file) {
my($vol, $mt_dir, $fname) = File::Spec->splitpath($cfg_file);
$mt->{mt_dir} = $mt_dir || './';
}
my %default_dirs = (
TemplatePath => 'tmpl',
ImportPath => 'import',
PluginPath => 'plugins',
SearchTemplatePath => 'search_templates',
);
for my $meth (keys %default_dirs) {
$cfg->$meth(File::Spec->catfile($mt->{mt_dir}, $default_dirs{$meth}))
unless defined $cfg->$meth();
}
if ($cfg->ObjectDriver eq 'DBI::mysql') {
my $pass_file = File::Spec->catfile($mt->{mt_dir}, 'mt-db-pass.cgi');
local *FH;
if (open FH, $pass_file) {
chomp(my $pass = <FH>);
close FH;
$pass =~ s!^\s*!!;
$pass =~ s!\s*$!!;
$cfg->DBPassword($pass);
}
}
MT::Object->set_driver($cfg->ObjectDriver)
or return $mt->error(MT::ObjectDriver->errstr);
$mt->set_language($cfg->DefaultLanguage);
$mt->{__rebuilt} = {};
$mt->{__cached_maps} = {};
$mt->{__cached_templates} = {};
my $plugin_dir = $cfg->PluginPath;
local *DH;
if (opendir DH, $plugin_dir) {
my @p = readdir DH;
for my $plugin (@p) {
next if $plugin !~ /\.pl$/;
$plugin = File::Spec->catfile($plugin_dir, $plugin);
eval { require $plugin };
warn($@), next if $@;
}
closedir DH;
}
$mt;
}
sub rebuild {
my $mt = shift;
my %param = @_;
my $blog;
unless ($blog = $param{Blog}) {
my $blog_id = $param{BlogID};
$blog = MT::Blog->load($blog_id) or
return $mt->error(
$mt->translate("Load of blog '[_1]' failed: [_2]",
$blog_id, MT::Blog->errstr));
}
my $at = $blog->archive_type || '';
my @at = split /,/, $at;
if (my $set_at = $param{ArchiveType}) {
my %at = map { $_ => 1 } @at;
return $mt->error(
$mt->translate("Archive type '[_1]' is not a chosen archive type",
$set_at)) unless $at{$set_at};
@at = ($set_at);
}
if (@at) {
require MT::Entry;
my %arg = ('sort' => 'created_on', direction => 'descend');
if ($param{Limit}) {
$arg{offset} = $param{Offset};
$arg{limit} = $param{Limit};
}
my $iter = MT::Entry->load_iter({ blog_id => $blog->id,
status => MT::Entry::RELEASE() },
\%arg);
my $cb = $param{EntryCallback};
while (my $entry = $iter->()) {
$cb->($entry) if $cb;
for my $at (@at) {
if ($at eq 'Category') {
my $cats = $entry->categories;
for my $cat (@$cats) {
$mt->_rebuild_entry_archive_type(
Entry => $entry, Blog => $blog,
Category => $cat, ArchiveType => 'Category'
) or return;
}
} else {
$mt->_rebuild_entry_archive_type( Entry => $entry,
Blog => $blog,
ArchiveType => $at )
or return;
}
}
}
}
unless ($param{NoIndexes}) {
$mt->rebuild_indexes( Blog => $blog ) or return;
}
1;
}
sub rebuild_entry {
my $mt = shift;
my %param = @_;
my $entry = $param{Entry} or
return $mt->error($mt->translate("Parameter '[_1]' is required",
'Entry'));
my $blog;
unless ($blog = $param{Blog}) {
my $blog_id = $entry->blog_id;
$blog = MT::Blog->load($blog_id) or
return $mt->error($mt->translate("Load of blog '[_1]' failed: [_2]",
$blog_id, MT::Blog->errstr));
}
my $at = $blog->archive_type;
if ($at && $at ne 'None') {
my @at = split /,/, $at;
for my $at (@at) {
if ($at eq 'Category') {
my $cats = $entry->categories;
for my $cat (@$cats) {
$mt->_rebuild_entry_archive_type(
Entry => $entry, Blog => $blog,
ArchiveType => $at, Category => $cat,
) or return;
}
} else {
$mt->_rebuild_entry_archive_type( Entry => $entry,
Blog => $blog,
ArchiveType => $at
) or return;
}
}
}
## The above will just rebuild the archive pages for this particular
## entry. If we want to rebuild all of the entries/archives/indexes
## on which this entry could be featured etc., however, we need to
## rebuild all of the entry's dependencies. Note that all of these
## are not *necessarily* dependencies, depending on the usage of tags,
## etc. There is not a good way to determine exact dependencies; it is
## easier to just rebuild, rebuild, rebuild.
return 1 unless $param{BuildDependencies};
## Rebuild previous and next entry archive pages.
if (my $prev = $entry->previous) {
$mt->rebuild_entry( Entry => $prev ) or return;
}
if (my $next = $entry->next) {
$mt->rebuild_entry( Entry => $next ) or return;
}
## Rebuild all indexes, in case this entry is on an index.
$mt->rebuild_indexes( Blog => $blog ) or return;
## Rebuild previous and next daily, weekly, and monthly archives;
## adding a new entry could cause changes to the intra-archive
## navigation.
my %at = map { $_ => 1 } split /,/, $blog->archive_type;
for my $at (qw( Daily Weekly Monthly )) {
if ($at{$at}) {
my @arg = ($entry->created_on, $entry->blog_id, $at);
if (my $prev_arch = get_entry(@arg, 'previous')) {
$mt->_rebuild_entry_archive_type(
Entry => $prev_arch,
Blog => $blog,
ArchiveType => $at) or return;
}
if (my $next_arch = get_entry(@arg, 'next')) {
$mt->_rebuild_entry_archive_type(
Entry => $next_arch,
Blog => $blog,
ArchiveType => $at) or return;
}
}
}
1;
}
sub _rebuild_entry_archive_type {
my $mt = shift;
my %param = @_;
my $at = $param{ArchiveType} or
return $mt->error($mt->translate("Parameter '[_1]' is required",
'ArchiveType'));
return 1 if $at eq 'None';
my $entry = $param{Entry} or
return $mt->error($mt->translate("Parameter '[_1]' is required",
'Entry'));
my $blog;
unless ($blog = $param{Blog}) {
my $blog_id = $entry->blog_id;
$blog = MT::Blog->load($blog_id) or
return $mt->error($mt->translate("Load of blog '[_1]' failed: [_2]",
$blog_id, MT::Blog->errstr));
}
## Load the template-archive-type map entries for this blog and
## archive type. We do this before we load the list of entries, because
## we will run through the files and check if we even need to rebuild
## anything. If there is nothing to rebuild at all for this entry,
## we save some time by not loading the list of entries.
require MT::TemplateMap;
my @map;
if (my $maps = $mt->{__cached_maps}{$at . $blog->id}) {
@map = @$maps;
} else {
@map = MT::TemplateMap->load({ archive_type => $at,
blog_id => $blog->id });
$mt->{__cached_maps}{$at . $blog->id} = \@map;
}
return $mt->error($mt->translate(
"You selected the archive type '[_1]', but you did not " .
"define a template for this archive type.", $at)) unless @map;
my @map_build;
## We keep a running total of the pages we have rebuilt
## in this session in $mt->{__rebuilt}.
my $done = $mt->{__rebuilt};
for my $map (@map) {
my $file = archive_file_for($entry, $blog, $at, $param{Category}, $map);
push @map_build, $map unless $done->{$file};
$map->{__saved_output_file} = $file;
}
return 1 unless @map_build;
@map = @map_build;
my(%cond);
require MT::Template::Context;
my $ctx = MT::Template::Context->new;
$ctx->{current_archive_type} = $at;
if ($at eq 'Individual') {
$ctx->stash('entry', $entry);
$ctx->{current_timestamp} = $entry->created_on;
$cond{EntryIfAllowComments} = $entry->allow_comments;
$cond{EntryIfAllowPings} = $entry->allow_pings;
$cond{EntryIfExtended} = $entry->text_more ? 1 : 0;
} elsif ($at eq 'Daily') {
my($start, $end) = start_end_day($entry->created_on, $blog);
$ctx->{current_timestamp} = $start;
$ctx->{current_timestamp_end} = $end;
my @entries = MT::Entry->load({ created_on => [ $start, $end ],
blog_id => $blog->id,
status => MT::Entry::RELEASE() },
{ range => { created_on => 1 } });
$ctx->stash('entries', \@entries);
} elsif ($at eq 'Weekly') {
my($start, $end) = start_end_week($entry->created_on, $blog);
$ctx->{current_timestamp} = $start;
$ctx->{current_timestamp_end} = $end;
my @entries = MT::Entry->load({ created_on => [ $start, $end ],
blog_id => $blog->id,
status => MT::Entry::RELEASE() },
{ range => { created_on => 1 } });
$ctx->stash('entries', \@entries);
} elsif ($at eq 'Monthly') {
my($start, $end) = start_end_month($entry->created_on, $blog);
$ctx->{current_timestamp} = $start;
$ctx->{current_timestamp_end} = $end;
my @entries = MT::Entry->load({ created_on => [ $start, $end ],
blog_id => $blog->id,
status => MT::Entry::RELEASE() },
{ range => { created_on => 1 } });
$ctx->stash('entries', \@entries);
} elsif ($at eq 'Category') {
my $cat;
unless ($cat = $param{Category}) {
return $mt->error($mt->translate(
"Building category archives, but no category provided."));
}
require MT::Placement;
$ctx->stash('archive_category', $cat);
my @entries = MT::Entry->load({ blog_id => $blog->id,
status => MT::Entry::RELEASE() },
{ 'join' => [ 'MT::Placement', 'entry_id',
{ category_id => $cat->id } ] });
$ctx->stash('entries', \@entries);
}
my $fmgr = $blog->file_mgr;
my $arch_root = $blog->archive_path;
return $mt->error($mt->translate("You did not set your Local Archive Path"))
unless $arch_root;
## For each mapping, we need to rebuild the entries we loaded above in
## the particular template map, and write it to the specified archive
## file template.
require MT::Template;
for my $map (@map) {
my $file = File::Spec->catfile($arch_root, $map->{__saved_output_file});
my $tmpl = $mt->{__cached_templates}{$map->template_id};
unless ($tmpl) {
$tmpl = MT::Template->load($map->template_id);
if ($mt->{cache_templates}) {
$mt->{__cached_templates}{$tmpl->id} = $tmpl;
}
}
my $html = $tmpl->build($ctx, \%cond) or
return $mt->error($mt->translate(
"Building entry '[_1]' failed: [_2]",
$entry->title, $tmpl->errstr));
## Untaint. We have to assume that we can trust the user's setting of
## the archive_path, and nothing else is based on user input.
($file) = $file =~ /(.+)/s;
## Determine if we need to build directory structure, and build it
## if we do. DirUmask determines directory permissions.
my($vol, $path, $fname) = File::Spec->splitpath($file);
$path =~ s!/$!!; ## OS X doesn't like / at the end in mkdir().
unless ($fmgr->exists($path)) {
$fmgr->mkpath($path)
or return $mt->error($mt->translate(
"Error making path '[_1]': [_2]", $path, $fmgr->errstr));
}
## By default we write all data to temp files, then rename the temp
## files to the real files (an atomic operation). Some users don't
## like this (requires too liberal directory permissions). So we
## have a config option to turn it off (NoTempFiles).
my $use_temp_files = !$mt->{cfg}->NoTempFiles;
my $temp_file = $use_temp_files ? "$file.new" : $file;
defined($fmgr->put_data($html, $temp_file))
or return $mt->error($mt->translate(
"Writing to '[_1]' failed: [_2]", $temp_file, $fmgr->errstr));
if ($use_temp_files) {
$fmgr->rename($temp_file, $file)
or return $mt->error($mt->translate(
"Renaming tempfile '[_1]' failed: [_2]",
$temp_file, $fmgr->errstr));
}
$done->{$map->{__saved_output_file}}++;
}
1;
}
sub rebuild_indexes {
my $mt = shift;
my %param = @_;
require MT::Template;
require MT::Template::Context;
require MT::Entry;
my $blog;
unless ($blog = $param{Blog}) {
my $blog_id = $param{BlogID};
$blog = MT::Blog->load($blog_id) or
return $mt->error($mt->translate("Load of blog '[_1]' failed: [_2]",
$blog_id, MT::Blog->errstr));
}
my $iter;
if (my $tmpl = $param{Template}) {
my $i = 0;
$iter = sub { $i++ < 1 ? $tmpl : undef };
} else {
$iter = MT::Template->load_iter({ type => 'index',
blog_id => $blog->id });
}
local *FH;
my $site_root = $blog->site_path;
return $mt->error($mt->translate("You did not set your Local Site Path"))
unless $site_root;
my $fmgr = $blog->file_mgr;
while (my $tmpl = $iter->()) {
## Skip index templates that the user has designated not to be
## rebuilt automatically. We need to do the defined-ness check
## because we added the flag in 2.01, and for templates saved
## before that time, the rebuild_me flag will be undefined. But
## we assume that these templates should be rebuilt, since that
## was the previous behavior.
next if !$param{Force} &&
defined $tmpl->rebuild_me && !$tmpl->rebuild_me;
my $ctx = MT::Template::Context->new;
my $html = $tmpl->build($ctx);
return $mt->error( $tmpl->errstr ) unless defined $html;
my $index = $tmpl->outfile
or return $mt->error($mt->translate(
"Template '[_1]' does not have an Output File.", $tmpl->name));
unless (File::Spec->file_name_is_absolute($index)) {
$index = File::Spec->catfile($site_root, $index);
}
## Untaint. We have to assume that we can trust the user's setting of
## the site_path and the template outfile.
($index) = $index =~ /(.+)/s;
my $use_temp_files = !$mt->{cfg}->NoTempFiles;
my $temp_file = $use_temp_files ? "$index.new" : $index;
defined($fmgr->put_data($html, $temp_file))
or return $mt->error($mt->translate(
"Writing to '[_1]' failed: [_2]", $temp_file, $fmgr->errstr));
if ($use_temp_files) {
$fmgr->rename($temp_file, $index)
or return $mt->error($mt->translate(
"Renaming tempfile '[_1]' failed: [_2]",
$temp_file, $fmgr->errstr));
}
}
1;
}
sub ping {
my $mt = shift;
my %param = @_;
my $blog;
unless ($blog = $param{Blog}) {
my $blog_id = $param{BlogID};
$blog = MT::Blog->load($blog_id) or
return $mt->error(
$mt->translate("Load of blog '[_1]' failed: [_2]",
$blog_id, MT::Blog->errstr));
}
my(@res);
## Send update pings.
my @updates = $mt->update_ping_list($blog);
for my $url (@updates) {
require MT::XMLRPC;
if (MT::XMLRPC->ping_update('weblogUpdates.ping', $blog, $url)) {
push @res, { good => 1, url => $url, type => "update" };
} else {
push @res, { good => 0, url => $url, type => "update",
error => MT::XMLRPC->errstr };
}
}
if ($blog->mt_update_key) {
require MT::XMLRPC;
if (MT::XMLRPC->mt_ping($blog)) {
push @res, { good => 1, url => $mt->{cfg}->MTPingURL,
type => "update" };
} else {
push @res, { good => 0, url => $mt->{cfg}->MTPingURL,
type => "update", error => MT::XMLRPC->errstr };
}
}
## Send TrackBack pings.
if (my $entry = $param{Entry}) {
my $pings = $entry->to_ping_url_list;
my %pinged = map { $_ => 1 } @{ $entry->pinged_url_list };
my $cats = $entry->categories;
for my $cat (@$cats) {
push @$pings, grep !$pinged{$_}, @{ $cat->ping_url_list };
}
require LWP::UserAgent;
my $ua = LWP::UserAgent->new;
$ua->agent('MovableType/' . MT->VERSION);
$ua->timeout($mt->{cfg}->PingTimeout);
## Build query string to be sent on each ping.
my @qs;
push @qs, 'title=' . MT::Util::encode_url($entry->title);
my $url = $entry->archive_url;
$url .= '#' . sprintf("%06d", $entry->id)
unless $blog->archive_type_preferred eq 'Individual';
push @qs, 'url=' . MT::Util::encode_url($url);
my $excerpt = $entry->excerpt ||
MT::Util::first_n_words($entry->text, $blog->words_in_excerpt || 20);
push @qs, 'excerpt=' . MT::Util::encode_url($excerpt);
push @qs, 'blog_name=' . MT::Util::encode_url($blog->name);
my $qs = join '&', @qs;
for my $url (@$pings) {
$url =~ s/^\s*//;
$url =~ s/\s*$//;
my $req;
if ($url =~ /\?/) {
$req = HTTP::Request->new(GET => $url . '&' . $qs);
} else {
$req = HTTP::Request->new(POST => $url);
$req->content_type('application/x-www-form-urlencoded');
$req->content($qs);
}
my $res = $ua->request($req);
if (substr($res->code, 0, 1) eq '2') {
my $c = $res->content;
my($error, $msg) = $c =~
m!<error>(\d+).*<message>(.+?)</message>!s;
if ($error) {
push @res, { good => 0, url => $url, type => 'trackback',
error => $msg };
} else {
push @res, { good => 1, url => $url, type => 'trackback' };
}
} else {
push @res, { good => 0, url => $url, type => 'trackback',
error => "HTTP error: " . $res->status_line };
}
}
}
\@res;
}
sub needs_ping {
my $mt = shift;
my %param = @_;
my $blog = $param{Blog};
my $entry = $param{Entry};
return unless $entry->status == MT::Entry::RELEASE();
my $old_status = $param{OldStatus};
my %list;
## If this is a new entry (!$old_status) OR the status was previously
## set to draft, and is now set to publish, send the update pings.
if (!$old_status || $old_status ne MT::Entry::RELEASE()) {
my @updates = $mt->update_ping_list($blog);
@list{ @updates } = (1) x @updates;
$list{$mt->{cfg}->MTPingURL} = 1 if $blog && $blog->mt_update_key;
}
if ($entry) {
@list{ @{ $entry->to_ping_url_list } } = ();
my %pinged = map { $_ => 1 } @{ $entry->pinged_url_list };
my $cats = $entry->categories;
for my $cat (@$cats) {
@list{ grep !$pinged{$_}, @{ $cat->ping_url_list } } = ();
}
}
my @list = keys %list;
return unless @list;
\@list;
}
sub update_ping_list {
my $mt = shift;
my($blog) = @_;
my @updates;
if ($blog->ping_weblogs) {
push @updates, $mt->{cfg}->WeblogsPingURL;
}
if ($blog->ping_blogs) {
push @updates, $mt->{cfg}->BlogsPingURL;
}
if (my $others = $blog->ping_others) {
push @updates, split /\r?\n/, $others;
}
my %updates;
for my $url (@updates) {
for ($url) {
s/^\s*//; s/\s*$//;
}
next unless $url =~ /\S/;
$updates{$url}++;
}
keys %updates;
}
{
my $LH;
sub set_language {
require MT::L10N;
$LH = MT::L10N->get_handle($_[1]);
}
sub translate {
my $this = shift;
$LH->maketext(@_);
}
sub current_language { $LH->language_tag }
sub language_handle { $LH }
}
sub supported_languages {
my $mt = shift;
require MT::L10N;
require File::Basename;
## Determine full path to lib/MT/L10N directory...
my $lib =
File::Spec->catdir(File::Basename::dirname($INC{'MT/L10N.pm'}), 'L10N');
## ... From that, determine full path to extlib/MT/L10N.
## To do that, we look for the last instance of the string 'lib'
## in $lib and replace it with 'extlib'. reverse is a nice tricky
## way of doing that.
(my $extlib = reverse $lib) =~ s!bil!biltxe!;
$extlib = reverse $extlib;
my @dirs = ( $lib, $extlib );
my %langs;
for my $dir (@dirs) {
opendir DH, $dir or next;
for my $f (readdir DH) {
my($tag) = $f =~ /^(\w+)\.pm$/;
next unless $tag;
my $lh = MT::L10N->get_handle($tag);
$langs{$lh->language_tag} = $lh->language_name;
}
closedir DH;
}
\%langs;
}
1;
__END__
=head1 NAME
MT - Movable Type
=head1 SYNOPSIS
use MT;
my $mt = MT->new;
$mt->rebuild(BlogID => 1)
or die $mt->errstr;
=head1 DESCRIPTION
The I<MT> class is the main high-level rebuilding/pinging interface in the
Movable Type library. It handles all rebuilding operations. It does B<not>
handle any of the application functionality--for that, look to I<MT::App> and
I<MT::App::CMS>, both of which subclass I<MT> to handle application requests.
=head1 USAGE
I<MT> has the following interface. On failure, all methods return C<undef>
and set the I<errstr> for the object or class (depending on whether the
method is an object or class method, respectively); look below at the section
L<ERROR HANDLING> for more information.
=head2 MT->new( %args )
Constructs a new I<MT> instance and returns that object. Returns C<undef>
on failure.
I<new> will also read your F<mt.cfg> file (provided that it can find it--if
you find that it can't, take a look at the I<Config> directive, below). It
will also initialize the chosen object driver; the default is the C<DBM>
object driver.
I<%args> can contain:
=over 4
=item * Config
Path to the F<mt.cfg> file.
If you do not specify a path, I<MT> will try to find your F<mt.cfg> file
in the current working directory.
=back
=head2 $mt->rebuild( %args )
Rebuilds your entire blog, indexes and archives; or some subset of your blog,
as specified in the arguments.
I<%args> can contain:
=over 4
=item * Blog
An I<MT::Blog> object corresponding to the blog that you would like to
rebuild.
Either this or C<BlogID> is required.
=item * BlogID
The ID of the blog that you would like to rebuild.
Either this or C<Blog> is required.
=item * ArchiveType
The archive type that you would like to rebuild. This should be one of the
following values: C<Individual>, C<Daily>, C<Weekly>, C<Monthly>, or
C<Category>.
This argument is optional; if not provided, all archive types will be rebuilt.
=item * EntryCallback
A callback that will be called for each entry that is rebuilt. If provided,
the value should be a subroutine reference; the subroutine will be handed
the I<MT::Entry> object for the entry that is about to be rebuilt. You could
use this to keep a running log of which entry is being rebuilt, for example:
$mt->rebuild(
BlogID => $blog_id,
EntryCallback => sub { print $_[0]->title, "\n" },
);
Or to provide a status indicator:
use MT::Entry;
my $total = MT::Entry->count({ blog_id => $blog_id });
my $i = 0;
local $| = 1;
$mt->rebuild(
BlogID => $blog_id,
EntryCallback => sub { printf "%d/%d\r", ++$i, $total },
);
print "\n";
This argument is optional; by default no callbacks are executed.
=item * NoIndexes
By default I<rebuild> will rebuild the index templates after rebuilding all
of the entries; if you do not want to rebuild the index templates, set the
value for this argument to a true value.
This argument is optional.
=item * Limit
Limit the number of entries to be rebuilt to the last C<N> entries in the
blog. For example, if you set this to C<20> and do not provide an offset (see
L<Offset>, below), the 20 most recent entries in the blog will be rebuilt.
This is only useful if you are rebuilding C<Individual> archives.
This argument is optional; by default all entries will be rebuilt.
=item * Offset
When used with C<Limit>, specifies the entry at which to start rebuilding
your individual entry archives. For example, if you set this to C<10>, and
set a C<Limit> of C<5> (see L<Limit>, above), entries 10-14 (inclusive) will
be rebuilt. The offset starts at C<0>, and the ordering is reverse
chronological.
This is only useful if you are rebuilding C<Individual> archives, and if you
are using C<Limit>.
This argument is optional; by default all entries will be rebuilt, starting
at the first entry.
=back
=head2 $mt->rebuild_entry( %args )
Rebuilds a particular entry in your blog (and its dependencies, if specified).
I<%args> can contain:
=over 4
=item * Entry
An I<MT::Entry> object corresponding to the object you would like to rebuild.
This argument is required.
=item * Blog
An I<MT::Blog> object corresponding to the blog to which the I<Entry> belongs.
This argument is optional; if not provided, the I<MT::Blog> object will be
loaded in I<rebuild_entry> from the I<$entry-E<gt>blog_id> column of the
I<MT::Entry> object passed in. If you already have the I<MT::Blog> object
loaded, however, it makes sense to pass it in yourself, as it will skip one
small step in I<rebuild_entry> (loading the object).
=item * BuildDependencies
Saving an entry can have effects on other entries; so after saving, it is
often necessary to rebuild other entries, to reflect the changes onto all
of the affected archive pages, indexes, etc.
If you supply this parameter with a true value, I<rebuild_indexes> will
rebuild: the archives for the next and previous entries, chronologically;
all of the index templates; the archives for the next and previous daily,
weekly, and monthly archives.
=back
=head2 $mt->rebuild_indexes( %args )
Rebuilds all of the index templates in your blog, or just one, if you use
the I<Template> argument (below). Only rebuilds templates that are set to
be rebuilt automatically, unless you use the I<Force> (below).
I<%args> can contain:
=over 4
=item * Blog
An I<MT::Blog> object corresponding to the blog whose indexes you would like
to rebuild.
Either this or C<BlogID> is required.
=item * BlogID
The ID of the blog whose indexes you would like to rebuild.
Either this or C<Blog> is required.
=item * Template
An I<MT::Template> object specifying the index template to rebuild; if you use
this argument, I<only> this index template will be rebuilt.
Note that if the template that you specify here is set to not rebuild
automatically, you I<must> specify the I<Force> argument in order to force it
to be rebuilt.
=item * Force
A boolean flag specifying whether or not to rebuild index templates who have
been marked not to be rebuilt automatically.
The default is C<0> (do not rebuild such templates).
=back
=head2 $mt->ping( %args )
Sends all configured XML-RPC pings as a way of notifying other community
sites that your blog has been updated.
I<%args> can contain:
=over 4
=item * Blog
An I<MT::Blog> object corresponding to the blog for which you would like to
send the pings.
Either this or C<BlogID> is required.
=item * BlogID
The ID of the blog for which you would like to send the pings.
Either this or C<Blog> is required.
=back
=head2 $mt->set_language($tag)
Loads the localization plugin for the language specified by I<$tag>, which
should be a valid and supported language tag--see I<supported_languages> to
obtain a list of supported languages.
The language is set on a global level, and affects error messages and all
text in the administration system.
This method can be called as either a class method or an object method; in
other words,
MT->set_language($tag)
will also work. However, the setting will still be global--it will not be
specified to the I<$mt> object.
The default setting--set when I<MT::new> is called--is U.S. English. If a
I<DefaultLanguage> is set in F<mt.cfg>, the default is then set to that
language.
=head2 $mt->translate($str)
Translates I<$str> into the currently-set language (set by I<set_language>),
and returns the translated string.
=head2 $mt->current_language
Returns the language tag for the currently-set language.
=head2 MT->supported_languages
Returns a reference to an associative array mapping language tags to their
proper names. For example:
use MT;
my $langs = MT->supported_languages;
print map { $_ . " => " . $langs->{$_} . "\n" } keys %$langs;
=head2 MT->VERSION
Returns the version of MT (including any beta/alpha designations).
=head2 MT->version_number
Returns the numeric version of MT (without any beta/alpha designations).
For example, if I<VERSION> returned C<2.5b1>, I<version_number> would
return C<2.5>.
=head1 ERROR HANDLING
On an error, all of the above methods return C<undef>, and the error message
can be obtained by calling the method I<errstr> on the class or the object
(depending on whether the method called was a class method or an instance
method).
For example, called on a class name:
my $mt = MT->new or die MT->errstr;
Or, called on an object:
$mt->rebuild(BlogID => $blog_id)
or die $mt->errstr;
=head1 LICENSE
Please see the file F<LICENSE> in the Movable Type distribution.
=head1 AUTHOR & COPYRIGHT
Except where otherwise noted, MT is Copyright 2001, 2002 Benjamin Trott,
[email protected], and Mena Trott, [email protected]. All rights
reserved.
=cut