Ready for initial integration.
--- /dev/null
+<?php
+/**
+ * GLM Member-DB WordPress Add-On Plugin
+ * Search Management data class
+ *
+ * PHP version 5.3
+ *
+ * @category Data
+ * @package GLM Member-DB
+ * @author Chuck Scott <cscott@gaslightmedia.com>
+ * @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 <cscott@gaslightmedia.com>
+ * @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
--- /dev/null
+<?php\r
+/**\r
+ * GLM Search Engine - Support Classes\r
+ *\r
+ * PHP version 5\r
+ *\r
+ * @category Support_Services\r
+ * @package GLMSearch\r
+ * @author Chuck Scott <cscott@gaslightmedia.com>\r
+ * @license http://www.gaslightmedia.com Gaslightmedia\r
+ * @release SVN: $Id: glmSearch.inc,v 1.0 2011/01/25 19:31:47 cscott Exp $\r
+ * @link\r
+ */\r
+\r
+/**** NOTE : THIS FILE HAS NOT HAD A THOUROUGH REVIEW SINCE BEING GRABBED FROM THE OLD GLM COMMON APPS *****/\r
+\r
+/*\r
+ * Set OpenSearchServer base URL and port\r
+ */\r
+define('OpenSearchServer', 'http://oss.gaslightmedia.com:9090');\r
+\r
+/**\r
+ * GLM Search - Web Site Search Support Class\r
+ *\r
+ * PHP version 5\r
+ *\r
+ * @category Support_Services\r
+ * @package EventManagement\r
+ * @author Chuck Scott <cscott@gaslightmedia.com>\r
+ * @license http://www.gaslightmedia.com Gaslightmedia\r
+ * @release SVN: $Id: GeoCalculations.php,v 1.0 2011/01/25 19:31:47 cscott Exp $\r
+ * @link http://housing.gaslightmedia.com/admin/\r
+ */\r
+class GLMSearch\r
+{\r
+\r
+ /**\r
+ * Name of the index an instance of this class will search.\r
+ * An index can have multiple Websites in it. If when calling\r
+ * the constructor no $index is specified, the code will assume\r
+ * that the index name and website name are the same. Otherwise\r
+ * it will use $index as the index name.\r
+ *\r
+ * @var $index\r
+ * @access private\r
+ */\r
+ private $index;\r
+ /**\r
+ * Name of the Web site an instance of this class will work on\r
+ *\r
+ * @var $website\r
+ * @access private\r
+ */\r
+ private $website;\r
+ /**\r
+ * Authentication paramters for all requests\r
+ *\r
+ * @var $auth\r
+ * @access private\r
+ */\r
+ private $auth;\r
+ /**\r
+ * General error message describing any failure\r
+ *\r
+ * @var $curlError\r
+ * @access public\r
+ */\r
+ public $errorMessage;\r
+ /**\r
+ * Exception object caused by curl or other failure\r
+ *\r
+ * @var $error\r
+ * @access public\r
+ */\r
+ public $error;\r
+ /**\r
+ * Request array\r
+ *\r
+ * This should be the most common request configuration\r
+ * we'll be using for our Web sites. It's public so it\r
+ * can be easily customized for a particular Web site\r
+ * once the class has been instantiated.\r
+ *\r
+ * See clearResults() method for default data\r
+ *\r
+ * @var $request Array of request information\r
+ * @access public\r
+ */\r
+ public $request = false;\r
+ /**\r
+ * Search type\r
+ *\r
+ * This selects whether a search will be a 'field' search or 'pattern' search\r
+ *\r
+ * @var $type String Either 'field' or 'pattern'\r
+ * @access private\r
+ */\r
+ private $type = 'field';\r
+ /**\r
+ * Curl instance\r
+ *\r
+ * @var $curl\r
+ * @access private\r
+ */\r
+ private $curl = false;\r
+ /**\r
+ * HTTP Status from curl\r
+ *\r
+ * @var $httpStatus\r
+ * @access public\r
+ */\r
+ public $httpStatus = false;\r
+ /**\r
+ * HTTP Header from curl\r
+ *\r
+ * @var $httpHeader\r
+ * @access public\r
+ */\r
+ public $httpHeader = false;\r
+ /**\r
+ * Raw Result of curl request\r
+ *\r
+ * Public so it can easily be examined\r
+ *\r
+ * @var $rawResult\r
+ * @access public\r
+ */\r
+ public $rawResults = false;\r
+ /**\r
+ * Full results as an array\r
+ *\r
+ * @var $resultArray\r
+ * @access private\r
+ */\r
+ private $resultArray = false;\r
+ /**\r
+ * Compressed results array\r
+ *\r
+ * This array has better processed data for output\r
+ * and has trimmed levels for document data for\r
+ * easier use.\r
+ *\r
+ * @var $result\r
+ * @access private\r
+ */\r
+ private $result = false;\r
+ /**\r
+ * Host Filter flag\r
+ *\r
+ * @var $filter\r
+ * @access public\r
+ */\r
+ public $filter = true;\r
+ /**\r
+ * Host Filter Type\r
+ *\r
+ * @var $filterType\r
+ * @access public\r
+ */\r
+ public $filterType = false;\r
+ /**\r
+ * Host Filter Value\r
+ *\r
+ * @var $filterValue\r
+ * @access public\r
+ */\r
+ public $filterValue = false;\r
+\r
+ /**\r
+ * Constructor\r
+ *\r
+ * @param text $index Optional index name if Web site is part of a larger index\r
+ * @param string $website Name of the Web site\r
+ * @param string $login Login to OpenSearchServer\r
+ * @param string $key Key for login\r
+ * @param text $filterType Optional filter type (when $this->filter is true).\r
+ * Filter types are "title", "titleExact", "titlePhonetic", "content",\r
+ * "contentExact", "contactPhonetic", "urlSplit", "urlExact", "urlPhonetic",\r
+ * "full", "fullExact", "fullPhonetic"\r
+ * @param text $filterValue Filter value to use with $filterType.\r
+ *\r
+ * @return void\r
+ * @access public\r
+ */\r
+ public function __construct($index, $website, $login, $key, $filterType = false, $filterValue = false)\r
+ {\r
+\r
+ // If there's a problem with Filter and validate supplied parameters\r
+ if (\r
+ ($website = filter_var($website, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH)) == false ||\r
+ ($login = filter_var($login, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH)) == false ||\r
+ ($key = filter_var($key, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH)) == false\r
+ ) {\r
+ return false;\r
+ }\r
+\r
+ // Store supplied parameters\r
+ $this->index = $index;\r
+ $this->website = $website;\r
+\r
+ // Build authentication parameters for submissions\r
+ $this->auth = "login=$login&key=$key";\r
+\r
+ // Create curl instance - and set to return response\r
+ $this->curl = curl_init();\r
+ curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, TRUE);\r
+\r
+ }\r
+\r
+ /**\r
+ * Perform a search on the Web site\r
+ *\r
+ * @param string $query The user's search string\r
+ * @param string $operator Operator for the query terms (AND, OR)\r
+ * Default = 'OR'\r
+ * @param integer $start Starting result number\r
+ * Default = 0 (first page)\r
+ * @param integer $rows Number of rows per result page\r
+ * Default = 10\r
+ *\r
+ * @return string JSON of results or false if a failure\r
+ *\r
+ * @access public\r
+ */\r
+ public function glmSearch($query, $operator = 'OR', $start = 0, $rows = 10)\r
+ {\r
+\r
+ // Clear all the results data\r
+ $this->clearResults();\r
+\r
+ // Filter and validate supplied parameters\r
+ if (\r
+ (filter_var($query, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH)) == false ||\r
+ (in_array($operator, array('OR', 'AND'))) == false\r
+ ) {\r
+ return false;\r
+ }\r
+\r
+ // strip any characters that cause a problem. Add more characters to array if needed.\r
+ $remove = array("'");\r
+ $query = htmlspecialchars_decode($query, ENT_QUOTES);\r
+ $query = str_replace("'", "", $query);\r
+\r
+ $start = ($start - 0);\r
+ $rows = ($rows - 0);\r
+\r
+\r
+ // Check if we have a valid query\r
+ if (trim($query) == '') {\r
+ return false;\r
+ }\r
+\r
+ // Create request URL\r
+ switch ($this->type) {\r
+ case 'field':\r
+ $url = OpenSearchServer.'/services/rest/index/'.$this->index.'/search/field/?'.$this->auth;\r
+ break;\r
+ case 'pattern':\r
+ $url = OpenSearchServer.'/services/rest/index/'.$this->index.'/search/pattern/?'.$this->auth;\r
+ break;\r
+ }\r
+\r
+ // Update query and operator in request\r
+ $this->request['query'] = $query;\r
+ $this->request['start'] = $start;\r
+ $this->request['rows'] = $rows;\r
+ $this->request['operator'] = $operator;\r
+\r
+ // If host filter has not been turned off, set filter to only search the specified Website in the index\r
+ if ($this->filter) {\r
+\r
+ // Determine if there's a specific filter type and value - Default to host:\r
+ $query = 'host:"'.$this->website.'"';\r
+ if ($this->filterType) {\r
+ if ($this->filterValue) {\r
+ $query = $this->filterType.':"'.$this->filterValue.'"';\r
+ } else {\r
+ $query = $this->filterType.':"'.$this->website.'"';\r
+ }\r
+ }\r
+\r
+ // Set filter\r
+ $this->request['filters'] = array(\r
+ array(\r
+ "type" => "QueryFilter",\r
+ "negative" => false,\r
+ "query" => $query\r
+ )\r
+ );\r
+\r
+ } else {\r
+ unset($this->request['filters']);\r
+ }\r
+\r
+ // Set curl options\r
+ curl_setopt_array($this->curl, array(\r
+ CURLOPT_URL => $url,\r
+ CURLOPT_POST => true,\r
+ CURLOPT_POSTFIELDS => json_encode($this->request),\r
+ CURLOPT_HTTPHEADER => array("Content-type: application/json; charset=utf-8"),\r
+ CURLOPT_VERBOSE => 1,\r
+ CURLOPT_HEADER => 1\r
+ ));\r
+\r
+ // Do curl call and get result;\r
+ try {\r
+ $res = curl_exec($this->curl);\r
+ } catch (Exception $e) {\r
+ return false;\r
+ }\r
+\r
+ // Parse out results elements\r
+ $this->httpStatus = curl_getinfo($this->curl, CURLINFO_HTTP_CODE);\r
+ $header_size = curl_getinfo($this->curl, CURLINFO_HEADER_SIZE);\r
+ $this->httpHeader = substr($res, 0, $header_size);\r
+ $this->rawResults = substr($res, $header_size);\r
+\r
+ // Check HTTP status code\r
+ if ($this->httpStatus != 200) {\r
+ return false;\r
+ }\r
+\r
+ $this->resultArray = json_decode($this->rawResults, true);\r
+\r
+ $res = $this->compressResults();\r
+\r
+ return $res;\r
+ }\r
+\r
+ /**\r
+ * Compress search results as associative array into\r
+ * more succinct result array for use with output template.\r
+ *\r
+ * @param $res Uncompressed search results array\r
+ *\r
+ * @return array Array of results or false if a failure\r
+ *\r
+ * @access public\r
+ */\r
+ public function compressResults()\r
+ {\r
+\r
+ // Check if we don't have valid input\r
+ if (!is_array($this->resultArray) || !$this->resultArray['successful']) {\r
+ return false;\r
+ }\r
+\r
+ // Calculate certain paging values\r
+ $rowsPerPage = $this->resultArray['rows'];\r
+ $thisPageStartIndex = $this->resultArray['start']; // Based on first result being 0\r
+ $thisPageStart = $thisPageStartIndex + 1; // Displayed first result number\r
+ $numbResults = $this->resultArray['numFound'];\r
+ $numbResultsOnPage = count($this->resultArray['documents']);\r
+ $lastResultOnPage = $thisPageStart + $numbResultsOnPage - 1;\r
+ $previousPageStartIndex = $thisPageStartIndex - $rowsPerPage;\r
+ if ($previousPageStartIndex < 0) {\r
+ $previousPageStartIndex = false;\r
+ }\r
+ $nextPageStartIndex = $thisPageStartIndex + $rowsPerPage;\r
+ if ($nextPageStartIndex > ($numbResults - 1)) {\r
+ $nextPageStartIndex = false;\r
+ }\r
+\r
+ // Build basic search results array\r
+ $this->result = array(\r
+ 'resultsPerPage' => $this->resultArray['rows'],\r
+ 'operator' => $this->request['operator'],\r
+ 'totalResults' => $numbResults,\r
+ 'firstResultOnPage' => $thisPageStart,\r
+ 'resultsOnPage' => $numbResultsOnPage,\r
+ 'lastResultOnPage' => $lastResultOnPage,\r
+ 'previousPageStartIndex' => $previousPageStartIndex,\r
+ 'nextPageStartIndex' => $nextPageStartIndex,\r
+ 'documents' => array()\r
+ );\r
+\r
+ // Add in results for each document\r
+ foreach ($this->resultArray['documents'] as $d) {\r
+\r
+ // Base document information\r
+ $doc = array(\r
+ 'score' => $d['score'],\r
+ 'collapseCount' => $d['collapseCount']\r
+ );\r
+\r
+ // Document fields (simple text fields)\r
+ foreach ($d['fields'] as $df) {\r
+ $doc[$df['fieldName']] = array(\r
+ 'type' => 'field',\r
+ 'name' => $df['fieldName'],\r
+ 'value' => (isset($df['values'][0]) ? $df['values'][0] : '')\r
+ );\r
+\r
+ }\r
+\r
+ // Document snippets (possible multiple snippets per each)\r
+ foreach ($d['snippets'] as $ds) {\r
+ $doc[$ds['fieldName']] = array(\r
+ 'type' => 'snippets',\r
+ 'name' => $ds['fieldName'],\r
+ 'snippets' => array()\r
+ );\r
+\r
+ // Process possible multiple snippet values\r
+ if (is_array($ds['values']) && count($ds['values']) > 0) {\r
+ foreach ($ds['values'] as $sv) {\r
+ $doc[$ds['fieldName']]['snippets'][] = $sv;\r
+ }\r
+ }\r
+\r
+ }\r
+\r
+ // Need to add processing of "functions" also here\r
+\r
+ // Look for null or blank title\r
+ if (empty($doc['title']['value']) && !empty($doc['url']['value'])) {\r
+ $doc['title']['value'] = $doc['url']['value'];\r
+ }\r
+\r
+ // Clean up lastModifiedDate if included\r
+ if (isset($doc['lastModifiedDate']) && isset($doc['lastModifiedDate']['value'])) {\r
+ $d = $doc['lastModifiedDate']['value'];\r
+ $doc['lastModifiedDate']['textValue'] = '';\r
+ if (trim($d) != '') {\r
+ $doc['lastModifiedDate']['textValue'] = substr($d, 0, 4).'-'.substr($d,4,2).'-'.substr($d,6,2);\r
+ }\r
+ }\r
+\r
+ // Add this document to result documents array\r
+ $this->result['documents'][] = $doc;\r
+\r
+ }\r
+\r
+ return $this->result;\r
+ }\r
+\r
+ /**\r
+ * Create an XML Sitemap from search results\r
+ *\r
+ * @param string $template Template to use for producing results (override default)\r
+ * @param array $request Array of request parameters\r
+ * 'query' Required - Search String\r
+ * 'matchAll' Optional - Match all words option ('AND', 'OR')\r
+ * 'start' Optional - Start index\r
+ * 'rows' Optional - Results per page\r
+ *\r
+ * @return void\r
+ * @access public\r
+ */\r
+ public function xmlSitemap($templateName = 'Sitemap_XML_0.9.html')\r
+ {\r
+\r
+ // Search for * (matches everything)\r
+ $request = array(\r
+ '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',\r
+ 'matchAll' => 'OR',\r
+ 'start' => 0,\r
+ 'rows' => 50000\r
+ );\r
+ $page = $this->doSearch($templateName, GLMSearch_TEMPLATE_PATH, $request);\r
+ return $page;\r
+ }\r
+\r
+ /**\r
+ * Tell OpenSearchServer to crawl a particular URL pattern\r
+ *\r
+ * @param integer $pattern URL Pattern\r
+ *\r
+ * @return array Object Results from Search Engine or false if failure.\r
+ *\r
+ * @access public\r
+ */\r
+ public function crawlURL($pattern)\r
+ {\r
+\r
+ // Clear all the results data\r
+ $this->clearResults();\r
+\r
+ // Filter and validate supplied parameters\r
+ if (($pattern = filter_var($pattern, FILTER_SANITIZE_STRING, FILTER_FLAG_STRIP_HIGH)) == false) {\r
+ return false;\r
+ }\r
+\r
+ // Create request URL\r
+ $param = 'url='.$pattern;\r
+ $url = OpenSearchServer.'/services/rest/index/'.$this->index.'/crawler/web/crawl?'.$this->auth.'&'.$param;\r
+\r
+ // Set curl options\r
+ curl_setopt_array($this->curl, array(\r
+ CURLOPT_URL => $url,\r
+ CURLOPT_POST => false,\r
+ CURLOPT_VERBOSE => 1,\r
+ CURLOPT_HEADER => 1\r
+ ));\r
+\r
+ // Do curl call and get result;\r
+ try {\r
+ $res = curl_exec($this->curl);\r
+ } catch (Exception $e) {\r
+ return false;\r
+ }\r
+\r
+ // Parse out results elements\r
+ $this->httpStatus = curl_getinfo($this->curl, CURLINFO_HTTP_CODE);\r
+ $header_size = curl_getinfo($this->curl, CURLINFO_HEADER_SIZE);\r
+ $this->httpHeader = substr($res, 0, $header_size);\r
+ $this->rawResults = substr($res, $header_size);\r
+\r
+ // Check HTTP status code\r
+ if ($this->httpStatus != 200) {\r
+ return false;\r
+ }\r
+\r
+ // Debug information\r
+ $this->errorMessage = 'crawlURL() - Completed successfully.';\r
+\r
+ return json_decode($this->rawResults);\r
+ }\r
+\r
+ /**\r
+ * Clear all request and results data - used before a new curl call\r
+ *\r
+ * @return void\r
+ * @access private\r
+ */\r
+ private function clearResults()\r
+ {\r
+\r
+ /*\r
+ * Reset request to default\r
+ * (Note: Need to add more explanation for this data.)\r
+ */\r
+ $this->request = array(\r
+ 'query' => false, // Query String\r
+ 'start' => 0, // Result number for start of page\r
+ 'rows' => 10, // Number of rows to display per page\r
+ 'lang' => 'ENGLISH', // Language (in all caps)\r
+ 'operator' => 'AND', // Either AND or OR - And matches pages containing all words\r
+ 'collapsing' => array(\r
+ 'max' => 2,\r
+ 'mode' => 'OFF',\r
+ 'type' => 'OPTIMIZED'\r
+ ),\r
+ 'geo' => null,\r
+ 'filters' => null,\r
+ 'sorts' => null,\r
+ 'returnedFields' => array(\r
+ 'url',\r
+ 'title',\r
+ 'lastModifiedDate'\r
+ ),\r
+ 'snippets' => array(\r
+ array(\r
+ 'field' => 'content',\r
+ 'tag' => 'b',\r
+ 'separator' => '...',\r
+ 'maxSize' => 300,\r
+ 'maxNumber' => 1,\r
+ 'fragmenter' => 'SENTENCE'\r
+ )\r
+ ),\r
+ 'facets' => null,\r
+ 'joins' => null,\r
+ 'enableLog' => null,\r
+ 'customLogs' => null,\r
+ 'searchFields' => array(\r
+ array(\r
+ 'field' => 'title',\r
+ 'boost'=> 10\r
+ ),\r
+ array(\r
+ 'field' => 'content',\r
+ 'boost'=> 1\r
+ ),\r
+ array(\r
+ 'field' => 'titleExact',\r
+ 'boost'=> 10\r
+ ),\r
+ array(\r
+ 'field' => 'contentExact',\r
+ 'boost'=> 1\r
+ )\r
+ )\r
+ );\r
+ // Clear results\r
+ $this->httpStatus = false;\r
+ $this->httpHeader = false;\r
+ $this->rawResults = false;\r
+ $this->resultArray = false;\r
+ $this->result = false;\r
+ $this->errorMessage = false;\r
+ $this->error = false;\r
+\r
+ }\r
+\r
+}\r
+\r
+?>\r
--- /dev/null
+/* 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;
+}
* 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
*/
* 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');
}
// 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(
'slug' => GLM_MEMBERS_SEARCH_PLUGIN_SLUG,
'actions' => $GLOBALS['glmMembersSearchAddOnValidActions'],
'config' => array(
+ 'settings' => $GLOBALS['searchManagementSettings']
),
'shortcodes' => $GLOBALS['glmMembersSearchShortcodes'],
'shortcodesDescription' => $GLOBALS['glmMembersSearchShortcodesDescription']
--- /dev/null
+<?php
+/**
+ * Gaslight Media Members Database
+ * GLM Members DB - Search Add-on - Management Search Tab
+ *
+ * PHP version 5.5
+ *
+ * @category glmWordPressPlugin
+ * @package glmMembersDatabase
+ * @author Chuck Scott <cscott@gaslightmedia.com>
+ * @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 <cscott@gaslightmedia.com>
+ * @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("<b> /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
--- /dev/null
+<?php
+/**
+ * Gaslight Media Members Database
+ * Front Search using OSS
+ *
+ * PHP version 5.5
+ *
+ * @category glmWordPressPlugin
+ * @package glmMembersDatabase
+ * @author Chuck Scott <cscott@gaslightmedia.com>
+ * @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
*/
+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;
+ }
+ );
+}
--- /dev/null
+-- 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' )
+;
+
--- /dev/null
+<?php
+/**
+ * Gaslight Media Members Database
+ * GLM Members Packaging DB Versions
+ *
+ * PHP version 5.5
+ *
+ * @category glmWordPressPlugin
+ * @package glmMembersDatabase
+ * @author Chuck Scott <cscott@gaslightmedia.com>
+ * @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)
+);
+
*
*/
-$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 = '
+ <tr><th>Shortcode</th><th>Attribute</th><th>Description</th></tr>
+ <tr>
+ <th>[glm-members-search]</th>
+ <td> </td>
+ <td width="50%">
+ 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.
+ </td>
+ </tr>
+ <tr>
+ <td> </td>
+ <th>type="{search type}"</th>
+ <td>
+ The type of search
+ <p>
+ <table width="100%">
+ <tr><th colspan=3">Search Types</th></tr>
+ <tr><td>standard</td><td>Typical search engine results</td></tr>
+ <tr><td>sitemap</td><td>A user-readable list of all pages in the site with links to the page.</td></tr>
+ <tr><td>xml-sitemap</td><td>An XML sitemap of all pages for this Web site</td></tr>
+ </table>
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td> </td>
+ <th>order="{order type}"</th>
+ <td>
+ Order of search results
+ <p>
+ <table width="100%">
+ <tr><th colspan=3">Order Types</th></tr>
+ <tr><td>relevance</td><td>Sort results by relevance with most relevant result first</td></tr>
+ <tr><td>date/td><td>Sort results by last date update with most recent first.</td></tr>
+ </table>
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td> </td>
+ <th>search="{search string}"</th>
+ <td>
+ Specified text to search for. Only use if you want to start with a particular search.
+ </td>
+ </tr>
+';
* 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
+ )
+ )
+);
--- /dev/null
+{include file='admin/management/header.html'}
+
+ <form action="{$thisUrl}?page={$thisPage}" method="post" enctype="multipart/form-data">
+ <input type="hidden" name="glm_action" value="search">
+ <input type="hidden" name="option" value="submit">
+
+ <table class="glm-admin-table">
+
+ <!-- Settings for talking with the Open Search Server -->
+
+ <tr>
+ <td colspan="2">
+ {if $settingsUpdated}<h2 class="glm-notice glm-flash-updated glm-right">Settings Updated</h2>{/if}
+ {if $settingsUpdateError}<span class="glm-error glm-flash-updated glm-right">Settings Update Error</span>{/if}
+ <h2>General Search Settings</h2>
+ </td>
+ </tr>
+ <tr>
+ <th {if $searchSettings.fieldRequired.search_index}class="glm-required"{/if}>Search Index:</th>
+ <td {if $searchSettings.fieldFail.search_index}class="glm-form-bad-input glm-form-bad-input-misc"{/if}>
+ <input type="text" name="search_index" value="{$searchSettings.fieldData.search_index}" class="glm-form-text-input-medium">
+ {if $searchSettings.fieldFail.search_index}<p>{$searchSettings.fieldFail.search_index}</p>{/if}
+ </td>
+ </tr>
+ <tr>
+ <th {if $searchSettings.fieldRequired.website}class="glm-required"{/if}>Website:</th>
+ <td {if $searchSettings.fieldFail.website}class="glm-form-bad-input glm-form-bad-input-misc"{/if}>
+ <input type="text" name="website" value="{$searchSettings.fieldData.website}" class="glm-form-text-input-medium">
+ {if $searchSettings.fieldFail.website}<p>{$searchSettings.fieldFail.website}</p>{/if}
+ </td>
+ </tr>
+ <tr>
+ <th {if $searchSettings.fieldRequired.login}class="glm-required"{/if}>OSS Login:</th>
+ <td {if $searchSettings.fieldFail.login}class="glm-form-bad-input glm-form-bad-input-misc"{/if}>
+ <input type="text" name="login" value="{$searchSettings.fieldData.login}" class="glm-form-text-input-medium">
+ {if $searchSettings.fieldFail.login}<p>{$searchSettings.fieldFail.login}</p>{/if}
+ </td>
+ </tr>
+ <tr>
+ <th {if $searchSettings.fieldRequired.login_key}class="glm-required"{/if}>OSS login key:</th>
+ <td {if $searchSettings.fieldFail.login_key}class="glm-form-bad-input glm-form-bad-input-misc"{/if}>
+ <input type="text" name="login_key" value="{$searchSettings.fieldData.login_key}" class="glm-form-text-input-medium">
+ {if $searchSettings.fieldFail.login_key}<p>{$searchSettings.fieldFail.login_key}</p>{/if}
+ </td>
+ </tr>
+ </table>
+ <input type="submit" value="Update Settings" class="button-primary">
+ </form>
+
+ <script type="text/javascript">
+
+ jQuery(document).ready(function($) {
+
+ // Flash certain elements for a short time after display
+ $(".glm-flash-updated").fadeOut(500).fadeIn(500).fadeOut(500).fadeIn(500).fadeOut(500).fadeIn(500).fadeOut(500).fadeIn(500).fadeOut(500).fadeIn(500).fadeOut(500);
+
+ });
+ </script>
+
+{include file='admin/footer.html'}
--- /dev/null
+
+ </div> <!-- / front content area -->
+
+ {if $frontDebug}
+ <script>
+ window.open('{$thisUrl}?glmDebugWindow=true','GLM_Plugin_Debug','width=800,height=800,left=50,top=50,resizable=yes,scrollbars=yes');
+ </script>
+ {/if}
+
+</div> <!-- / wrap -->
\ No newline at end of file
--- /dev/null
+{if $haveResult}<?xml version="1.0" encoding="UTF-8"?>\r
+<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\r
+{foreach $result->documents as $doc}\r
+ <url>\r
+ <loc>{$doc->url->value|escape:'html'}</loc>\r
+{if $doc->lastModifiedDate->textValue}\r
+ <lastmod>{$doc->lastModifiedDate->textValue}</lastmod>\r
+{/if}\r
+ <changefreq>weekly</changefreq>\r
+ </url>\r
+{/foreach}\r
+</urlset>{else}Sitemap Error: No results available{/if}\r
--- /dev/null
+<div class="wrap">
+ <div id="glm-member-search-front-container" class="glm-member-front-container">
+
\ No newline at end of file
--- /dev/null
+{include file='front/search/header.html'}
+
+ <form action="{$thisUrl}?glm_action=index" method="post" enctype="multipart/form-data">
+ Search for: <input type="hidden" name="GLMSearch" value="true">
+ <input type="hidden" name="start" value="0">
+ <input type="hidden" name="rows" value="10">
+ <input type="text" name="query" value="{$query}">
+ <input type="checkbox" name="matchAll" {if $searchResult.operator == 'AND'}checked{/if} value="on"> Match all words
+ <input type="submit" id="submit" value="Search">
+ </form>
+
+{if $haveSearchResult}
+
+ {if $searchResult.totalResults > 0}
+
+ <!-- Results Header - Top -->
+
+ <div class="GLMSresultsHeader">
+
+ <div class="GLMSresultsSummary">
+ Showing {$searchResult.firstResultOnPage} through {$searchResult.lastResultOnPage} of {$searchResult.totalResults} results.
+ </div>
+
+ <!-- Results Navigation -->
+
+ <div class="GLMSresultsNavContainer">
+
+ {if $searchResult.previousPageStartIndex !== false}
+ <a href="{$thisUrl}?GLMSearch=true&query={$query|escape:'url'}&{if $searchResult.operator == 'AND'}matchAll=on&{/if}start={$searchResult.previousPageStartIndex}&rows={$searchResult.resultsPerPage}">Previous Results</a>
+ {else}
+ <span class="GLMSresultsNavInactive">Previous Results</span>
+ {/if}
+ -
+ {if $searchResult.nextPageStartIndex !== false}
+ <a href="{$thisUrl}?GLMSearch=true&query={$query|escape:'url'}&{if $searchResult.operator == 'AND'}matchAll=on&{/if}start={$searchResult.nextPageStartIndex}&rows={$searchResult.resultsPerPage}">Next Results</a>
+ {else}
+ <span class="GLMSresultsNavInactive">Next Results</span>
+ {/if}
+ </div>
+
+ </div>
+
+ <!-- Search results -->
+
+ <div id="GLMSresultsContainer">
+
+ {foreach $searchResult.documents as $doc}
+ <div class="GLMSresultContainer">
+
+ <div class="GLMSresultTitle">
+ <a href="{$doc.url.value}">{$doc.title.value}</a>
+ </div>
+
+ <div class="GLMSresultSnippets">
+ {foreach from=$doc.content.snippets item="snip" name="snip"}
+ {$snip}
+ {if (!$smarty.foreach.snip.last)}<br>----<br>{/if}
+ {/foreach}
+ </div>
+ <div class="GLMSresultUrl">{$doc.url.value}</div>
+ </div>
+ {/foreach}
+
+ </div>
+
+ <!-- Results Header - Bottom -->
+
+ <div class="GLMSresultsHeader">
+
+ <div class="GLMSresultsSummary">
+ Showing {$searchResult.firstResultOnPage} through {$searchResult.lastResultOnPage} of {$searchResult.totalResults} results.
+ </div>
+
+ <!-- Results Navigation -->
+
+ <div class="GLMSresultsNavContainer">
+
+ {if $searchResult.previousPageStartIndex !== false}
+ <a href="{$thisUrl}?GLMSearch=true&query={$query|escape:'url'}&{if $searchResult.operator == 'AND'}matchAll=on&{/if}start={$searchResult.previousPageStartIndex}&rows={$searchResult.resultsPerPage}">Previous Results</a>
+ {else}
+ <span class="GLMSresultsNavInactive">Previous Results</span>
+ {/if}
+ -
+ {if $searchResult.nextPageStartIndex !== false}
+ <a href="{$thisUrl}?GLMSearch=true&query={$query|escape:'url'}&{if $searchResult.operator == 'AND'}matchAll=on&{/if}start={$searchResult.nextPageStartIndex}&rows={$searchResult.resultsPerPage}">Next Results</a>
+ {else}
+ <span class="GLMSresultsNavInactive">Next Results</span>
+ {/if}
+ </div>
+
+ </div>
+
+
+ {else}
+ <h3>No results matching your search.</h3>
+ {/if}
+
+{else}
+ (Please enter your desired search above.)
+{/if}
+
+</div> <!-- /search wrapper -->
+
+{include file='front/footer.html'}