diff --git a/Bugzilla/Hook.pm b/Bugzilla/Hook.pm
index 0db7baf7dc0c24c86a5f23f042020e70c03bb294..2d285dd22ca7125131818257df2b829fbf4403a6 100644
--- a/Bugzilla/Hook.pm
+++ b/Bugzilla/Hook.pm
@@ -432,6 +432,41 @@ The definition is structured as:
 
 =back
 
+=head2 buglist_column_joins
+
+This allows you to join additional tables to display additional columns
+in buglists. This hook is generally used in combination with the
+C<buglist_columns> hook.
+
+Params:
+
+=over
+
+=item C<column_joins> - A hashref containing data to return back to
+L<Bugzilla::Search>. This hashref contains names of the columns as keys and 
+a hashref about table to join as values. This hashref has the following keys:
+
+=over
+
+=item C<table> - The name of the additional table to join.
+
+=item C<as> - (optional) The alias used for the additional table. This alias
+must not conflict with an existing alias already used in the query.
+
+=item C<from> - (optional) The name of the column in the C<bugs> table which
+the additional table should be linked to. If omitted, C<bug_id> will be used.
+
+=item C<to> - (optional) The name of the column in the additional table which
+should be linked to the column in the C<bugs> table, see C<from> above.
+If omitted, C<bug_id> will be used.
+
+=item C<join> - (optional) Either INNER or LEFT. Determine how the additional
+table should be joined with the C<bugs> table. If omitted, LEFT is used.
+
+=back
+
+=back
+
 =head2 search_operator_field_override
 
 This allows you to modify L<Bugzilla::Search/OPERATOR_FIELD_OVERRIDE>,
diff --git a/Bugzilla/Search.pm b/Bugzilla/Search.pm
index 64642774d441ab384e72ed56d8806bb2e6869ce3..d349a31aeadbaef55950b40bc6f70494066afa3f 100644
--- a/Bugzilla/Search.pm
+++ b/Bugzilla/Search.pm
@@ -971,7 +971,8 @@ sub _column_join {
     my ($self, $field) = @_;
     # The _realname fields require the same join as the username fields.
     $field =~ s/_realname$//;
-    my $join_info = COLUMN_JOINS->{$field};
+    my $column_joins = $self->_get_column_joins();
+    my $join_info = $column_joins->{$field};
     if ($join_info) {
         # Don't allow callers to modify the constant.
         $join_info = dclone($join_info);
@@ -1809,6 +1810,20 @@ sub _get_operator_field_override {
     return $cache->{operator_field_override};
 }
 
+sub _get_column_joins {
+    my $self = shift;
+    my $cache = Bugzilla->request_cache;
+
+    return $cache->{column_joins} if defined $cache->{column_joins};
+
+    my %column_joins = %{ COLUMN_JOINS() };
+    Bugzilla::Hook::process('buglist_column_joins',
+                            { column_joins => \%column_joins });
+
+    $cache->{column_joins} = \%column_joins;
+    return $cache->{column_joins};
+}
+
 ###########################
 # Search Function Helpers #
 ###########################
diff --git a/extensions/Example/Extension.pm b/extensions/Example/Extension.pm
index a2ab3b5fc3e864e8beb8a34041d637731cb132ee..5cd6a1d29c17d55b1aa2941201409d8d2b2e9549 100644
--- a/extensions/Example/Extension.pm
+++ b/extensions/Example/Extension.pm
@@ -181,6 +181,22 @@ sub buglist_columns {
     
     my $columns = $args->{'columns'};
     $columns->{'example'} = { 'name' => 'bugs.delta_ts' , 'title' => 'Example' };
+    $columns->{'product_desc'} = { 'name'  => 'prod_desc.description',
+                                   'title' => 'Product Description' };
+}
+
+sub buglist_column_joins {
+    my ($self, $args) = @_;
+    my $joins = $args->{'column_joins'};
+
+    # This column is added using the "buglist_columns" hook
+    $joins->{'product_desc'} = {
+        from  => 'product_id',
+        to    => 'id',
+        table => 'products',
+        as    => 'prod_desc',
+        join  => 'INNER',
+    };
 }
 
 sub search_operator_field_override {