Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
e0b0bc5
Add table name to join query
monkeyfeet Sep 7, 2020
96f134a
Update naming of package
monkeyfeet Sep 7, 2020
cddad8b
Merge pull request #1 from PlasticStudio/fix/multiple_manymany_filters
monkeyfeet Sep 7, 2020
9b560f8
Update namespacing to plasticstudio
monkeyfeet Sep 7, 2020
2aee8bf
Merge pull request #2 from PlasticStudio/fix/multiple_manymany_filters
monkeyfeet Sep 7, 2020
6cc25ad
Repair sort issue, remove duplicates
monkeyfeet Sep 7, 2020
8fcf2ec
Merge pull request #3 from PlasticStudio/fix/multiple_manymany_filters
monkeyfeet Sep 7, 2020
2ddada9
Add extra info
monkeyfeet Sep 8, 2020
391882c
Merge pull request #4 from PlasticStudio/feature/readme
monkeyfeet Sep 8, 2020
54815da
Update composer with author details etc
monkeyfeet Sep 8, 2020
26ae479
Merge pull request #5 from PlasticStudio/feature/readme
monkeyfeet Sep 8, 2020
73507a5
Add default sorting
monkeyfeet Sep 9, 2020
2ceb998
Merge pull request #6 from PlasticStudio/feature/sorting
monkeyfeet Sep 9, 2020
826f718
Simplify get_mapped_defaults function
monkeyfeet Sep 14, 2020
afb06d3
Merge pull request #7 from PlasticStudio/feature/defaults
monkeyfeet Sep 14, 2020
a211553
changed filtering style from listboxfield to checkboxsetfield
callan-stretton Oct 1, 2020
80a8fc0
Merge pull request #8 from PlasticStudio/hotfix/set-to-checkboxsetfield
callan-stretton Oct 1, 2020
bb9085d
fix config line not commented out, template folder rename, missing cl…
ebakernz Mar 17, 2021
c0a8cc2
Merge pull request #9 from PlasticStudio/feature/config
ebakernz Mar 17, 2021
820d8b0
Update requireDefaultRecords for SearchPage
monkeyfeet Mar 17, 2021
7d0af07
filter results list by canView()
monkeyfeet Mar 18, 2021
ec445ea
Merge pull request #10 from PlasticStudio/feature/dms_documents
monkeyfeet Mar 18, 2021
3ff1246
Update readme
monkeyfeet Mar 18, 2021
73f1b1d
Merge pull request #11 from PlasticStudio/feature/dms_documents
monkeyfeet Mar 18, 2021
6b57344
Add configurable submit_button_text
monkeyfeet Mar 25, 2021
68818fe
Merge pull request #12 from PlasticStudio/feature/button_text_config
monkeyfeet Mar 25, 2021
2ab6b5e
Update readme around sorts and defaults
monkeyfeet Mar 25, 2021
ca35d29
Merge pull request #13 from PlasticStudio/feature/sort_order
monkeyfeet Mar 25, 2021
7a17727
add config for placeholder text in SearchForm
ebakernz Nov 29, 2021
4e472d2
Merge pull request #14 from PlasticStudio/hotfix/placeholder_text
ebakernz Nov 29, 2021
2ace9e9
remove security token to stop timeout error
ebakernz Dec 5, 2021
eea052a
Merge pull request #15 from PlasticStudio/hotfix/token
ebakernz Dec 5, 2021
2fbf783
elemental work
josephlewisnz Feb 9, 2022
ae191cc
index task;
ebakernz Feb 25, 2022
3993137
fix label
ebakernz Feb 25, 2022
7e4365b
404 error pg fix
ebakernz Feb 25, 2022
a338893
404 error pg fix
ebakernz Feb 25, 2022
850d078
write to sql updates
ebakernz Feb 27, 2022
0e18b52
update task
ebakernz Feb 28, 2022
be95ac5
update task
ebakernz Feb 28, 2022
ed66ee0
delete elemnet, remove isondraft
ebakernz Feb 28, 2022
149ab71
add option to reindex all search content
ebakernz Feb 28, 2022
bb7979e
update description
ebakernz Feb 28, 2022
9c9c295
add limit for task
ebakernz Feb 28, 2022
0627326
update eol
ebakernz Feb 28, 2022
795b3c8
limit
ebakernz Feb 28, 2022
40999c1
change task
ebakernz Mar 1, 2022
4a98210
task update
ebakernz Mar 1, 2022
95fdd88
form action url working
ebakernz Mar 10, 2022
48fa76f
revert 404 form action fix
ebakernz Mar 15, 2022
9f5917b
form action
ebakernz Mar 15, 2022
e0cd8ac
update readme
ebakernz Mar 24, 2022
51893c7
Merge pull request #16 from PlasticStudio/feature/elemental-search-test
ebakernz Mar 24, 2022
af054e2
Feature/double draft bug (#17)
josephlewisnz May 10, 2022
fbfd26c
php 8 fixes
ebakernz Sep 15, 2022
535aa70
Merge branch 'master' into feature/bug-fixes
ebakernz Sep 15, 2022
14128ef
Merge pull request #18 from PlasticStudio/feature/bug-fixes
ebakernz Sep 15, 2022
ef360c8
php8 fix for str replace
kjmnavarro Nov 9, 2022
b85abd5
peer review code fix
kjmnavarro Nov 9, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 34 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,18 @@ The built-in SilverStripe search form is a very simple search engine. This plugi
# Usage

* Create a `SearchPage` instance (typically at the root of your website). This page only is used to display results, so please refrain from creating multiple instances.
* Configure your website's `_config/config.yml` to define search parameters.
* Run `dev/build` to instansiate your new configuration
* Configure your website's `_config/config.yml` (or add `_config/search.yml`) to define search parameters.
* Run `dev/build` to instansiate your new configuration (this will also automatically create an instance of `SearchPage` if one does not exist).
* To overwrite the default `SearchPage` tmeplate, add a template file to your application: `templates/PlasticStudio/Search/Layout/SearchPage.ss`


# Elemental

* Elemental search is included
* On page or Element save, all content from all Elements is saved to a field called `ElementalSearchContent` on sitetree.
* Simply include `'SiteTree_Live.ElementalSearchContent'` to the list of page columns
* Currently there is no way to exclude individual elements from being included.
* Run IndexPageContentForSearchTask to index element content


# Configuration
Expand All @@ -23,17 +33,20 @@ The built-in SilverStripe search form is a very simple search engine. This plugi
* `Filters`: a list of filters to apply pre-search (maps to `DataList->Filter(key => value)`)
* `Columns`: columns to search for query string matches (format `Table.Column`)
* `filters`: associative list of filter options
* `Structure`: defines the filter's relational structure (must be one of `db`, `has_one` or `has_many`)
* `Structure`: defines the filter's relational structure (must be one of `db`, `has_one` or `many_many`)
* `Label`: front-end field label
* `Table`: relational subject's table
* `Column`: column to filter on
* `Operator`: SQL filter operator (ie `>`, `=`)
* `Operator`: SQL filter operator (ie `>`, `<`, `=`)
* `JoinTables`: associative list of relationship mappings (use the `key` from the `types` array)
* `Table`: relational join table
* `Column`: column to join by
* `sorts`: associative list of sort options
* `sorts`: associative list of sort options. These are used to popoulate a "Sort by" dropdown field in the Advanced Search Form. Sort order of search results will default to the top item in this list.
* `Label`: front-end field label
* `Sort`: SQL sort string
* `submit_button_text`: Text to use on search form submit button (defaults to "Search")

TODO: `defaults`: Default attributes or settings, as opposed to those submitted through the search form.


# Example configuration
Expand All @@ -44,7 +57,7 @@ Name: search
Before:
- '#site'
---
Jaedb\Search\SearchPageController:
PlasticStudio\Search\SearchPageController:
types:
docs:
Label: 'Documents'
Expand All @@ -53,6 +66,7 @@ Jaedb\Search\SearchPageController:
ClassNameShort: 'File'
Filters:
File_Live.ShowInSearch: '1'
File_Live.ClassName: '''Silverstripe\\Assets\\File''' # You need to TRIPLE-ESCAPE in order to pass this as a string to the query
Columns: ['File_Live.Title','File_Live.Description','File_Live.Name']
pages:
Label: 'Pages'
Expand All @@ -62,7 +76,7 @@ Jaedb\Search\SearchPageController:
Filters:
SiteTree_Live.ShowInSearch: '1'
JoinTables: ['SiteTree_Live']
Columns: ['SiteTree_Live.Title','SiteTree_Live.MenuTitle','SiteTree_Live.Content']
Columns: ['SiteTree_Live.Title','SiteTree_Live.MenuTitle','SiteTree_Live.Content', 'SiteTree_Live.ElementalSearchContent']
filters:
updated_before:
Structure: 'db'
Expand All @@ -86,6 +100,15 @@ Jaedb\Search\SearchPageController:
pages:
Table: 'Page_Tags'
Column: 'PageID'
authors:
Structure: 'many_many'
Label: 'Authors'
ClassName: 'Member'
Table: 'Member'
JoinTables:
pages:
Table: 'Page_Authors'
Column: 'PageID'
sorts:
title_asc:
Label: 'Title (A-Z)'
Expand All @@ -99,4 +122,8 @@ Jaedb\Search\SearchPageController:
published_desc:
Label: 'Publish date (oldest first)'
Sort: 'DatePublished ASC'
submit_button_text: 'Go'
## TODO:
## defaults:
## sort: 'Title ASC'
```
9 changes: 6 additions & 3 deletions _config/config.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
---
Name: search
Name: ps-search
Before:
- '#site'
---
SilverStripe\Control\Controller:
extensions:
- Jaedb\Search\SearchControllerExtension
Jaedb\Search\SearchPageController:
- PlasticStudio\Search\SearchControllerExtension
SilverStripe\CMS\Model\SiteTree:
extensions:
- PlasticStudio\Search\SiteTreeSearchExtension
# PlasticStudio\Search\SearchPageController:
# types:
# docs:
# Label: 'Documents'
Expand Down
9 changes: 9 additions & 0 deletions _config/elemental.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
Name: 'ps-search-elemental'
After: '#ps-search'
Only:
moduleexists: 'dnadesign/silverstripe-elemental'
---
DNADesign\Elemental\Models\BaseElement:
extensions:
- PlasticStudio\Search\ElementalSearchExtension
17 changes: 11 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,24 @@
{
"name": "jaedb/search",
"name": "plasticstudio/search",
"type": "silverstripe-vendormodule",
"description": "SilverStripe search engine",
"homepage": "http://jamesbarnsley.co.nz",
"keywords": ["silverstripe"],
"description": "Search engine for Silverstripe websites - forked from jaedb/search",
"homepage": "https://psdigital.co.nz",
"keywords": ["silverstripe","silverstripesearch"],
"license": "BSD-3-Clause",
"authors": [
{
"name": "James Barnsley",
"homepage": "http://jamesbarnsley.co.nz",
"homepage": "https://jamesbarnsley.co.nz",
"email": "james@barnsley.co.nz"
},
{
"name": "Jeremy Cole",
"homepage": "https://psdigital.co.nz",
"email": "jeremy@psdigital.co.nz"
}
],
"support": {
"issues": "http://github.com/jaedb/search/issues"
"issues": "http://github.com/plasticstudio/search/issues"
},
"extra": {
"expose": [
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"version": "1.1.0",
"author": "James Barnsley",
"description": "SilverStripe Search Engine",
"repository": "https://github.com/jaedb/search",
"repository": "https://github.com/plasticstudio/search",
"licenses": {
"type": "Apache License",
"url": "http://www.apache.org/licenses/LICENSE-2.0.txt"
Expand Down
46 changes: 46 additions & 0 deletions src/ElementalSearchExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace PlasticStudio\Search;

use PlasticStudio\Search\SiteTreeSearchExtension;
use SilverStripe\Core\Extension;
use SilverStripe\Versioned\Versioned;

class ElementalSearchExtension extends Extension
{

/**
* Force a re-index of the parent page for any given element
* @param Versioned $original
*/
public function onAfterPublish(&$original)
{
$this->updateSearchContent();
}

/**
* Force a re-index of the parent page on archive of element
* @param Versioned $original
*/
public function onAfterDelete(&$original)
{
$this->updateSearchContent();
}
/**
* Force a re-index of the parent page on un-publish of element
*/
public function onAfterUnpublish()
{
$this->updateSearchContent();
}

public function updateSearchContent()
{
$parent = $this->getOwner()->getPage();
//Even though we have the parent page. Lets always get the "live" version. This is so when we update the search content we are not indexing draft/unpublished content
$liveParentPage = Versioned::get_by_stage($parent->ClassName, Versioned::LIVE)->byID($parent->ID);
if ($liveParentPage && $liveParentPage->hasExtension(SiteTreeSearchExtension::class)) {
$liveParentPage->updateSearchContent();
}
}
}
132 changes: 132 additions & 0 deletions src/IndexPageContentForSearchTask.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?php

namespace PlasticStudio\Search;

use SilverStripe\Dev\BuildTask;
use SilverStripe\View\SSViewer;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Core\Config\Config;
use SilverStripe\ORM\Queries\SQLUpdate;

class IndexPageContentForSearchTask extends BuildTask
{
protected $title = 'Index Page Content for Search';

protected $description = 'Collate all page content from elements and save to a field for search. Add optional query string, "reindex=true" to reindex all pages.';

public function run($request)
{
$reindex = $request->getVar('reindex');
$offset = $request->getVar('offset') ? $request->getVar('offset') : NULL;
$limit = $request->getVar('limit') ? $request->getVar('limit') : 10;

// select all sitetree items
$items = SiteTree::get()->limit($limit, $offset);
echo 'Running...<br />';
echo 'limit: ' . $limit . '<br />';
echo 'offset: ' . $offset . '<br />';
// echo 'count ' . $items->Count(). '<br />';

if(!$reindex) {
$items = $items->filter(['ElementalSearchContent' => null]);
echo 'Running - generating first index...<br />';
}

if(!$items->count()) {
echo 'No items to update.<br />';
} else {

foreach ($items as $item) {

// get the page content as plain content string
$content = $this->collateSearchContent($item);

// Update this item in db
$update = SQLUpdate::create();
$update->setTable('"SiteTree"');
$update->addWhere(['ID' => $item->ID]);
$update->addAssignments([
'"ElementalSearchContent"' => $content
]);
$update->execute();

// IF page is published, update the live table
if ($item->isPublished()) {
$update = SQLUpdate::create();
$update->setTable('"SiteTree_Live"');
$update->addWhere(['ID' => $item->ID]);
$update->addAssignments([
'"ElementalSearchContent"' => $content
]);
$update->execute();
}

echo '<p>Page ' . $item->Title . ' indexed.</p>' . PHP_EOL;
}
}
}

/**
* Generate the search content to use for the searchable object
*
* We just retrieve it from the templates.
*/
private function collateSearchContent($page): string
{
// Get the page
/** @var SiteTree $page */
// $page = $this->getOwner();

$content = '';

if (self::isElementalPage($page)) {
// Get the page's elemental content
$content .= $this->collateSearchContentFromElements($page);
}

return $content;
}


/**
* @param SiteTree $page
* @return bool
*/
private static function isElementalPage($page)
{
return $page::has_extension("DNADesign\Elemental\Extensions\ElementalPageExtension");
}

/**
* @return string|string[]|null
*/
private function collateSearchContentFromElements($page)
{
// Get the original theme
$originalThemes = SSViewer::get_themes();

// Init content
$content = '';

try {
// Enable frontend themes in order to correctly render the elements as they would be for the frontend
Config::nest();
SSViewer::set_themes(SSViewer::config()->get('themes'));

// Get the elements content
$content .= $page->getOwner()->getElementsForSearch();

// Clean up the content
$content = preg_replace('/\s+/', ' ', $content);

// Return themes back for the CMS
Config::unnest();
} finally {
// Restore themes
SSViewer::set_themes($originalThemes);
}

return $content;
}

}
Loading