Permalink
Browse files

Updated to add the Tag-Index feature. Now tags are indexed based on e…

…ntry-categories. One can retrieve tags based on one or more category(s)
  • Loading branch information...
1 parent 9174056 commit 6eacee09f25708c01e5fd81929740a6ddbcf5301 Arvind Tripathy committed Jan 6, 2010
@@ -0,0 +1,36 @@
+::README for SphinxTags::
+
+A complex plugin that relates Tags to Categories. Yes, for some reason we were urged to associate these two entities and return a tag-cloud based on a category.
+
+::Administration::
+1. Verify if Sphinx is actually installed and running correctly on the server
+2. Verify that the SphinxSearch MT plugin is deployed
+3. After installing this plugin to your MT, visit CMS->Settings->Plugins->SphinxSearch
+4. Download latest copy of sphinx.conf and merge with existing if you've made changes to prior sphinx.conf
+5. Run the sphinx indexer with the --rotate option to read the latest data
+6. Test the sphinx indexes for tags by the following command:
+ /path/to/sphinx/search -c /path/to/sphinx/files/sphinx.conf -i tag_index TAG_SEARCH_TERM
+
+
+::Configuration::
+1. Visit your Blog CMS and edit the sidebar widget that renders the tag-cloud
+2. Replace the current tag-cloud lines with the following:
+
+ <mt:Unless name="datebased_archive">
+ <mt:IfArchiveType archive_type="Category">
+ <mt:setvarblock name='cat_name'><mt:ArchiveTitle></mt:setvarblock>
+ </mt:IfArchiveType>
+ </mt:Unless>
+ <mt:setvarblock name='my_blog'><mt:BlogId></mt:setvarblock>
+ <mt:SphinxTagPool category="$cat_name" blog_ids="$my_blog">
+
+3. Copy over one of the templates found in this SphinxTags/tmpl/ folder.
+ tagcloud.tmpl => renders the simple cloud with some CSS formatting
+ tagsearch.tmpl => simple FORM based tag search
+ (it doesn't harm to copy both)
+4. Edit the mt-config.cgi and add the chosen template from the previous step
+
+ SearchAltTemplate tagcloud tagcloud.tmpl
+
+5. Rebuild the Category Archives or the entire site based on where you expect the Tag Clouds to show up.
+6. Sit back, enjoy your blog.
@@ -1,7 +1,7 @@
id: SphinxSearch
name: SphinxSearch
description: Alternative search engine in MT using SphinxSearch
-version: 0.200
+version: 0.201
author_name: Six Apart, Ltd.
author_link: http://www.sixapart.com/
@@ -126,6 +126,10 @@ tags:
SearchParameters: $SphinxSearch::SphinxSearch::Tags::search_parameters_tag
SearchDateStart: $SphinxSearch::SphinxSearch::Tags::search_date_start_tag
SearchDateEnd: $SphinxSearch::SphinxSearch::Tags::search_date_end_tag
+
+ # special tag
+ SphinxTagPool: '$SphinxSearch::SphinxSearch::Tags::_hdlr_sphinx_tag_pool'
+
block:
IfCurrentSearchResultsPage?: $SphinxSearch::SphinxSearch::Tags::if_current_search_results_page_conditional_tag
IfNotCurrentSearchResultsPage?: $SphinxSearch::SphinxSearch::Tags::if_not_current_search_results_page
@@ -143,6 +147,10 @@ tags:
IfSearchDateStart?: $SphinxSearch::SphinxSearch::Tags::if_search_date_start_conditional_tag
IfSearchDateEnd?: $SphinxSearch::SphinxSearch::Tags::if_search_date_end_conditional_tag
+ # special tags
+ SphinxTags: '$SphinxSearch::SphinxSearch::Tags::_hdlr_sphinx_search_results'
+ SearchResults: '$SphinxSearch::SphinxSearch::Tags::_hdlr_sphinx_search_results'
+
task_workers:
sphinx_indexer_task:
label: "Runs the sphinx indexer."
@@ -48,7 +48,34 @@ sub _get_data_rows {
my @mva_fields;
my @normal_fields;
+ # Do counts first
+ if ( my $counts = $index_hash->{count_columns} ) {
+ for my $count ( keys %$counts ) {
+ my $what_class = $counts->{$count}->{what};
+ my $with_column = $counts->{$count}->{with};
+ my $wheres = $counts->{$count}->{select_values};
+
+ eval("require $what_class;");
+ next if ($@);
+
+ my $terms = {$with_column => $obj->id};
+ if ($wheres) {
+ @$terms{keys %$wheres} = values %$wheres;
+ }
+
+ my $count_val = $what_class->count($terms);
+ next if ($@);
+
+ my %tmp_field;
+ $tmp_field{key} = $count;
+ $tmp_field{value} = $count_val;
+ push @group_fields, \%tmp_field;
+ }
+ }
+
+ # Do regular columns next
foreach(@{ $index_hash->{columns}}) {
+
my %tmp_field;
$tmp_field{key} = $_;
$tmp_field{value} = encode_html($obj->$_);
@@ -77,40 +104,82 @@ sub _get_data_rows {
}
}
+ # Do special and/or mva columns
if ($index_hash->{mva}) {
foreach my $mva ( keys %{ $index_hash->{mva} } ) {
my $cur_mva = $index_hash->{mva}->{$mva};
+ my %tmp_field;
+ $tmp_field{key} = $mva;
- my %terms;
- my $mva_key = "id";
- if ( my $sel_values = $cur_mva->{select_values} ) {
- @terms{keys %$sel_values} = values %$sel_values;
- }
- if( my $id_columns = $cur_mva->{by} ) {
- $terms{$id_columns->[0]} = $obj->id;
- $mva_key = $id_columns->[1];
- } else {
- %terms = ( "${mva}_".$index_hash->{id_column} => $obj->id );
- }
-
- my $mva_source = $cur_mva->{with};
- next if(!$mva_source || $mva_source eq '');
-
- eval("use $mva_source");
+ # This is a hack. XMLPipes and SQL queries
+ if ( my $mva_query = $cur_mva->{query} ) {
+
+ my $mva_class = $cur_mva->{to};
+ $mva_class = $cur_mva->{with} if(!$mva_class);
+ my @cols = @{$cur_mva->{by}};
+
+ eval("require $mva_class;") if($mva_class);
+ next if ($@);
- my @mva_value;
- if($mva_source->can('load')) {
- my @mva_vals = $mva_source->load( \%terms );
- foreach(@mva_vals) {
- push @mva_value, $_->$mva_key;
+ my $driver = $mva_class->dbi_driver;
+ my $dbh = $driver->rw_handle;
+
+ $mva_query .= " AND ".$cols[0]." = ".$obj->id;
+ my $sth = $dbh->prepare($mva_query);
+
+ return 0 if !$sth; # ignore this operation if _meta column doesn't exist
+ $sth->execute or next;
+
+ my $rows;
+ my @mva_value;
+ while (my $row = $sth->fetchrow_arrayref) {
+ $rows++;
+ push @mva_value, $row->[1];
}
- my %tmp_field;
- $tmp_field{key} = $mva;
+ $sth->finish;
+
$tmp_field{value} = join(',',@mva_value);
-
push @mva_fields, \%tmp_field;
+
+ } else {
+
+ my %terms;
+ my $mva_key = "id";
+ if ( my $sel_values = $cur_mva->{select_values} ) {
+ @terms{keys %$sel_values} = values %$sel_values;
+ }
+ if( my $id_columns = $cur_mva->{by} ) {
+
+ # First column is selecting Object column
+ $terms{$id_columns->[0]} = $obj->id;
+
+ # Second column becomes new Join column
+ $mva_key = $id_columns->[1];
+ next if($mva_key !~ /_id/ );
+
+ } else {
+ %terms = ( "${mva}_".$index_hash->{id_column} => $obj->id );
+ }
+
+ my $mva_source = $cur_mva->{with};
+ next if(!$mva_source || $mva_source eq '');
+
+ eval("use $mva_source");
+
+ my %args;
+ my @mva_value;
+ if($mva_source->can('load')) {
+
+ my @mva_vals = $mva_source->load( \%terms, \%args );
+ foreach(@mva_vals) {
+ push @mva_value, $_->$mva_key;
+ }
+
+ $tmp_field{value} = join(',',@mva_value);
+ push @mva_fields, \%tmp_field;
+ }
}
}
}
@@ -16,6 +16,7 @@ sub init_app {
no warnings 'redefine';
*MT::App::Search::execute = sub {
require SphinxSearch::Util;
+
my $results = _get_sphinx_results(@_);
return $_[0]->error( "Error querying searchd: "
. ( SphinxSearch::Util::_get_sphinx_error() || $_[0]->errstr )
@@ -89,7 +90,7 @@ sub _get_sphinx_results {
my $sort_mode = {};
my $sort_mode_param = $app->param('sort_mode') || 'descend';
my $sort_by_param = $app->param('sort_by')
- || ( $index =~ /\bentry\b/ ? 'authored_on' : 'created_on' );
+ || ( $index =~ /\bentry\b/ ? 'authored_on' : ( $index =~ /\btag\b/ ? 'entry_count' : 'created_on' ) );
if ( $sort_mode_param eq 'descend' ) {
$sort_mode = { Descend => $sort_by_param };
@@ -319,6 +320,7 @@ sub _get_sphinx_results {
),
UseDistributed => $distributed,
);
+
return unless ($results);
my $i = 0;
@@ -4,6 +4,8 @@ package SphinxSearch::Tags;
use strict;
use warnings;
+require MT::Tag;
+
sub search_results_page_loop_container_tag {
my ( $ctx, $args, $cond ) = @_;
@@ -285,20 +287,20 @@ sub search_categories_container_tag {
for my $cat (@cats) {
local $ctx->{__stash}{category} = $cat;
-# Don't think we need all these bits right now
-# local $ctx->{__stash}{entries};
-# local $ctx->{__stash}{category_count};
-# local $ctx->{__stash}{blog_id} = $cat->blog_id;
-# local $ctx->{__stash}{blog} = MT::Blog->load($cat->blog_id, { cached_ok => 1 });
-# my @args = (
-# { blog_id => $cat->blog_id,
-# status => MT::Entry::RELEASE() },
-# { 'join' => [ 'MT::Placement', 'entry_id',
-# { category_id => $cat->id } ],
-# 'sort' => 'created_on',
-# direction => 'descend', });
-# $ctx->{__stash}{category_count} = MT::Entry->count(@args);
-# next unless $ctx->{__stash}{category_count} || $args->{show_empty};
+ # # Don't think we need all these bits right now
+ # local $ctx->{__stash}{entries};
+ # local $ctx->{__stash}{category_count};
+ # local $ctx->{__stash}{blog_id} = $cat->blog_id;
+ # local $ctx->{__stash}{blog} = MT::Blog->load($cat->blog_id, { cached_ok => 1 });
+ # my @args = (
+ # { blog_id => $cat->blog_id,
+ # status => MT::Entry::RELEASE() },
+ # { 'join' => [ 'MT::Placement', 'entry_id',
+ # { category_id => $cat->id } ],
+ # 'sort' => 'created_on',
+ # direction => 'descend', });
+ # $ctx->{__stash}{category_count} = MT::Entry->count(@args);
+ # next unless $ctx->{__stash}{category_count} || $args->{show_empty};
defined( my $out = $builder->build( $ctx, $tokens, $cond ) )
or return $ctx->error( $builder->errstr );
@@ -405,4 +407,111 @@ sub if_last_search_results_page {
!next_search_results_page(@_);
}
+# special tags
+
+# This tag can be used in two ways for now in the Search Results template:
+ # 1) through SeachResults, which it overrides and falls back if no tags were found
+ # 2) specifically through SphinxTags, which is an alternative for search results block
+# Later this can be expanded to more objects returned in the search results that the CORE engine cannot handle
+
+sub _hdlr_sphinx_search_results {
+ my ( $ctx, $args, $cond ) = @_;
+
+ my $tmpltag = lc $ctx->stash('tag');
+
+ # for the case that we want to use mt:Entries with mt-search
+ # send to MT::Template::Search if searh results are found
+ if ($ctx->stash('results') && (!$ctx->stash('sphinxtags') && $tmpltag eq 'searchresults') ) {
+ require MT::Template::Context::Search;
+ return MT::Template::Context::Search::_hdlr_results($ctx, $args, $cond);
+ }
+
+ my @tags = ( @{ $ctx->stash('sphinxtags') } );
+ if(@tags) {
+
+ my $total = scalar(@tags);
+
+ # Initialize the loop variables
+ my $res = ''; # Cumulative output
+ my $count = 0; # Loop counter
+ my $attr = $args->{attributes} || {}; # Tag attributes
+ my $glue = $attr->{glue} || $args->{glue}; # Glue for output
+ my $vars = $ctx->{__stash}{vars} ||= {}; # Template variables
+ my $builder = $ctx->stash('builder'); # Builder objects
+ my $tokens = $ctx->stash('tokens'); # Current template tokens
+
+ for my $tag (@tags) {
+
+ $count++;
+ local $ctx->{__stash}{Tag} = $tag;
+
+ local $vars->{__first__} = $count == 1;
+ local $vars->{__last__} = ($count == $total);
+ local $vars->{__odd__} = ($count % 2) == 1;
+ local $vars->{__even__} = ($count % 2) == 0;
+ local $vars->{__counter__} = $count;
+
+ defined(my $out = $builder->build($ctx, $tokens, $cond))
+ or return $ctx->error( $builder->errstr );
+
+ $res .= $glue if defined($glue) && ( $count > 1 );
+ $res .= $out;
+ }
+ $res;
+ }
+ else {
+
+ # Fall back to standard search results
+ require MT::Template::Context::Search;
+ return MT::Template::Context::Search::_hdlr_results($ctx, $args, $cond);
+ }
+}
+
+# Special function tag to dynamically load a Search URL through jQuery and return the tag-pool based on its parameters.
+# Accepts the following:
+ # div => ID of thne HTML element to load the results in. If not passed it loads in its own DIV by the ID #tagpool
+ # category => comma-delimited list of category basenames to filter the results. Can be single or list of all categories but not meant to be empty
+ # searchall => to return tags always
+ # include_blogs => filter based on one or more blogs
+ # jquery => can be 1, 0 or anything. If not 0, then a link to jQuery is included in the published page statically. Loads from the jQuery host
+
+sub _hdlr_sphinx_tag_pool {
+ my ($ctx, $args) = @_;
+
+ my $div = $args->{div} || 'tagpool';
+ my $cats = $args->{category} || '';
+ my $tmpl = $args->{template} || 'tagcloud';
+ my $searchall = $args->{searchall} || '1';
+ my $blogs = $args->{include_blogs} || $args->{blog_ids}|| '';
+
+ my $load_jquery = $args->{jquery} || '0';
+ $load_jquery = '<script type="text/javascript" src="http://code.jquery.com/jquery-latest.pack.js"></script>' if($load_jquery ne '0');
+ $load_jquery = '' if($load_jquery eq '0');
+
+ my $app = MT->instance;
+ my $script = $ctx->{config}->SearchScript;
+
+ my $cgi_path = $app->config('CGIPath');
+ $cgi_path .= '/' unless $cgi_path =~ m!/$!;
+ $cgi_path .= $script;
+
+ my $html = <<HTML;
+
+ $load_jquery
+ <div id="tagpool">
+ <div id="waiting">...</div>
+ </div>
+ <script type="text/javascript">
+ \$(document).ready(function(){
+ \$.get("$cgi_path", { IncludeBlogs: "$blogs", index: "tag", Template: "$tmpl", searchall: "$searchall", category: "$cats", sort_by: "entry_count" },
+ function(data){
+ // alert("Data Loaded: " + data);
+ \$("#$div").html(data);
+ });
+ });
+ </script>
+HTML
+ return $html;
+}
+
1;
Oops, something went wrong.

0 comments on commit 6eacee0

Please sign in to comment.