From ec4303901e1ae857fc28eedbaf5f2639d2219775 Mon Sep 17 00:00:00 2001 From: Chuck Scott Date: Fri, 24 Jun 2016 15:59:02 -0400 Subject: [PATCH] Alpha version of new Search add-on for GLM Associate. Ready for initial integration. --- classes/data/dataManagement.php | 158 +++++ classes/glmSearch.php | 598 ++++++++++++++++++ css/front.css | 43 ++ index.php | 9 +- models/admin/management/search.php | 161 +++++ models/front/search/index.php | 160 +++++ setup/adminTabs.php | 15 + .../create_database_V0.0.1.sql | 27 + setup/databaseScripts/dbVersions.php | 19 + setup/shortcodes.php | 63 +- setup/validActions.php | 16 +- views/admin/management/search.html | 60 ++ views/front/footer.html | 10 + views/front/search/Sitemap_XML_0.9.html | 12 + views/front/search/header.html | 3 + views/front/search/index.html | 104 +++ 16 files changed, 1449 insertions(+), 9 deletions(-) create mode 100644 classes/data/dataManagement.php create mode 100644 classes/glmSearch.php create mode 100644 css/front.css create mode 100644 models/admin/management/search.php create mode 100644 models/front/search/index.php create mode 100644 setup/databaseScripts/create_database_V0.0.1.sql create mode 100644 setup/databaseScripts/dbVersions.php create mode 100644 views/admin/management/search.html create mode 100644 views/front/footer.html create mode 100644 views/front/search/Sitemap_XML_0.9.html create mode 100644 views/front/search/header.html create mode 100644 views/front/search/index.html diff --git a/classes/data/dataManagement.php b/classes/data/dataManagement.php new file mode 100644 index 0000000..654c72f --- /dev/null +++ b/classes/data/dataManagement.php @@ -0,0 +1,158 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataSearchManagement.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + */ + +/** + * GlmDataManagementSearch class + * + * PHP version 5 + * + * @category Data + * @package GLM Member DB + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: dataSearchManagement.php,v 1.0 2011/01/25 19:31:47 cscott + * Exp $ + */ +class GlmDataSearchManagement extends GlmDataAbstract +{ + + /** + * WordPress Database Object + * + * @var $wpdb + * @access public + */ + public $wpdb; + /** + * Plugin Configuration Data + * + * @var $config + * @access public + */ + public $config; + /** + * Data Table Name + * + * @var $table + * @access public + */ + public $table; + /** + * Field definitions + * + * 'type' is type of field as defined by the application + * text Regular text field + * pointer Pointer to an entry in another table + * 'filters' is the filter name for a particular filter ID in PHP filter + * functions + * See PHP filter_id() + * + * 'use' is when to use the field + * l = List + * g = Get + * n = New + * i = Insert + * e = Edit + * u = Update + * d = Delete + * a = All + * + * @var $ini + * @access public + */ + public $fields = false; + + /** + * Constructor + * + * @param object $d database connection + * @param array $config Configuration array + * @param bool $limitedEdit Flag to say indicate limited edit requested + * + * @return void + * @access public + */ + public function __construct($wpdb, $config, $limitedEdit = false) + { + + // If this class is not being extended along with existing $wpdb and $config + if (!$this->wpdb) { + + // Save WordPress Database object + $this->wpdb = $wpdb; + + // Save plugin configuration object + $this->config = $config; + + } + + /* + * Table Name + */ + $this->table = GLM_MEMBERS_SEARCH_PLUGIN_DB_PREFIX . 'management'; + + /* + * Table Data Fields + */ + + $this->fields = array ( + + 'id' => array ( + 'field' => 'id', + 'type' => 'integer', + 'view_only' => true, + 'use' => 'a' + ), + + // OSS Search Index + 'search_index' => array ( + 'field' => 'search_index', + 'type' => 'text', + 'required' => true, + 'use' => 'a' + ), + + // OSS Search Website + 'website' => array ( + 'field' => 'website', + 'type' => 'text', + 'required' => true, + 'use' => 'a' + ), + + // OSS Search Login + 'login' => array ( + 'field' => 'login', + 'type' => 'text', + 'required' => true, + 'use' => 'a' + ), + + // OSS Search Login Key + 'login_key' => array ( + 'field' => 'login_key', + 'type' => 'text', + 'required' => true, + 'use' => 'a' + ) + + + ); + + } + + +} + +?> \ No newline at end of file diff --git a/classes/glmSearch.php b/classes/glmSearch.php new file mode 100644 index 0000000..e609c69 --- /dev/null +++ b/classes/glmSearch.php @@ -0,0 +1,598 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: glmSearch.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link + */ + +/**** NOTE : THIS FILE HAS NOT HAD A THOUROUGH REVIEW SINCE BEING GRABBED FROM THE OLD GLM COMMON APPS *****/ + +/* + * Set OpenSearchServer base URL and port + */ +define('OpenSearchServer', 'http://oss.gaslightmedia.com:9090'); + +/** + * GLM Search - Web Site Search Support Class + * + * PHP version 5 + * + * @category Support_Services + * @package EventManagement + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: GeoCalculations.php,v 1.0 2011/01/25 19:31:47 cscott Exp $ + * @link http://housing.gaslightmedia.com/admin/ + */ +class GLMSearch +{ + + /** + * Name of the index an instance of this class will search. + * An index can have multiple Websites in it. If when calling + * the constructor no $index is specified, the code will assume + * that the index name and website name are the same. Otherwise + * it will use $index as the index name. + * + * @var $index + * @access private + */ + private $index; + /** + * Name of the Web site an instance of this class will work on + * + * @var $website + * @access private + */ + private $website; + /** + * Authentication paramters for all requests + * + * @var $auth + * @access private + */ + private $auth; + /** + * General error message describing any failure + * + * @var $curlError + * @access public + */ + public $errorMessage; + /** + * Exception object caused by curl or other failure + * + * @var $error + * @access public + */ + public $error; + /** + * Request array + * + * This should be the most common request configuration + * we'll be using for our Web sites. It's public so it + * can be easily customized for a particular Web site + * once the class has been instantiated. + * + * See clearResults() method for default data + * + * @var $request Array of request information + * @access public + */ + public $request = false; + /** + * Search type + * + * This selects whether a search will be a 'field' search or 'pattern' search + * + * @var $type String Either 'field' or 'pattern' + * @access private + */ + private $type = 'field'; + /** + * Curl instance + * + * @var $curl + * @access private + */ + private $curl = false; + /** + * HTTP Status from curl + * + * @var $httpStatus + * @access public + */ + public $httpStatus = false; + /** + * HTTP Header from curl + * + * @var $httpHeader + * @access public + */ + public $httpHeader = false; + /** + * Raw Result of curl request + * + * Public so it can easily be examined + * + * @var $rawResult + * @access public + */ + public $rawResults = false; + /** + * Full results as an array + * + * @var $resultArray + * @access private + */ + private $resultArray = false; + /** + * Compressed results array + * + * This array has better processed data for output + * and has trimmed levels for document data for + * easier use. + * + * @var $result + * @access private + */ + private $result = false; + /** + * Host Filter flag + * + * @var $filter + * @access public + */ + public $filter = true; + /** + * Host Filter Type + * + * @var $filterType + * @access public + */ + public $filterType = false; + /** + * Host Filter Value + * + * @var $filterValue + * @access public + */ + public $filterValue = false; + + /** + * Constructor + * + * @param text $index Optional index name if Web site is part of a larger index + * @param string $website Name of the Web site + * @param string $login Login to OpenSearchServer + * @param string $key Key for login + * @param text $filterType Optional filter type (when $this->filter is true). + * Filter types are "title", "titleExact", "titlePhonetic", "content", + * "contentExact", "contactPhonetic", "urlSplit", "urlExact", "urlPhonetic", + * "full", "fullExact", "fullPhonetic" + * @param text $filterValue Filter value to use with $filterType. + * + * @return void + * @access public + */ + public function __construct($index, $website, $login, $key, $filterType = false, $filterValue = false) + { + + // If there's a problem with Filter and validate supplied parameters + if ( + ($website = filter_var($website, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH)) == false || + ($login = filter_var($login, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH)) == false || + ($key = filter_var($key, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH)) == false + ) { + return false; + } + + // Store supplied parameters + $this->index = $index; + $this->website = $website; + + // Build authentication parameters for submissions + $this->auth = "login=$login&key=$key"; + + // Create curl instance - and set to return response + $this->curl = curl_init(); + curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, TRUE); + + } + + /** + * Perform a search on the Web site + * + * @param string $query The user's search string + * @param string $operator Operator for the query terms (AND, OR) + * Default = 'OR' + * @param integer $start Starting result number + * Default = 0 (first page) + * @param integer $rows Number of rows per result page + * Default = 10 + * + * @return string JSON of results or false if a failure + * + * @access public + */ + public function glmSearch($query, $operator = 'OR', $start = 0, $rows = 10) + { + + // Clear all the results data + $this->clearResults(); + + // Filter and validate supplied parameters + if ( + (filter_var($query, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH)) == false || + (in_array($operator, array('OR', 'AND'))) == false + ) { + return false; + } + + // strip any characters that cause a problem. Add more characters to array if needed. + $remove = array("'"); + $query = htmlspecialchars_decode($query, ENT_QUOTES); + $query = str_replace("'", "", $query); + + $start = ($start - 0); + $rows = ($rows - 0); + + + // Check if we have a valid query + if (trim($query) == '') { + return false; + } + + // Create request URL + switch ($this->type) { + case 'field': + $url = OpenSearchServer.'/services/rest/index/'.$this->index.'/search/field/?'.$this->auth; + break; + case 'pattern': + $url = OpenSearchServer.'/services/rest/index/'.$this->index.'/search/pattern/?'.$this->auth; + break; + } + + // Update query and operator in request + $this->request['query'] = $query; + $this->request['start'] = $start; + $this->request['rows'] = $rows; + $this->request['operator'] = $operator; + + // If host filter has not been turned off, set filter to only search the specified Website in the index + if ($this->filter) { + + // Determine if there's a specific filter type and value - Default to host: + $query = 'host:"'.$this->website.'"'; + if ($this->filterType) { + if ($this->filterValue) { + $query = $this->filterType.':"'.$this->filterValue.'"'; + } else { + $query = $this->filterType.':"'.$this->website.'"'; + } + } + + // Set filter + $this->request['filters'] = array( + array( + "type" => "QueryFilter", + "negative" => false, + "query" => $query + ) + ); + + } else { + unset($this->request['filters']); + } + + // Set curl options + curl_setopt_array($this->curl, array( + CURLOPT_URL => $url, + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => json_encode($this->request), + CURLOPT_HTTPHEADER => array("Content-type: application/json; charset=utf-8"), + CURLOPT_VERBOSE => 1, + CURLOPT_HEADER => 1 + )); + + // Do curl call and get result; + try { + $res = curl_exec($this->curl); + } catch (Exception $e) { + return false; + } + + // Parse out results elements + $this->httpStatus = curl_getinfo($this->curl, CURLINFO_HTTP_CODE); + $header_size = curl_getinfo($this->curl, CURLINFO_HEADER_SIZE); + $this->httpHeader = substr($res, 0, $header_size); + $this->rawResults = substr($res, $header_size); + + // Check HTTP status code + if ($this->httpStatus != 200) { + return false; + } + + $this->resultArray = json_decode($this->rawResults, true); + + $res = $this->compressResults(); + + return $res; + } + + /** + * Compress search results as associative array into + * more succinct result array for use with output template. + * + * @param $res Uncompressed search results array + * + * @return array Array of results or false if a failure + * + * @access public + */ + public function compressResults() + { + + // Check if we don't have valid input + if (!is_array($this->resultArray) || !$this->resultArray['successful']) { + return false; + } + + // Calculate certain paging values + $rowsPerPage = $this->resultArray['rows']; + $thisPageStartIndex = $this->resultArray['start']; // Based on first result being 0 + $thisPageStart = $thisPageStartIndex + 1; // Displayed first result number + $numbResults = $this->resultArray['numFound']; + $numbResultsOnPage = count($this->resultArray['documents']); + $lastResultOnPage = $thisPageStart + $numbResultsOnPage - 1; + $previousPageStartIndex = $thisPageStartIndex - $rowsPerPage; + if ($previousPageStartIndex < 0) { + $previousPageStartIndex = false; + } + $nextPageStartIndex = $thisPageStartIndex + $rowsPerPage; + if ($nextPageStartIndex > ($numbResults - 1)) { + $nextPageStartIndex = false; + } + + // Build basic search results array + $this->result = array( + 'resultsPerPage' => $this->resultArray['rows'], + 'operator' => $this->request['operator'], + 'totalResults' => $numbResults, + 'firstResultOnPage' => $thisPageStart, + 'resultsOnPage' => $numbResultsOnPage, + 'lastResultOnPage' => $lastResultOnPage, + 'previousPageStartIndex' => $previousPageStartIndex, + 'nextPageStartIndex' => $nextPageStartIndex, + 'documents' => array() + ); + + // Add in results for each document + foreach ($this->resultArray['documents'] as $d) { + + // Base document information + $doc = array( + 'score' => $d['score'], + 'collapseCount' => $d['collapseCount'] + ); + + // Document fields (simple text fields) + foreach ($d['fields'] as $df) { + $doc[$df['fieldName']] = array( + 'type' => 'field', + 'name' => $df['fieldName'], + 'value' => (isset($df['values'][0]) ? $df['values'][0] : '') + ); + + } + + // Document snippets (possible multiple snippets per each) + foreach ($d['snippets'] as $ds) { + $doc[$ds['fieldName']] = array( + 'type' => 'snippets', + 'name' => $ds['fieldName'], + 'snippets' => array() + ); + + // Process possible multiple snippet values + if (is_array($ds['values']) && count($ds['values']) > 0) { + foreach ($ds['values'] as $sv) { + $doc[$ds['fieldName']]['snippets'][] = $sv; + } + } + + } + + // Need to add processing of "functions" also here + + // Look for null or blank title + if (empty($doc['title']['value']) && !empty($doc['url']['value'])) { + $doc['title']['value'] = $doc['url']['value']; + } + + // Clean up lastModifiedDate if included + if (isset($doc['lastModifiedDate']) && isset($doc['lastModifiedDate']['value'])) { + $d = $doc['lastModifiedDate']['value']; + $doc['lastModifiedDate']['textValue'] = ''; + if (trim($d) != '') { + $doc['lastModifiedDate']['textValue'] = substr($d, 0, 4).'-'.substr($d,4,2).'-'.substr($d,6,2); + } + } + + // Add this document to result documents array + $this->result['documents'][] = $doc; + + } + + return $this->result; + } + + /** + * Create an XML Sitemap from search results + * + * @param string $template Template to use for producing results (override default) + * @param array $request Array of request parameters + * 'query' Required - Search String + * 'matchAll' Optional - Match all words option ('AND', 'OR') + * 'start' Optional - Start index + * 'rows' Optional - Results per page + * + * @return void + * @access public + */ + public function xmlSitemap($templateName = 'Sitemap_XML_0.9.html') + { + + // Search for * (matches everything) + $request = array( + 'query' => 'a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9', + 'matchAll' => 'OR', + 'start' => 0, + 'rows' => 50000 + ); + $page = $this->doSearch($templateName, GLMSearch_TEMPLATE_PATH, $request); + return $page; + } + + /** + * Tell OpenSearchServer to crawl a particular URL pattern + * + * @param integer $pattern URL Pattern + * + * @return array Object Results from Search Engine or false if failure. + * + * @access public + */ + public function crawlURL($pattern) + { + + // Clear all the results data + $this->clearResults(); + + // Filter and validate supplied parameters + if (($pattern = filter_var($pattern, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH)) == false) { + return false; + } + + // Create request URL + $param = 'url='.$pattern; + $url = OpenSearchServer.'/services/rest/index/'.$this->index.'/crawler/web/crawl?'.$this->auth.'&'.$param; + + // Set curl options + curl_setopt_array($this->curl, array( + CURLOPT_URL => $url, + CURLOPT_POST => false, + CURLOPT_VERBOSE => 1, + CURLOPT_HEADER => 1 + )); + + // Do curl call and get result; + try { + $res = curl_exec($this->curl); + } catch (Exception $e) { + return false; + } + + // Parse out results elements + $this->httpStatus = curl_getinfo($this->curl, CURLINFO_HTTP_CODE); + $header_size = curl_getinfo($this->curl, CURLINFO_HEADER_SIZE); + $this->httpHeader = substr($res, 0, $header_size); + $this->rawResults = substr($res, $header_size); + + // Check HTTP status code + if ($this->httpStatus != 200) { + return false; + } + + // Debug information + $this->errorMessage = 'crawlURL() - Completed successfully.'; + + return json_decode($this->rawResults); + } + + /** + * Clear all request and results data - used before a new curl call + * + * @return void + * @access private + */ + private function clearResults() + { + + /* + * Reset request to default + * (Note: Need to add more explanation for this data.) + */ + $this->request = array( + 'query' => false, // Query String + 'start' => 0, // Result number for start of page + 'rows' => 10, // Number of rows to display per page + 'lang' => 'ENGLISH', // Language (in all caps) + 'operator' => 'AND', // Either AND or OR - And matches pages containing all words + 'collapsing' => array( + 'max' => 2, + 'mode' => 'OFF', + 'type' => 'OPTIMIZED' + ), + 'geo' => null, + 'filters' => null, + 'sorts' => null, + 'returnedFields' => array( + 'url', + 'title', + 'lastModifiedDate' + ), + 'snippets' => array( + array( + 'field' => 'content', + 'tag' => 'b', + 'separator' => '...', + 'maxSize' => 300, + 'maxNumber' => 1, + 'fragmenter' => 'SENTENCE' + ) + ), + 'facets' => null, + 'joins' => null, + 'enableLog' => null, + 'customLogs' => null, + 'searchFields' => array( + array( + 'field' => 'title', + 'boost'=> 10 + ), + array( + 'field' => 'content', + 'boost'=> 1 + ), + array( + 'field' => 'titleExact', + 'boost'=> 10 + ), + array( + 'field' => 'contentExact', + 'boost'=> 1 + ) + ) + ); + // Clear results + $this->httpStatus = false; + $this->httpHeader = false; + $this->rawResults = false; + $this->resultArray = false; + $this->result = false; + $this->errorMessage = false; + $this->error = false; + + } + +} + +?> diff --git a/css/front.css b/css/front.css new file mode 100644 index 0000000..996ef06 --- /dev/null +++ b/css/front.css @@ -0,0 +1,43 @@ +/* Search Results Styling */ +#GLMSearch { + padding: 1em; +} +#GLMSformContainer {} +#GLMSformContainer input {} +.GLMSresultsHeader { + margin-top: 1em; + margin-bottom: 2em; +} +.GLMSresultsSummary {} +.GLMSresultsNavContainer {} +.GLMSresultsNavContainer a {} +.GLMSresultsNavInactive { + color: lightgray; +} +#GLMSresultsContainer { +} +.GLMSresultContainer { + color: #1E130A; + font-family: Arial,Helvetica,sans-serif; + font-size: 1em; + margin-bottom: 2em; +} +.GLMSresultTitle { + color: #0000CC; + text-decoration: underline; + font-weight: bold; + margin-bottom: .3em; +} +.GLMSresultText {} +.GLMSresultSnippets {} +.GLMSresultSnippets b { + border: solid lightgray 1px; + padding: .1em; +} +.GLMSresultUrl { + color: #008000; + margin-top: .2em; +} +#slideshow { + display: none; +} diff --git a/index.php b/index.php index 4c74af5..8f639bd 100644 --- a/index.php +++ b/index.php @@ -4,7 +4,7 @@ * Plugin URI: http://www.gaslightmedia.com/ * Description: Gaslight Media Members Database. * Version: 0.0.1 - * Author: Chuck Scott + * Author: Gaslight Media * Author URI: http://www.gaslightmedia.com/ * License: GPL2 */ @@ -38,7 +38,7 @@ * version from this plugin. */ define('GLM_MEMBERS_SEARCH_PLUGIN_VERSION', '0.0.1'); -// define('GLM_MEMBERS_SEARCH_PLUGIN_DB_VERSION', '0.0.1'); +define('GLM_MEMBERS_SEARCH_PLUGIN_DB_VERSION', '0.0.1'); // This is the minimum version of the GLM Members DB plugin require for this plugin. define('GLM_MEMBERS_SEARCH_PLUGIN_MIN_MEMBERS_REQUIRED_VERSION', '1.0.57'); @@ -143,12 +143,10 @@ if (is_file(GLM_MEMBERS_SEARCH_PLUGIN_DB_SCRIPTS.'/dbVersions.php')) { } // Load Search Management Settings data -/* None - Need to figure out a smooth way to do this. $searchManagementSettings = $wpdb->get_row( "SELECT * FROM ".GLM_MEMBERS_SEARCH_PLUGIN_DB_PREFIX."management WHERE id = 1", ARRAY_A ); unset($searchManagementSettings['id']); -*/ -function glmMembersRegisterSsearch($addOns) { +function glmMembersRegisterSearch($addOns) { // Add this add-on to the add-ons array $addOns[GLM_MEMBERS_SEARCH_PLUGIN_SLUG] = array( @@ -158,6 +156,7 @@ function glmMembersRegisterSsearch($addOns) { 'slug' => GLM_MEMBERS_SEARCH_PLUGIN_SLUG, 'actions' => $GLOBALS['glmMembersSearchAddOnValidActions'], 'config' => array( + 'settings' => $GLOBALS['searchManagementSettings'] ), 'shortcodes' => $GLOBALS['glmMembersSearchShortcodes'], 'shortcodesDescription' => $GLOBALS['glmMembersSearchShortcodesDescription'] diff --git a/models/admin/management/search.php b/models/admin/management/search.php new file mode 100644 index 0000000..9e7f066 --- /dev/null +++ b/models/admin/management/search.php @@ -0,0 +1,161 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release search.php,v 1.0 2014/10/31 19:31:47 cscott Exp $ + * @link http://dev.gaslightmedia.com/ + */ + +// Load Management Search data abstract +require_once(GLM_MEMBERS_SEARCH_PLUGIN_CLASS_PATH.'/data/dataManagement.php'); + +/** + * GlmMembersAdmin_management_search + * + * PHP version 5 + * + * @category Model + * @package GLM Member DB + * @author Chuck Scott + * @license http://www.gaslightmedia.com Gaslightmedia + * @release SVN: $Id: search.php,v 1.0 2011/01/25 19:31:47 cscott + * Exp $ + */ +class GlmMembersAdmin_management_search extends GlmDataSearchManagement +{ + + /** + * WordPress Database Object + * + * @var $wpdb + * @access public + */ + public $wpdb; + + /* + * Constructor + * + * This contructor performs the work for this model. This model returns + * an array containing the following. + * + * 'status' + * + * True if successfull and false if there was a fatal failure. + * + * 'view' + * + * A suggested view name that the contoller should use instead of the + * default view for this model or false to indicate that the default view + * should be used. + * + * 'data' + * + * Data that the model is returning for use in merging with the view to + * produce output. + * + * @wpdb object WordPress database object + * + * @return array Array containing status, suggested view, and any data + */ + public function __construct ($wpdb, $config) + { + + // Save WordPress Database object + $this->wpdb = $wpdb; + + // Save plugin configuration object + $this->config = $config; + + // Run constructor for members data class + parent::__construct(false, false); + + } + + public function modelAction($actionData = false) + { + $searchSettigns = false; + $settingsUpdated = false; + $settingsUpdateError = false; + + + // Determine if current user can edit configurations + if (!current_user_can('glm_members_management')) { + return array( + 'status' => false, + 'menuItemRedirect' => 'error', + 'modelRedirect' => 'index', + 'view' => 'admin/error/index.html', + 'data' => array( + 'reason' => 'User does not have rights to make configuration changes.' + ) + ); + } + + // Check for submission option + $option = ''; + if (isset($_REQUEST['option']) && $_REQUEST['option'] == 'submit') { + $option = $_REQUEST['option']; + } + + switch($option) { + + // Update the settings and redisplay the form + case 'submit': + + // Update the search management settings + $searchSettings = $this->updateEntry(1); + if ($searchSettings['status']) { + $settingsUpdated = true; + } else { + $settingsUpdateError = true; + } + + break; + + // Default is to get the current settings and display the form + default: + + // Try to get the first (should be only) entry for general settings. + $searchSettings = $this->editEntry(1); + + if ($searchSettings === false) { + + if (GLM_MEMBERS_PLUGIN_ADMIN_DEBUG) { + glmMembersAdmin::addNotice("  /models/admin/management/search.php: Unable to load search management settings.", 'Alert'); + } + + } + + break; + + } + + // Compile template data + $templateData = array( + 'reason' => '', + 'searchSettings' => $searchSettings, + 'settingsUpdated' => $settingsUpdated, + 'settingsUpdateError' => $settingsUpdateError + ); + + // Return status, suggested view, and data to controller + return array( + 'status' => true, + 'menuItemRedirect' => false, + 'modelRedirect' => false, + 'view' => 'admin/management/search.html', + 'data' => $templateData + ); + + + } +} + +?> \ No newline at end of file diff --git a/models/front/search/index.php b/models/front/search/index.php new file mode 100644 index 0000000..d27edd5 --- /dev/null +++ b/models/front/search/index.php @@ -0,0 +1,160 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @version 0.1 + */ + +// Load GLM Search class +require_once(GLM_MEMBERS_SEARCH_PLUGIN_CLASS_PATH.'/glmSearch.php'); + +/* + * Perform searches using the Gaslight Media Open Search Server + * and display results + */ +class GlmMembersFront_search_index extends GLMSearch +{ + + /** + * WordPress Database Object + * + * @var $wpdb + * @access public + */ + public $wpdb; + /** + * Plugin Configuration Data + * + * @var $config + * @access public + */ + public $config; + + /* + * Constructor + * + * This contructor sets up this model. At this time that only includes + * storing away the WordPress data object. + * + * @return object Class object + * + */ + public function __construct ($wpdb, $config) + { + + // Save WordPress Database object + $this->wpdb = $wpdb; + + // Save plugin configuration object + $this->config = $config; + + // Get the Open Search Server parameters from management settings + $index = $this->config['settings']['search_index']; + $website = $this->config['settings']['website']; + $login = $this->config['settings']['login']; + $key = $this->config['settings']['login_key']; + + // Run constructor for members data class + parent::__construct($index, $website, $login, $key); + + } + + /* + * Perform Model Action + * + * This method does the work for this model and returns any resulting data + * + * @return array Status and data array + * + * 'status' + * + * True if successfull and false if there was a fatal failure. + * + * 'menuItemRedirect' + * + * If not false, provides a menu item the controller should + * execute after this one. Normally if this is used, there would also be a + * modelRedirect value supplied as well. + * + * 'modelRedirect' + * + * If not false, provides an action the controller should execute after + * this one. + * + * 'view' + * + * A suggested view name that the contoller should use instead of the + * default view for this model or false to indicate that the default view + * should be used. + * + * 'data' + * + * Data that the model is returning for use in merging with the view to + * produce output. + * + */ + public function modelAction ($actionData = false) + { + + $haveSearchResult = false; + $status = true; + $query = false; + $searchResult = array( + 'operator' => 'AND' + ); + + + /* + * Get input from form + */ + if (isset($_REQUEST['query'])) { + + $query = $_REQUEST['query']; + $operator = 'OR'; + if (isset($_REQUEST['matchAll']) && $_REQUEST['matchAll'] == 'on') { + $operator = 'AND'; + } + + $start = $_REQUEST['start']; + $rows = $_REQUEST['rows']; + + if (trim($query) != '') { + $searchResult = $this->glmSearch($query, $operator, $start, $rows); + if (is_array($searchResult) && isset($searchResult['totalResults']) && $searchResult['totalResults'] > 0 ) { + $haveSearchResult = true; + } + } + + } + + // Compile template data + $templateData = array( + 'haveSearchResult' => $haveSearchResult, + 'searchResult' => $searchResult, + 'query' => $query + ); + + $view = 'index.html'; + + // Return status, suggested view, and data to controller - also return any modified settings + return array( + 'status' => $status, + 'menuItemRedirect' => false, + 'modelRedirect' => false, + 'view' => 'front/search/'.$view, + 'data' => $templateData + ); + + } + + +} + +?> \ No newline at end of file diff --git a/setup/adminTabs.php b/setup/adminTabs.php index f9ead31..3f5a6fb 100644 --- a/setup/adminTabs.php +++ b/setup/adminTabs.php @@ -34,3 +34,18 @@ */ +if (apply_filters('glm_members_permit_admin_members_search_tab', true)) { + add_filter('glm-member-db-add-tab-for-management', + function($addOnTabs) { + $newTabs = array( + array( + 'text' => 'Search', + 'menu' => 'management', + 'action' => 'search' + ) + ); + $addOnTabs = array_merge($addOnTabs, $newTabs); + return $addOnTabs; + } + ); +} diff --git a/setup/databaseScripts/create_database_V0.0.1.sql b/setup/databaseScripts/create_database_V0.0.1.sql new file mode 100644 index 0000000..958f06a --- /dev/null +++ b/setup/databaseScripts/create_database_V0.0.1.sql @@ -0,0 +1,27 @@ +-- Gaslight Media Members Database - Search +-- File Created: 12/02/15 15:27:15 +-- Database Version: 0.0.1 +-- Database Creation Script +-- +-- To permit each query below to be executed separately, +-- all queries must be separated by a line with four dashes + +-- Search Management Settings +CREATE TABLE {prefix}management ( + id INT NOT NULL AUTO_INCREMENT, + search_index TINYTEXT NULL, -- OSS Search Index to use (normally "Index_1") + website TINYTEXT NULL, -- Hostname for the Website + login TINYTEXT NULL, -- OSS API Login + login_key TINYTEXT NULL, -- OSS API Login Key + PRIMARY KEY (id) +); + +---- + +-- Set default package management entry +INSERT INTO {prefix}management + ( id, search_index, website, login, login_key ) + VALUES + ( 1, 'Index_1', 'www.gaslightmedia.com', 'WebsiteServices', '829800701e8440b67a78e3afbefa1049' ) +; + diff --git a/setup/databaseScripts/dbVersions.php b/setup/databaseScripts/dbVersions.php new file mode 100644 index 0000000..1419080 --- /dev/null +++ b/setup/databaseScripts/dbVersions.php @@ -0,0 +1,19 @@ + + * @license http://www.gaslightmedia.com Gaslightmedia + * @release dbVersions.php,v 1.0 2014/10/31 19:31:47 cscott Exp $ + * @link http://dev.gaslightmedia.com/ + */ + +$glmMembersSearchDbVersions = array( + '0.0.1' => array('version' => '0.0.1', 'tables' => 1) +); + diff --git a/setup/shortcodes.php b/setup/shortcodes.php index b8fdf75..61f7769 100644 --- a/setup/shortcodes.php +++ b/setup/shortcodes.php @@ -92,8 +92,67 @@ * */ -$glmMembersSampleShortcodes = array( +$glmMembersSearchShortcodes = array( + 'glm-members-search' => array( + 'plugin' => GLM_MEMBERS_SEARCH_PLUGIN_SLUG, + 'menu' => 'search', + 'action' => 'index', + 'table' => false, + 'attributes' => array( + 'type' => 'standard', // 'standard', 'xml-sitemap' + 'order' => 'relevance', // 'relevance', 'date' + 'search' => false // Text to search for or false + ) + ) ); -$glmMembersSampleShortcodesDescription = ''; +$glmMembersSearchShortcodesDescription = ' + ShortcodeAttributeDescription + + [glm-members-search] +   + + Displays a search form for searching the entire Web site using the Gaslight Media search + engine. If the search form is submitted or the shortcode includes a pre-set search + string, the search form will be displayed with the search parameters and the results + displayed below. + + + +   + type="{search type}" + + The type of search +

+ + + + + +
Search Types
standardTypical search engine results
sitemapA user-readable list of all pages in the site with links to the page.
xml-sitemapAn XML sitemap of all pages for this Web site
+

+ + + +   + order="{order type}" + + Order of search results +

+ + + + +
Order Types
relevanceSort results by relevance with most relevant result first
date/td>Sort results by last date update with most recent first.
+

+ + + +   + search="{search string}" + + Specified text to search for. Only use if you want to start with a particular search. + + +'; diff --git a/setup/validActions.php b/setup/validActions.php index 00e7305..c29e80e 100644 --- a/setup/validActions.php +++ b/setup/validActions.php @@ -29,12 +29,24 @@ * This array is integrated into the valid actions array in the main GLM Member * DB plugin when this plugin registers itself. */ - +/* $glmMembersSampleAddOnValidActions = array( 'adminActions' => array( ), 'frontActions' => array( ) ); +*/ -?> \ No newline at end of file +$glmMembersSearchAddOnValidActions = array( + 'adminActions' => array( + 'management' => array( + 'search' => GLM_MEMBERS_SEARCH_PLUGIN_SLUG + ) + ), + 'frontActions' => array( + 'search' => array( + 'index' => GLM_MEMBERS_SEARCH_PLUGIN_SLUG + ) + ) +); diff --git a/views/admin/management/search.html b/views/admin/management/search.html new file mode 100644 index 0000000..79a5a46 --- /dev/null +++ b/views/admin/management/search.html @@ -0,0 +1,60 @@ +{include file='admin/management/header.html'} + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ {if $settingsUpdated}

Settings Updated

{/if} + {if $settingsUpdateError}Settings Update Error{/if} +

General Search Settings

+
Search Index: + + {if $searchSettings.fieldFail.search_index}

{$searchSettings.fieldFail.search_index}

{/if} +
Website: + + {if $searchSettings.fieldFail.website}

{$searchSettings.fieldFail.website}

{/if} +
OSS Login: + + {if $searchSettings.fieldFail.login}

{$searchSettings.fieldFail.login}

{/if} +
OSS login key: + + {if $searchSettings.fieldFail.login_key}

{$searchSettings.fieldFail.login_key}

{/if} +
+ +
+ + + +{include file='admin/footer.html'} diff --git a/views/front/footer.html b/views/front/footer.html new file mode 100644 index 0000000..f8b0015 --- /dev/null +++ b/views/front/footer.html @@ -0,0 +1,10 @@ + + + + {if $frontDebug} + + {/if} + + \ No newline at end of file diff --git a/views/front/search/Sitemap_XML_0.9.html b/views/front/search/Sitemap_XML_0.9.html new file mode 100644 index 0000000..dc32586 --- /dev/null +++ b/views/front/search/Sitemap_XML_0.9.html @@ -0,0 +1,12 @@ +{if $haveResult} + +{foreach $result->documents as $doc} + + {$doc->url->value|escape:'html'} +{if $doc->lastModifiedDate->textValue} + {$doc->lastModifiedDate->textValue} +{/if} + weekly + +{/foreach} +{else}Sitemap Error: No results available{/if} diff --git a/views/front/search/header.html b/views/front/search/header.html new file mode 100644 index 0000000..5e9f93d --- /dev/null +++ b/views/front/search/header.html @@ -0,0 +1,3 @@ +
+
+ \ No newline at end of file diff --git a/views/front/search/index.html b/views/front/search/index.html new file mode 100644 index 0000000..47d8063 --- /dev/null +++ b/views/front/search/index.html @@ -0,0 +1,104 @@ +{include file='front/search/header.html'} + +
+ Search for: + + + + Match all words + +
+ +{if $haveSearchResult} + + {if $searchResult.totalResults > 0} + + + +
+ +
+ Showing {$searchResult.firstResultOnPage} through {$searchResult.lastResultOnPage} of {$searchResult.totalResults} results. +
+ + + +
+ + {if $searchResult.previousPageStartIndex !== false} + Previous Results + {else} + Previous Results + {/if} + - + {if $searchResult.nextPageStartIndex !== false} + Next Results + {else} + Next Results + {/if} +
+ +
+ + + +
+ + {foreach $searchResult.documents as $doc} +
+ + + +
+ {foreach from=$doc.content.snippets item="snip" name="snip"} + {$snip} + {if (!$smarty.foreach.snip.last)}
----
{/if} + {/foreach} +
+
{$doc.url.value}
+
+ {/foreach} + +
+ + + +
+ +
+ Showing {$searchResult.firstResultOnPage} through {$searchResult.lastResultOnPage} of {$searchResult.totalResults} results. +
+ + + +
+ + {if $searchResult.previousPageStartIndex !== false} + Previous Results + {else} + Previous Results + {/if} + - + {if $searchResult.nextPageStartIndex !== false} + Next Results + {else} + Next Results + {/if} +
+ +
+ + + {else} +

No results matching your search.

+ {/if} + +{else} + (Please enter your desired search above.) +{/if} + +
+ +{include file='front/footer.html'} -- 2.17.1