evocms-community / pagebuilder

Page Builder for Evolution CMS
29 stars 23 forks source link

What is the best way to perform site search in PageBuilder? #65

Open pmfx opened 6 years ago

pmfx commented 6 years ago

I was wondering what is the best way to make site search when website content heavily depends on PageBuilder?

How to configure AjaxSearch or other snippet to search in PageBuilder and show the search results?

mnoskov commented 6 years ago

Good question

mnoskov commented 6 years ago

I found that AjaxSearch can perform search in custom tables this way:

function pagebuilder_ajaxsearch(&$main, &$joined, $bsf, $fields) {
    global $modx;

    $joined = [
        'tb_name' => $modx->getFullTablename('pagebuilder'),
        'tb_alias' => 'pb',
        'id' => 'id',
        'main' => 'id',
        'join' => 'document_id',
        'searchable' => ['values'],
        'displayed' => ['config', 'values'],
        'concat_separator' => ', ',
        'filters' => [
            ['field' => 'visible', 'oper' => '=', 'value' => '1'],
        ],
    ];
}
[!AjaxSearch? &whereSearch=`content|pagebuilder_ajaxsearch` &ajaxSearch=`0`!]

But results filtered by built in jscropper (because data stored in json format)

pmfx commented 6 years ago

Thanks. That was a good clue and I got it working! At least it looks like it is working ;)

Here is what I did:

I've copied AjaxSearch default config file: assets/snippets/ajaxSearch/configs/default.config.php as a assets/snippets/ajaxSearch/configs/pagebuilder.config.php

At the end of this new config file I've added your code and a copy of AjaxSearch strip code (without JS strip):

function pagebuilder_ajaxsearch(&$main, &$joined, $bsf, $fields) {
  global $modx;

  $joined = [
    'tb_name' => $modx->getFullTablename('pagebuilder'),
    'tb_alias' => 'pb',
    'id' => 'id',
    'main' => 'id',
    'join' => 'document_id',
    'searchable' => ['values'],
    'displayed' => ['config', 'values'],
    'concat_separator' => ', ',
    'filters' => [
      ['field' => 'visible', 'oper' => '=', 'value' => '1']
    ],
  ];
}

function pagebuilderStripOutput($text) {
  global $modx;

  if ($text !== '') {
    // stripLineBreaking : replace line breaking tags with whitespace
    $text = preg_replace("'<(br[^/>]*?/|hr[^/>]*?/|/(div|h[1-6]|li|p|td))>'si", ' ', $text);

    // stripTags : Remove MODX sensitive tags
    $modRegExArray[] = '~\[\[(.*?)\]\]~s';
    $modRegExArray[] = '~\[\!(.*?)\!\]~s';
    $modRegExArray[] = '#\[\~(.*?)\~\]#s';
    $modRegExArray[] = '~\[\((.*?)\)\]~s';
    $modRegExArray[] = '~{{(.*?)}}~s';
    $modRegExArray[] = '~\[\*(.*?)\*\]~s';
    $modRegExArray[] = '~\[\+(.*?)\+\]~s';

    foreach ($modRegExArray as $mReg) $text = preg_replace($mReg, '', $text);

    // stripHtml : Remove HTML sensitive tags
    $text = strip_tags($text);
  }
  return $text;
}

The last thing was a snippet call:

[!AjaxSearch? 
&config=`pagebuilder` 
&ajaxSearch=`0` 
&whereSearch=`content|tv|pagebuilder_ajaxsearch` 
&stripOutput=`pagebuilderStripOutput`
!]
pmfx commented 6 years ago

To show extract from PB in AS results you can use this in snippet parameter:

&extract=`1:content,pb_values`

But this may result in showing code like {"richtext":"Lorem ipsum....."}

As a temporary workaround I added this at the end of a "pagebuilderStripOutput" function:

// strip pagebuilder wrappers
$text = str_replace('{"richtext":"', '', $text);
$text = str_replace('"}', '', $text);

But it is not perfect in case other field names are used. Probably can be solved with preg_replace/regex but I'm not that familiar with it.

pmfx commented 6 years ago

While the configuring AjaxSearch is pretty difficult, maybe easiest solution would be to make a copy of PageBuilder values (without JS code) inside "content" field of "site_content" table on every document save event?

With this, there would be no issues with searching or configuring AjaxSearch.

pmfx commented 6 years ago

... and it could be added as a new plugin setting (turned off by default).

mnoskov commented 6 years ago

I don't like this solution, we can just end AjaxSearch config to crop all mustaches with regex

fourroses666 commented 5 years ago

Cool, have it working. My mistake was that I didn't add it to the result (landing) page snippet.