We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 8822
    • 203 Posts
    I have SimpleSearch setup to search certain pages on my website, including their TV content. Is there anyway of restricting which TVs are included in the search? I want some TVs searched, but not all of them - any ideas?
    • Doesn't look like it. As far as I can tell, it's a case of all or nothing.

      AdvSearch does allow a comma-separated list of TV names to include in the search.
        Studying MODX in the desert - http://sottwell.com
        Tips and Tricks from the MODX Forums and Slack Channels - http://modxcookbook.com
        Join the Slack Community - http://modx.org
        • 4172
        • 5,888 Posts
        not with the default-search-driver, but with this one it should:

        <?php
        
        /**
         * SimpleSearch
         *
         * Copyright 2010-11 by Shaun McCormick <[email protected]>
         *
         * This file is part of SimpleSearch, a simple search component for MODx
         * Revolution. It is loosely based off of AjaxSearch for MODx Evolution by
         * coroico/kylej, minus the ajax.
         *
         * SimpleSearch 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.
         *
         * SimpleSearch 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
         * SimpleSearch; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
         * Suite 330, Boston, MA 02111-1307 USA
         *
         * @package simplesearch
         */
        require_once dirname(__file__) . '/simplesearchdriver.class.php';
        /**
         * Standard sql-based search driver for SimpleSearch
         * 
         * @package simplesearch
         */
        class SimpleSearchDriverResourcesCustom extends SimpleSearchDriver {
            public $searchString;
        
            public function initialize() {
                return true;
            }
            public function index(array $fields) {
                return true;
            }
            public function removeIndex($id) {
                return true;
            }
        
            public function search($str, array $scriptProperties = array()) {
        
                if (!empty($str))
                    $this->searchString = strip_tags($this->modx->sanitizeString($str));
        
                $joins = $this->modx->fromJson($this->modx->getOption('joins', $scriptProperties, ''));
                $where = $this->modx->fromJson($this->modx->getOption('where', $scriptProperties, ''));
        
                $ids = $this->modx->getOption('ids', $scriptProperties, '');
                $exclude = $this->modx->getOption('exclude', $scriptProperties, '');
                $useAllWords = $this->modx->getOption('useAllWords', $scriptProperties, false);
                $searchStyle = $this->modx->getOption('searchStyle', $scriptProperties, 'partial');
                $hideMenu = $this->modx->getOption('hideMenu', $scriptProperties, 2);
                $maxWords = $this->modx->getOption('maxWords', $scriptProperties, 7);
                $andTerms = $this->modx->getOption('andTerms', $scriptProperties, true);
                $matchWildcard = $this->modx->getOption('matchWildcard', $scriptProperties, true);
                $docFields = explode(',', $this->modx->getOption('docFields', $scriptProperties, 'pagetitle,longtitle,alias,description,introtext,content'));
                $searchTvs = explode(',', $this->modx->getOption('searchTvs', $scriptProperties, ''));
                $searchTvs = count($searchTvs) > 0 ? $searchTvs : false;
                $debug = $this->modx->getOption('debug', $scriptProperties, false);
        
                $relevanceFields = explode(',', $this->modx->getOption('relevanceFields', $scriptProperties, ''));
        
                if ($searchTvs) {
                    $c = $this->modx->newQuery('modTemplateVar');
                    $c->where(array('name:IN' => $searchTvs));
                    if ($collection = $this->modx->getCollection('modTemplateVar', $c)) {
                        foreach ($collection as $object) {
                            $tv_ids[$object->get('name')] = $object->get('id');
                        }
                    }
                }
        
                $c = $this->modx->newQuery('modResource');
        
                if (!$searchTvs) {
                    $c->leftJoin('modTemplateVarResource', 'TemplateVarResources');
                }
        
        
                $classname = 'modResource';
        
                $c->select($this->modx->getSelectColumns($classname, $classname, ''));
        
        
                /* if using customPackages, add here */
                $customPackages = array();
                if (!empty($scriptProperties['customPackages'])) {
                    $packages = explode('||', $scriptProperties['customPackages']);
                    if (is_array($packages) && !empty($packages)) {
                        $searchArray = array(
                            '{core_path}',
                            '{assets_path}',
                            '{base_path}',
                            );
                        $replacePaths = array(
                            $this->modx->getOption('core_path', null, MODX_CORE_PATH),
                            $this->modx->getOption('assets_path', null, MODX_ASSETS_PATH),
                            $this->modx->getOption('base_path', null, MODX_BASE_PATH),
                            );
                        foreach ($packages as $package) {
                            /* 0: class name, 1: field name(s) (csl), 2: package name, 3: package path, 4: criteria */
                            $package = explode(':', $package);
                            if (!empty($package[4])) {
                                $package[3] = str_replace($searchArray, $replacePaths, $package[3]);
                                $this->modx->addPackage($package[2], $package[3]);
                                $c->leftJoin($package[0], $package[0], $package[4]);
                                $customPackages[] = $package;
                            }
                        }
                    }
                }
        
                /* process conditional clauses */
                $whereGroup = 1;
                if ($searchStyle == 'partial' || $this->modx->config['dbtype'] == 'sqlsrv') {
                    $wildcard = ($matchWildcard) ? '%' : '';
                    $whereArray = array();
                    if (empty($useAllWords)) {
                        $i = 1;
                        foreach ($this->search->searchArray as $term) {
                            if ($i > $maxWords)
                                break;
                            $term = $wildcard . $term . $wildcard;
                            foreach ($docFields as $field) {
                                $whereArray[] = array(
                                    $field . ':LIKE',
                                    $term,
                                    xPDOQuery::SQL_OR,
                                    $whereGroup);
                            }
                            if ($searchTvs) {
                                foreach ($searchTvs as $tv) {
                                    if (isset($tv_ids[$tv])) {
                                        $tv_id = $tv_ids[$tv];
                                        $alias = 'TV' . $tv;
                                        if ($i == 1) {
                                            $joins[] = array(
                                                'alias' => $alias,
                                                'classname' => 'modTemplateVarResource',
                                                'on' => $alias . '.contentid=modResource.id AND ' . $alias . '.tmplvarid=' . $tv_id);
                                        }
                                        $whereArray[] = array(
                                            $alias . '.value:LIKE',
                                            $term,
                                            xPDOQuery::SQL_OR,
                                            $whereGroup);
                                    }
                                }
                            } else {
                                $whereArray[] = array(
                                    'TemplateVarResources.value:LIKE',
                                    $term,
                                    xPDOQuery::SQL_OR,
                                    $whereGroup);
                            }
        
                            if (is_array($customPackages) && !empty($customPackages)) {
                                foreach ($customPackages as $package) {
                                    $fields = explode(',', $package[1]);
                                    foreach ($fields as $field) {
                                        $whereArray[] = array(
                                            $package[0] . '.' . $field . ':LIKE',
                                            $term,
                                            xPDOQuery::SQL_OR,
                                            $whereGroup);
                                    }
                                }
                            }
                            if ($andTerms)
                                $whereGroup++;
                            $i++;
                        }
                    } else {
                        $term = $wildcard . $this->searchString . $wildcard;
                        foreach ($docFields as $field) {
                            $whereArray[] = array(
                                $field . ':LIKE',
                                $term,
                                xPDOQuery::SQL_OR,
                                $whereGroup);
                        }
                        if ($searchTvs) {
                            foreach ($searchTvs as $tv) {
                                if (isset($tv_ids[$tv])) {
                                    $tv_id = $tv_ids[$tv];
                                    $alias = 'TV' . $tv;
                                    $joins[] = array(
                                        'alias' => $alias,
                                        'classname' => 'modTemplateVarResource',
                                        'on' => $alias . '.contentid=modResource.id AND ' . $alias . '.tmplvarid=' . $tv_id);
                                    $whereArray[] = array(
                                        $alias . '.value:LIKE',
                                        $term,
                                        xPDOQuery::SQL_OR,
                                        $whereGroup);
                                }
                            }
                        } else {
                            $whereArray[] = array(
                                'TemplateVarResources.value:LIKE',
                                $term,
                                xPDOQuery::SQL_OR,
                                $whereGroup);
                        }
                        if (is_array($customPackages) && !empty($customPackages)) {
                            foreach ($customPackages as $package) {
                                $fields = explode(',', $package[1]);
                                foreach ($fields as $field) {
                                    $whereArray[] = array(
                                        $package[0] . '.' . $field . ':LIKE',
                                        $term,
                                        xPDOQuery::SQL_OR,
                                        $whereGroup);
                                }
                            }
                        }
                    }
                    $prevWhereGrp = 0;
                    foreach ($whereArray as $clause) {
                        // The following works, but i consider it a hack, and should be fixed. -oori
                        $c->where(array($clause[0] => $clause[1]), $clause[2], null, $clause[3]);
                        if ($clause[3] > $prevWhereGrp)
                            $c->andCondition(array('AND:id:!=' => ''), null, $prevWhereGrp); // hack xpdo to prefix the whole thing with AND
                        $prevWhereGrp = $clause[3];
                        if ($andTerms)
                            $whereGroup++;
                    }
                    $c->andCondition(array('AND:id:!=' => ''), null, $whereGroup - 1); // xpdo hack: pad last condition...
        
                } else {
                    $fields = $this->modx->getSelectColumns('modResource', '', '', $docFields);
                    if (is_array($customPackages) && !empty($customPackages)) {
                        foreach ($customPackages as $package) {
                            $fields .= (!empty($fields) ? ',' : '') . $this->modx->getSelectColumns($package[0], $package[0], '', explode(',', $package[1]));
                            if (!empty($package[4])) {
                                $c->where($package[4]);
                            }
                        }
                    }
                    $wildcard = ($matchWildcard) ? '*' : '';
                    $relevancyTerms = array();
                    if (empty($useAllWords)) {
                        $i = 0;
                        foreach ($this->search->searchArray as $term) {
                            if ($i > $maxWords)
                                break;
                            $relevancyTerms[] = $this->modx->quote($term . $wildcard);
                            $i++;
                        }
                    } else {
                        $relevancyTerms[] = $this->modx->quote($str . $wildcard);
                    }
                    $this->addRelevancyCondition($c, array(
                        'class' => 'modResource',
                        'fields' => $fields,
                        'terms' => $relevancyTerms));
                }
                if (!empty($ids)) {
                    $idType = $this->modx->getOption('idType', $this->config, 'parents');
                    $depth = $this->modx->getOption('depth', $this->config, 10);
                    $ids = $this->processIds($ids, $idType, $depth);
                    $f = $this->modx->getSelectColumns('modResource', 'modResource', '', array('id'));
                    $c->where(array("{$f}:IN" => $ids), xPDOQuery::SQL_AND, null, $whereGroup);
                }
                if (!empty($exclude)) {
                    $exclude = $this->cleanIds($exclude);
                    $f = $this->modx->getSelectColumns('modResource', 'modResource', '', array('id'));
                    $c->where(array("{$f}:NOT IN" => explode(',', $exclude)), xPDOQuery::SQL_AND, null, 2);
                }
        
                $this->prepareJoins($classname, $joins, $c);
        
                $c->where(array('published:=' => 1), xPDOQuery::SQL_AND, null, $whereGroup);
                $c->where(array('searchable:=' => 1), xPDOQuery::SQL_AND, null, $whereGroup);
                $c->where(array('deleted:=' => 0), xPDOQuery::SQL_AND, null, $whereGroup);
        
                if (is_array($where) && count($where) > 0) {
                    $c->where($where, xPDOQuery::SQL_AND, null, $whereGroup);
                }
        
                /* restrict to either this context or specified contexts */
                $ctx = !empty($this->config['contexts']) ? $this->config['contexts'] : $this->modx->context->get('key');
                $f = $this->modx->getSelectColumns('modResource', 'modResource', '', array('context_key'));
                $c->where(array("{$f}:IN" => explode(',', $ctx)), xPDOQuery::SQL_AND, null, $whereGroup);
                if ($hideMenu != 2) {
                    $c->where(array('hidemenu' => $hideMenu == 1 ? true : false));
                }
                $total = $this->modx->getCount('modResource', $c);
                $c->query['distinct'] = 'DISTINCT';
        
                if (count($relevanceFields) > 0) {
                    foreach ($relevanceFields as $field) {
                        if (!empty($field)) {
                            $wildcard = '%';
                            $i = 1;
                            foreach ($this->search->searchArray as $term) {
                                if ($i > $maxWords)
                                    break;
                                $fieldalias = str_replace('.', '_', $field . '_' . $term . '_match');
                                $term = $wildcard . $term . $wildcard;
        
                                $c->select(array("IF({$field} LIKE '{$term}',1,0) as {$fieldalias}"));
                                $c->sortby($fieldalias, 'DESC');
                                $i++;
                            }
                        }
                    }
                }
        
                if (!empty($scriptProperties['sortBy'])) {
                    $sortDir = $this->modx->getOption('sortDir', $scriptProperties, 'DESC');
                    $sortDirs = explode(',', $sortDir);
                    $sortBys = explode(',', $scriptProperties['sortBy']);
                    $dir = 'desc';
                    for ($i = 0; $i < count($sortBys); $i++) {
                        if (isset($sortDirs[$i])) {
                            $dir = $sortDirs[$i];
                        }
                        $c->sortby('modResource.' . $sortBys[$i], strtoupper($dir));
                    }
                }
        
                /* set limit */
                $perPage = $this->modx->getOption('perPage', $this->config, 10);
                if (!empty($perPage)) {
                    $offset = $this->modx->getOption('start', $this->config, 0);
                    $offsetIndex = $this->modx->getOption('offsetIndex', $this->config, 'sisea_offset');
                    if (isset($_REQUEST[$offsetIndex]))
                        $offset = (int)$_REQUEST[$offsetIndex];
                    $c->limit($perPage, $offset);
                }
        
                if ($debug) {
                    $c->prepare();
                    echo $c->toSql();
                    //die();
                }
        
        
                $resources = $this->modx->getCollection('modResource', $c);
                /*
                if (empty($scriptProperties['sortBy'])) {
                $resources = $this->sortResults($resources, $scriptProperties);
                }
                */
                $includeTVs = $this->modx->getOption('includeTVs', $scriptProperties, '');
                $processTVs = $this->modx->getOption('processTVs', $scriptProperties, '');
                $list = array();
                /**
                 *  *  *  *  *  *  * @var modResource $resource */
                foreach ($resources as $resource) {
                    if (!$resource->checkPolicy('list'))
                        continue;
                    $resourceArray = $resource->toArray();
        
                    if (!empty($includeTVs)) {
                        $templateVars = &$resource->getMany('TemplateVars');
                        /**
                         *  *  *  *  *  *  * @var modTemplateVar $templateVar */
                        foreach ($templateVars as $tvId => $templateVar) {
                            $resourceArray[$templateVar->get('name')] = !empty($processTVs) ? $templateVar->renderOutput($resource->get('id')) : $templateVar->get('value');
                        }
                    }
                    $list[] = $resourceArray;
                }
        
                //print_r($list);
        
                return array(
                    'total' => $total,
                    'results' => $list,
                    );
            }
        
            /**
             * add relevancy search criteria to query
             *
             * @param xPDOQuery $query
             * @param array $options
             * @param string $options['class'] class name (not currently used but may be needed with custom classes)
             * @param string $options['fields'] query-ready list of fields to search for the terms
             * @param array $options['terms'] search terms (will only be one array member if useAllWords parameter is set)
             * @return boolean
             */
            public function addRelevancyCondition(&$query, $options) {
                $class = $this->modx->getOption('class', $options, 'modResource');
                $fields = $this->modx->getOption('fields', $options, '');
                $terms = $this->modx->getOption('terms', $options, array());
                if (!empty($fields)) {
                    foreach ($terms as $term) {
                        $query->where("MATCH ( {$fields} ) AGAINST ( {$term} IN BOOLEAN MODE )");
                    }
                }
                return true;
            }
        
        
            public function prepareJoins($classname, $joins, &$c, $forcounting = false) {
                global $modx;
        
                if (is_array($joins)) {
                    foreach ($joins as $join) {
                        $jalias = $modx->getOption('alias', $join, '');
                        $joinclass = $modx->getOption('classname', $join, '');
                        $on = $modx->getOption('on', $join, null);
                        if (!empty($jalias)) {
                            if (empty($joinclass) && $fkMeta = $modx->getFKDefinition($classname, $jalias)) {
                                $joinclass = $fkMeta['class'];
                            }
                            if (!empty($joinclass)) {
                                $selectfields = $modx->getOption('selectfields', $join, '');
        
                                /*
                                if ($joinFkMeta = $modx->getFKDefinition($joinclass, 'Resource')){
                                $localkey = $joinFkMeta['local'];
                                }
                                */
                                $c->leftjoin($joinclass, $jalias, $on);
                                $selectfields = !empty($selectfields) ? explode(',', $selectfields) : null;
                                if ($forcounting) {
        
                                } else {
                                    $c->select($modx->getSelectColumns($joinclass, $jalias, $jalias . '_', $selectfields));
                                }
                            }
                        }
                    }
                }
            }
        
        }
        
        


        put this file to: components/simplesearch/model/simplesearch/driver/simplesearchdriverresourcescustom.class.php

        and try something like that:

        [[!SimpleSearch?
        &where=`{"parent":"75"}`
        &sisea.driver_class=`simplesearchdriverresourcescustom`
        &sisea.driver_db_specific=`0`
        &searchTvs = `migxtagmanager_tags,image,tsRegion`
        ]]
        [ed. note: Bruno17 last edited this post 10 years, 3 months ago.]
          -------------------------------

          you can buy me a beer, if you like MIGX

          http://webcmsolutions.de/migx.html

          Thanks!
          • 8822
          • 203 Posts
          Hey Wow, thanks Bruno17, i will try that and let you know how i get on.
          Am i right in assuming that in your example 'migxtagmanager_tags,image,tsRegion' etc. are the names of the TVs that the search should search?
            • 4172
            • 5,888 Posts
            Quote from: Emily at Nov 26, 2013, 08:32 PM

            Am i right in assuming that in your example 'migxtagmanager_tags,image,tsRegion' etc. are the names of the TVs that the search should search?

            right, this are the names of TVs to search on.

            with that driver, you can give some fields more relevance, and let simplesearch order the results by relevance-fields

            example for pushing results with the search-term in pagetitle to top and next with results in a TV named 'migxtagmanager_tags':

            [[!SimpleSearch?
            &where=`{"parent":"75"}`
            &sisea.driver_class=`simplesearchdriverresourcescustom`
            &sisea.driver_db_specific=`0`
            &searchTvs = `image,tsRegion,migxtagmanager_tags`
            &relevanceFields = `pagetitle,TVmigxtagmanager_tags.value`
            ]]


            additional you can do joins to other tables and extend the search to fields in related tables.
              -------------------------------

              you can buy me a beer, if you like MIGX

              http://webcmsolutions.de/migx.html

              Thanks!
              • 8822
              • 203 Posts
              Great, can't wait to try it out.
              Will it work with getPage do you know?
                • 4172
                • 5,888 Posts
                simpleSearch has its own pagination, no need to use getPage here
                  -------------------------------

                  you can buy me a beer, if you like MIGX

                  http://webcmsolutions.de/migx.html

                  Thanks!
                  • 8822
                  • 203 Posts
                  Ok thanks.

                  I have setup some test pages and am using the following in my call:

                  [[!SimpleSearch?
                  &where=`{"parent":"3"}`
                  &limit=`10`
                  &pageVarKey=`page`
                  &useAllWords=`1`
                  &sisea.driver_class=`simplesearchdriverresourcescustom`
                  &sisea.driver_db_specific=`0`
                  &searchTvs = `businessname`
                  &sortBy=`link_attributes`
                  &sortDir=`DESC`
                  &tpl=`fbnsearchresultstpl`
                  ]]


                  I have created the simplesearchdriverresourcescustom.class.php file in components/simplesearch/model/simplesearch/driver (and assets/components/simplesearch/model/simplesearch/driver just incase that was the issue).

                  When i use the search though the page is displayed completely blank. Removing the &sisea line items fixes the issue (though obviously with no TV content displayed in the search results)

                  Any thoughts?
                    • 4172
                    • 5,888 Posts
                    the file needs to be in

                    core/components/simplesearch/model/simplesearch/driver/
                      -------------------------------

                      you can buy me a beer, if you like MIGX

                      http://webcmsolutions.de/migx.html

                      Thanks!
                      • 8822
                      • 203 Posts
                      aaaah, yes, that does it!

                      i am using the following call though and never get any search results back, even when using words that are definately in TVs for certain resources:

                      [[!SimpleSearch?
                      &where=`{"parent":"3"}`
                      &depth=`2`
                      &sisea.driver_class=`simplesearchdriverresourcescustom`
                      &sisea.driver_db_specific=`0`
                      &searchTvs = `metaKeywords,businessname,businessaddress1,businesscounty,businesstown,businessemail,categories`
                      &limit=`10`
                      &pageVarKey=`page`
                      &useAllWords=`1`
                      &sortBy=`link_attributes`
                      &sortDir=`DESC`
                      &tpl=`fbnsearchresultstpl`
                      ]]


                      Do you spot anything obviously wrong?