Update Xoops 2.0.x Search Page to Support the Template Engine

Requested and Answered by Christian on 2007/7/30 16:19:04

Update Xoops 2.0.x Search Page to Support the Template Engine

Overview Xoops has a template engine that allows you to separate page generation (php code) from page layout and presentation (HTML + CSS). Xoops also supports a theme engine. This level of customization exists “above” data generation + layout and is outside the scope of this article. Templates are HTML documents written to make use of Smarty tags. Smarty is an additional language/layer that you must learn in order layout your Xoops generated HTML. Basically, though, the paradigm is one of adding in tags throughout your HTML that act as placeholders for incoming variables that were set up by the corresponding PHP page. By default, the search page for Xoops is found at the root of your Xoops directory and is called search.php. This page (unlike most) actually generates the HTML necessary to carry out it's assigned task directly inside the PHP code with a series of 'echo' statements. This makes the process of updating the look and feel of the Xoops search page more difficult since you now have to deal with the functionality of Xoop's search engine too. This 'How To' documents the process for stripping out layout from function with regards to search.php. At the end of this tutorial, your Xoops system will have a new system-level template that is associated with your search page. You'll be able to update the look and feel of your search page by manipulating this Smarty template rather than the search.php file directly. Furthermore, the search.php page will now have an interface (or contract) between itself and the corresponding template page that consists of various tags and their meanings. This means that you can tweak search.php whenever you like to change how the search engine works without necessarily affecting the look and feel of the search page itself (unless, of course, your changes necessitate a change to the interface with the template). Back Up Everything – Use a Test Site – Yadda, Yadda, Yadda As with anything, be sure to back up your valuable data first before attempting the changes in this document. Make these changes on test site first (if you can). Although nothing here is too invasive, it's important to be sure that you can recover if something goes wrong. searchform.php In the “include” folder, there exists a file called searchform.php. This file is responsible for generating the 'advanced search' form that you see at the bottom of every search page. Before we do anything else, we need to make a small change to this form in order to make it compatible with our new search template. At the very bottom of the file, simply add the following line:

$search_form->addElement(new XoopsFormButton("""submit"_SR_SEARCH"submit"));

return 
$search_form->render();    // Added by Lankford on 2007/7/26.
?>
What does this do? Instead of the entire PHP page being included into “\search.php” (along with the creation and availability of it's $search_form variable), we treat the include like a function and 'return' the HTML version (produced by the render method) of the form that this file's code generates. modules/system/xoops_version.php Your next step is to tell Xoops about the Smarty template that you are about to create. You're probably already somewhat familiar with modules and how to install/configure them. Interestingly enough, Xoops treats it's system code like a module. This is why you see the “System Admin” button on the left side of Xoops' administration screen along with buttons for all of the other installed modules. It's because the system module is just that...a module! This is great because not only are you able to quickly and easily figure out how to configure the system in the same way that you'd configure a module, but the folks that wrote the Xoops core code are able to use the same bits of code for installing/updating system settings as they are for installing/updating modules. So what? Right? Well, the point of all this is that it is really easy to create a new template for the Xoops system. All you have to do is write the template (we'll do this later) and define that template for the Xoops system module. If you don't already know, you define templates for your modules in each module's 'xoops_version.php' file. This file contains lots of things in it that tell Xoops all about your module, not just template data. But the great thing is that, because of this architecture decision, it's really easy to define a new template. Simply add in this additional code somewhere around line 80:
$modversion['templates'][15]['description'] = 'Dummy template for custom blocks or blocks without templates';
$modversion['templates'][16]['file'] = 'system_search.html';
$modversion['templates'][16]['description'] = 'Smarty template for Xoops' search page.';

// Blocks
All we've done here is to define a 16th template. We've given it a file name, 'system_search.html' and a description which will show up whenever we try to edit our system templates. Create the Smarty Template Now it's time to really do something. Let's create the Smarty template for rendering our search page by creating a new file called '\modules\system\templates\system_search.html'. Please insert the following HTML/Smarty code into that new file that you just created:
<!-- Added by Lankford on 2007/7/26 -->

<
h3>"<{$search_type}>" <{$label_search_results}>: <{$showing}></h3>
<{
$label_keywords}>&nbsp;
    <
strong>
    <{* 
This section generates a space separated list of keywords that were searched. *}>
  <{
section name=cur_kw_searched loop=$searched_keywords}>
          <{
$searched_keywords[cur_kw_searched]}><{if $smarty.section.cur_kw_searched.index <> $smarty.section.cur_kw_searched.total}>&nbsp;<{/if}>
    <{/
section}>
    </
strong>
<
br />
<{
$label_ignored_keywords}>&nbsp;
    <
strong>
    <{* 
This section generates a space separated list of keywords that were NOT searched. *}>
     <{
section name=cur_kw_not_searched loop=$ignored_keywords}>
          <{
$ignored_keywords[cur_kw_not_searched]}><{if $smarty.section.cur_kw_not_searched.index <> $smarty.section.cur_kw_not_searched.total}>&nbsp;<{/if}>
    <{/
section}>
    </
strong>
<
br />

<{* 
    
This section generates a search results that mimic Xoops' original search.php results. 
    Note: The results are sorted.  Modules with higher hit counts are located on the page
          above modules with lower hit counts.
*}>
<{*  This section has been commented out in favor of the '
table' version located below...
<{foreach from=$module_sort_order key=sort_key item=sort_value}>
   <h3><{$sort_key}>: (<{$sort_value}> hits returned)</h3>
   
   <{section name=cur_result loop=$search_results[$sort_key].results}>
         <{if $smarty.section.cur_result.index > 0}><br /><{/if}>
       <img alt="<{$search_results[$sort_key].results[cur_result].processed_image_alt_text}>" src="<{$search_results[$sort_key].results[cur_result].processed_image_url}>" />
       <{$search_results[$sort_key].results[cur_result].processed_image_tag}>&nbsp;
       <b>
           <a href="<{$search_results[$sort_key].results[cur_result].link}>"><{$search_results[$sort_key].results[cur_result].processed_title}></a>
       </b>
       <br /><small>&nbsp;&nbsp;
           <a href="<{$search_results[$sort_key].results[cur_result].processed_user_url}>"><{$search_results[$sort_key].results[cur_result].processed_user_name}></a> <{$search_results[$sort_key].results[cur_result].processed_time}>
       </small>
   <{/section}>
  
   <br />
   <a href="<{$search_results[$sort_key].search_more_url}>"><{$search_results[$sort_key].search_more_title}></a>
<{/foreach}>

<hr />
*}>

<{* 
    This section generates a search results and places them into tables using the standard
    Xoops style tags for table formatting. 
    Note: The results are sorted.  Modules with higher hit counts are located on the page
          above modules with lower hit counts.
*}>
<{foreach from=$module_sort_order key=sort_key item=sort_value}>
  <table class="outer" cellpadding="4" cellspacing="1" width="100%">
    <tr>
      <th colspan="2" align="left" class="head">
          <b><{$sort_key}></b>: (<{$sort_value}> hits returned)
      </th>
    </tr>
    <{if ($search_results[$sort_key].search_more_title == '') and ($sort_value > 0)}>
            <tr>
                <th colspan="2">
                <table cellspacing="0" cellpadding="0" width="100%">
                    <tr>
                        <td align="left">
                                <a href="<{$search_results[$sort_key].search_prev_url}>"><{$search_results[$sort_key].search_prev_title}></a>
                        </td>
                        <td align="right">
                                <a href="<{$search_results[$sort_key].search_next_url}>"><{$search_results[$sort_key].search_next_title}></a>
                        </td>
                    </tr>
                </table>
            </th>
            </tr>
       <{/if}>
    <{section name=cur_result loop=$search_results[$sort_key].results}>
        <tr>
          <td class="head">
              <{math equation="x + y" x=$smarty.section.cur_result.index y=$start}>
          </td>
          <td align="left" class="<{cycle values="even,odd"}>" width="100%">
               <img alt="<{$search_results[$sort_key].results[cur_result].processed_image_alt_text}>" src="<{$search_results[$sort_key].results[cur_result].processed_image_url}>" />
               <{$search_results[$sort_key].results[cur_result].processed_image_tag}>&nbsp;
               <b>
                   <a href="<{$search_results[$sort_key].results[cur_result].link}>"><{$search_results[$sort_key].results[cur_result].processed_title}></a>
               </b>
               <br /><small>&nbsp;&nbsp;
                   <a href="<{$search_results[$sort_key].results[cur_result].processed_user_url}>"><{$search_results[$sort_key].results[cur_result].processed_user_name}></a> <{$search_results[$sort_key].results[cur_result].processed_time}>
               </small>
          </td>
        </tr>
       <{/section}>
        <{if $sort_value > 0 }>
           <{if $search_results[$sort_key].search_more_title == ''}>
         <tr>
                <th colspan="2" align="right">
                <table cellspacing="0" cellpadding="0" width="100%">
                    <tr>
                        <td align="left">
                                <a href="<{$search_results[$sort_key].search_prev_url}>"><{$search_results[$sort_key].search_prev_title}></a>
                        </td>
                        <td align="right">
                                <a href="<{$search_results[$sort_key].search_next_url}>"><{$search_results[$sort_key].search_next_title}></a>
                        </td>
                    </tr>
                </table>
            </th>
        </tr>
           <{else}>
             <{if $search_results[$sort_key].search_more_url != ''}>
             <tr>
                    <th colspan="2" align="right">
                         <a href="<{$search_results[$sort_key].search_more_url}>"><{$search_results[$sort_key].search_more_title}></a>
                    </th>
                </tr>
             <{/if}>
        <{/if}>
   <{/if}>
   </table>
   <br />
<{/foreach}>


<hr />
<{$search_form}>
search.php The last major step involves updating the main search PHP page in the root of the Xoops system. Since the existing page generates all the HTML, we'll have to overhaul it so that places everything into Smarty template variables and passes those variables to the template we just created instead. So, edit your '\search.php' and make sure it looks like this:
<?php
// $Id: search.php 506 2006-05-26 23:10:37Z skalpa $
//  ------------------------------------------------------------------------ //
//                XOOPS - PHP Content Management System                      //
//                    Copyright (c) 2000 XOOPS.org                           //
//                       <https://xoops.org/>                             //
//  ------------------------------------------------------------------------ //
//  This program is free software; you can redistribute it and/or modify     //
//  it under the terms of the GNU General Public License as published by     //
//  the Free Software Foundation; either version 2 of the License, or        //
//  (at your option) any later version.                                      //
//                                                                           //
//  You may not change or alter any portion of this comment or credits       //
//  of supporting developers from this source code or any supporting         //
//  source code which is considered copyrighted (c) material of the          //
//  original comment or credit authors.                                      //
//                                                                           //
//  This program is distributed in the hope that it will be useful,          //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of           //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            //
//  GNU General Public License for more details.                             //
//                                                                           //
//  You should have received a copy of the GNU General Public License        //
//  along with this program; if not, write to the Free Software              //
//  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA //
//  ------------------------------------------------------------------------ //

$xoopsOption['pagetype'] = "search";

include 
'mainfile.php';

$xoopsOption['template_main'] = 'system_search.html';

$config_handler =& xoops_gethandler('config');
$xoopsConfigSearch =& $config_handler->getConfigsByCat(XOOPS_CONF_SEARCH);

if (
$xoopsConfigSearch['enable_search'] != 1) {
    
header('Location: '.XOOPS_URL.'/index.php');
    exit();
}

include 
XOOPS_ROOT_PATH.'/header.php';

$action "search";
if (!empty(
$_GET['action'])) {
  
$action $_GET['action'];
} elseif (!empty(
$_POST['action'])) {
  
$action $_POST['action'];
}
$query "";
if (!empty(
$_GET['query'])) {
  
$query $_GET['query'];
} elseif (!empty(
$_POST['query'])) {
  
$query $_POST['query'];
}
$andor "AND";
if (!empty(
$_GET['andor'])) {
  
$andor $_GET['andor'];
} elseif (!empty(
$_POST['andor'])) {
  
$andor $_POST['andor'];
}
$mid $uid $start 0;
if ( !empty(
$_GET['mid']) ) {
  
$mid intval($_GET['mid']);
} elseif ( !empty(
$_POST['mid']) ) {
  
$mid intval($_POST['mid']);
}
if (!empty(
$_GET['uid'])) {
  
$uid intval($_GET['uid']);
} elseif (!empty(
$_POST['uid'])) {
  
$uid intval($_POST['uid']);
}
if (!empty(
$_GET['start'])) {
  
$start intval($_GET['start']);
} elseif (!empty(
$_POST['start'])) {
  
$start intval($_POST['start']);
}

$xoopsTpl->assign("start"$start 1);

$queries = array();

if (
$action == "recoosults") {
    if (
$query == "") {
         
redirect_header("search.php",1,_SR_PLZENTER);
        exit();
    }
} elseif (
$action == "showall") {
    if (
$query == "" || empty($mid)) {
        
redirect_header("search.php",1,_SR_PLZENTER);
        exit();
    }
} elseif (
$action == "showallbyuser") {
    if (empty(
$mid) || empty($uid)) {
        
redirect_header("search.php",1,_SR_PLZENTER);
        exit();
    }
}

$groups is_object($xoopsUser) ? $xoopsUser -> getGroups() : XOOPS_GROUP_ANONYMOUS;
$gperm_handler = & xoops_gethandler'groupperm' );
$available_modules $gperm_handler->getItemIds('module_read'$groups);

if (
$action == 'search') {
    
// This area seems to handle the 'just display the advanced search page' part.
   
$search_form = include 'include/searchform.php';
   
$xoopsTpl->assign('search_form'$search_form);
    include 
XOOPS_ROOT_PATH.'/footer.php';
    exit();
}

if ( 
$andor != "OR" && $andor != "exact" && $andor != "AND" ) {
    
$andor "AND";
}
$xoopsTpl->assign("search_type"$andor);

$myts =& MyTextSanitizer::getInstance();
if (
$action != 'showallbyuser') {
    if ( 
$andor != "exact" ) {
        
$ignored_queries = array(); // holds kewords that are shorter than allowed minmum length
        
$temp_queries preg_split('/[s,]+/'$query);
        foreach (
$temp_queries as $q) {
            
$q trim($q);
            if (
strlen($q) >= $xoopsConfigSearch['keyword_min']) {
                
$queries[] = $myts->addSlashes($q);
            } else {
                
$ignored_queries[] = $myts->addSlashes($q);
            }
        }
        if (
count($queries) == 0) {
            
redirect_header('search.php'2sprintf(_SR_KEYTOOSHORT$xoopsConfigSearch['keyword_min']));
            exit();
        }
    } else {
        
$query trim($query);
        if (
strlen($query) < $xoopsConfigSearch['keyword_min']) {
            
redirect_header('search.php'2sprintf(_SR_KEYTOOSHORT$xoopsConfigSearch['keyword_min']));
            exit();
        }
        
$queries = array($myts->addSlashes($query));
    }
}
$xoopsTpl->assign("label_search_results"_SR_SEARCHRESULTS);

// Keywords section.
$xoopsTpl->assign("label_keywords"_SR_KEYWORDS ':');
$keywords = array();
$ignored_keywords = array();
foreach (
$queries as $q) {
    
$keywords[] = htmlspecialchars(stripslashes($q));
}
if (!empty(
$ignored_queries)) {
     
$xoopsTpl->assign("label_ignored_keywords"sprintf(_SR_IGNOREDWORDS$xoopsConfigSearch['keyword_min']));
    foreach (
$ignored_queries as $q) {
        
$ignored_keywords[] = htmlspecialchars(stripslashes($q));
    }
    
$xoopsTpl->assign("ignored_keywords"$ignored_keywords);
}
$xoopsTpl->assign("searched_keywords"$keywords);

$all_results = array();
$all_results_counts = array();
switch (
$action) {
    case 
"results":
        
$module_handler =& xoops_gethandler('module');
        
$criteria = new CriteriaCompo(new Criteria('hassearch'1));
        
$criteria->add(new Criteria('isactive'1));
        
$criteria->add(new Criteria('mid'"(".implode(','$available_modules).")"'IN'));
        
$modules =& $module_handler->getObjects($criteriatrue);
        
$mids = isset($_REQUEST['mids']) ? $_REQUEST['mids'] : array();
        if (empty(
$mids) || !is_array($mids)) {
            unset(
$mids);
            
$mids array_keys($modules);
        }
    
        foreach (
$mids as $mid) {
            
$mid intval($mid);
            if ( 
in_array($mid$available_modules) ) {
                
$module =& $modules[$mid];
                
$results =& $module->search($queries$andor50);
                
$xoopsTpl->assign("showing"sprintf(_SR_SHOWING15));
                
$count count($results);
                
$all_results_counts[$module->getVar('name')] = $count;

                if (!
is_array($results) || $count == 0) {
                    
$all_results[$module->getVar('name')] = array();
                } else {
                    for (
$i 0$i $count$i++) {
                          
$results[$i]['processed_image_alt_text'] = $myts->makeTboxData4Show($module->getVar('name')) . ": ";
                        if (isset(
$results[$i]['image']) && $results[$i]['image'] != "") {
                              
$results[$i]['processed_image_url'] = "modules/" $module->getVar('dirname') . "/" $results[$i]['image'];
                        } else {
                              
$results[$i]['processed_image_url'] = "images/icons/posticon2.gif";
                        }
                        if (!
preg_match("/^http[s]*:///i"$results[$i]['link'])) {
                            
$results[$i]['link'] = "modules/".$module->getVar('dirname')."/".$results[$i]['link'];
                        }
                        
$results[$i]['processed_title'] = $myts->makeTboxData4Show($results[$i]['title']);
                        
$results[$i]['uid'] = @intval($results[$i]['uid']);
                        if ( !empty(
$results[$i]['uid']) ) {
                            
$uname XoopsUser::getUnameFromId($results[$i]['uid']);
                            
$results[$i]['processed_user_name'] = $uname;
                            
$results[$i]['processed_user_url'] = XOOPS_URL."/userinfo.php?uid=".$results[$i]['uid'];
                        }
                        
$results[$i]['processed_time'] = !empty($results[$i]['time']) ? " ("formatTimestamp(intval($results[$i]['time'])).")" "";
                    }
                    if ( 
$count >= ) {
                        
$search_url XOOPS_URL.'/search.php?query='.urlencode(stripslashes(implode(' '$queries)));
                        
$search_url .= "&mid=$mid&action=showall&andor=$andor";
                    } else {
                        
$search_url "";
                    }
                    
$all_results[$module->getVar('name')] = array("search_more_title" => _SR_SHOWALLR
                                                                
"search_more_url" => htmlspecialchars($search_url), 
                                                                                                                  
"search_next_title" => ""
                                                                    
"search_next_url" => ""
                                                                    
"search_prev_title" => "",
                                                                    
"search_prev_url" => "",
                                                                
"results" =>$results);
                }
            }
            unset(
$results);
            unset(
$module);
        }
        break;
    case 
"showall":
    case 
'showallbyuser':
        
$module_handler =& xoops_gethandler('module');
        
$module =& $module_handler->get($mid);
        
$results =& $module->search($queries$andor20$start$uid);
      
$xoopsTpl->assign("showing"sprintf(_SR_SHOWING$start 1$start 20));
        
$count count($results);
        
$all_results_counts[$module->getVar('name')] = $count;
        if (
is_array($results) && $count 0) {
            
$next_results =& $module->search($queries$andor1$start 20$uid);
            
$next_count count($next_results);
            
$has_next false;

            if (
is_array($next_results) && $next_count == 1) {
                
$has_next true;
            }

            for (
$i 0$i $count$i++) {
                  
$results[$i]['processed_image_alt_text'] = $myts->makeTboxData4Show($module->getVar('name')) . ": ";
                if (isset(
$results[$i]['image']) && $results[$i]['image'] != "") {
                      
$results[$i]['processed_image_url'] = "modules/" $module->getVar('dirname') . "/" $results[$i]['image'];
                } else {
                      
$results[$i]['processed_image_url'] = "images/icons/posticon2.gif";
                }
                if (!
preg_match("/^http[s]*:///i"$results[$i]['link'])) {
                    
$results[$i]['link'] = "modules/".$module->getVar('dirname')."/".$results[$i]['link'];
                }
                
$results[$i]['processed_title'] = $myts->makeTboxData4Show($results[$i]['title']);
                
$results[$i]['uid'] = @intval($results[$i]['uid']);
                if ( !empty(
$results[$i]['uid']) ) {
                    
$uname XoopsUser::getUnameFromId($results[$i]['uid']);
                    
$results[$i]['processed_user_name'] = $uname;
                    
$results[$i]['processed_user_url'] = XOOPS_URL."/userinfo.php?uid=".$results[$i]['uid'];
                }
                
$results[$i]['processed_time'] = !empty($results[$i]['time']) ? " ("formatTimestamp(intval($results[$i]['time'])).")" "";
            }
            
                        
$search_url_prev "";
                        
$search_url_next "";
                        
              
$search_url XOOPS_URL.'/search.php?query='.urlencode(stripslashes(implode(' '$queries)));
                
$search_url .= "&mid=$mid&action=$action&andor=$andor";
                if (
$action=='showallbyuser') {
                    
$search_url .= "&uid=$uid";
                }
                if ( 
$start ) {
                    
$prev $start 20;
                    
$search_url_prev $search_url."&start=$prev";
                }
                if (
false != $has_next) {
                    
$next $start 20;
                    
$search_url_next $search_url."&start=$next";
                }
                
          
$all_results[$module->getVar('name')] = array("search_more_title" => "",
                                                                                                      
"search_more_url" => "",
                                                                                                      
"search_next_title" => _SR_NEXT
                                                        
"search_next_url" => htmlspecialchars($search_url_next), 
                                                        
"search_prev_title" => _SR_PREVIOUS,
                                                        
"search_prev_url" => htmlspecialchars($search_url_prev),
                                                        
"results" =>$results);
        } else {
            echo 
'<p>'._SR_NOMATCH.'</p>';
        }
        break;
}
arsort($all_results_counts);
$xoopsTpl->assign("module_sort_order"$all_results_counts);
$xoopsTpl->assign("search_results"$all_results);

$search_form = include 'include/searchform.php';
$xoopsTpl->assign('search_form'$search_form);

include 
XOOPS_ROOT_PATH."/footer.php";
?>
Update the System Module You've now placed all your shiny new code onto the site, but you won't see anything good yet until you do a couple of things first. First and foremost, you need to 'update' the system module so that your new Smarty template is loaded into the database. Follow these steps to do this: *) Goto the administration section on your website ('\admin.php'). *) Click the “System Admin” button on the left side of the screen. *) Click on “Modules”. *) Click the module update button for the system administration module (Resized Image) and confirm your selection. You should see the following text somewhere on the screen: Quote:
Template system_search.html inserted to the database. Template system_search.html recompiled.
Update the Default Template Set (optional) Hopefully, you are aware of the fact that you can define multiple template sets and select whichever one you'd like to be the 'default' template set for your web site. It would be really great if you could associate template sets with themes (hint, hint) ... but I digress. The point here, is that if you've decided to modify your templates to enhance the visual appearance of your web site (and if you are following these instructions, then that's a pretty safe assumption), you'll want to ensure that the new template we just made available is present in your default template set. Please following these instructions to do so: *) Goto the administration section on your website ('\admin.php'). *) Click the “System Admin” button on the left side of the screen. *) Click on “Templates”. *) In the Template Set Manager, find the row with a check mark in the far right column. This row is the currently selected template set for your site. *) Click the “List” link to the right of “System” in the Templates column of the Template Set Manager for the currently selected template set (boy that's a mouth full!). *) On the resulting page find the “system_search.html” row that is highlighted in yellow and click on the “Generate” link. This will ensure that this particular template set has your new search template ready for use. Conclusion That's it. Your new search page should be up and running (although you might have to clear out your template cache folder if you're still seeing the old one). You may now customize the look and feel of your site's search page by updating the appropriate template whenever you like. If you think this has been helpful, then please lobby the Xoops folks to have changes like this added to the core for the next version of Xoops. Author : rlankford from this thread

This Q&A was found on XOOPS Web Application System : https://xoops.org/modules/smartfaq/faq.php?faqid=678