LemonStand Forum: How to Control Search Results Display - LemonStand Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

How to Control Search Results Display

#1 User is offline   infradawn 

  • Member
  • PipPipPip
  • Group: Members
  • Posts: 85
  • Joined: 19-April 10

Posted 29 August 2010 - 09:01 AM

Hi,

I've created some controls to shape the way that a category's products are displayed. Drop-downs control Sort order [Name, Price], View as [List, Compact List, Grid] and Show per page [5, 10, 25, All].

Everything happens in a partial named shop:category. It draws the controls, updates VisitorPreferencs with changed settings, and uses AJAX to update content according to Sort order and selected View. Changes to Show per page need a Phpr::$response->redirect to reload the entire page with a URL that is correct for the updated pagination. Looks good, works great.

Then I started working on getting the same control over search results. Though I'd start with my shop:category partial and tweak it. Well I'm still tweaking it!

The search is implemented pretty much as in the demo store. Shop_Product::find_products returning $products and a pagination object.

I managed to get Show per page working by saving the value of $query to VisitorPreferences in the partial. This is necessary because after the control's onchange event [getForm().submit()] $query is empty (because the target page following the submit has a URL ../store/search/ with no search params) and the partial has to recreate the proper search URL from saved values before redirecting with:

Phpr::$response->redirect(root_url('search?query='.urlencode($saved_query).'&records='.urlencode($saved_show)));


This works, but I'm thinking there's probably a better way.

A bigger problem is how to change the View (List, Grid, etc).

After landing on the Search page with a setting of 5 records per page and 14 products meeting the search criteria:

$products->Count()= 5
$products->requestRowCount()= 29
$pagination->getRowCount()= 14

Now when I change view, say from List to Grid and update using AJAX (exactly the same method used successfully with category products) the above values do not persist. They are all 0. Looks like the objects don't persist across the AJAX update.

I don't want to make duplicates of these objects that do persist because it's a poor approach. So I figure I'm missing something.

For the category product control I use $category->list_products() which returns a full sorted product list which is easy to manipulate. The search method Shop_Product::find_products returns something a whole lot tougher to deal with.

I haven't even begun to tackle sorting the search results yet :|

Any pointers to best practice how to do this?



One day my posts will be short, but until then...

Thanks

iD
0

#2 User is offline   Aleksey 

  • Co-Founder
  • Group: +Administrators
  • Posts: 3,330
  • Joined: 31-October 09

Posted 29 August 2010 - 03:50 PM

Hi, iD!

There is a significant difference between the Shop_Product::find_products() and Shop_Category::list_products() functions. Product search is not a single request, but a result of multiple different requests and therefore some useful methods as post-pagination are not applicable. That is why working with the find_products() method result is not that funny.

I have a suggestion. Do not use AJAX on the search page. The shop:search action expects parameters to be passed through the GET array, so it is much simpler to reload the page instead of using any AJAX handlers. For example, you can add the Records Per Page selector to your Search form:

<select onchange="$(this).getForm().submit()" name="records">
  <? for ($i = 10; $i <= 100; $i = $i+10): ?>
     <option value="<?= $i ?>" <?= option_state($records, $i) ?>><?= $i ?></option>
   <? endfor ?>
</select>


When you choose an item in the drop-down, the page reloads and the shop:search action can read the updated "records" parameter from the GET array.

Thanks

#3 User is offline   infradawn 

  • Member
  • PipPipPip
  • Group: Members
  • Posts: 85
  • Joined: 19-April 10

Posted 30 August 2010 - 05:07 AM

Hi Aleksey,

Well, the search param processing part of this is now solved. All query params that need to persist are saved to Visitor Preferences in the partial and the search is re-run whenever any param changes. The trick was to make those params available to the partial so they could be saved. Thanks for the heads-up on GET.

A search URL might look like: ../store/search/?query=AnyText&sort=name&view=list&records=10. And the partial picks up the custom query params like this:

<?
  /* Get custom search values from GET or from Visitor Preferences */
  $sort = Phpr::$request->getField('sort', Cms_VisitorPreferences::get('search_sort', 'name'));
  $view = Phpr::$request->getField('view', Cms_VisitorPreferences::get('search_view', 'list'));
?>


The last piece is how to sort the search results. Any ideas? :D

Thanks

iD
0

#4 User is offline   Aleksey 

  • Co-Founder
  • Group: +Administrators
  • Posts: 3,330
  • Joined: 31-October 09

Posted 30 August 2010 - 02:41 PM

Hi, iD!

Search results sorting is not supported yet. As I said above, search is a complex function, which involves more than a single query. It makes the search result non-uniform and does not allow to apply sorting to the whole search result on the SQL level. However I have some ideas how we can implement a post-query sorting. I added a task to our to-do list. Thanks.

Aleksey

#5 User is offline   Eric 

  • Developer
  • Group: +Administrators
  • Posts: 1,201
  • Joined: 04-August 10

Posted 31 August 2010 - 10:30 AM

Quote

The last piece is how to sort the search results. Any ideas? :D


Until the feature is implemented, one idea would be to sort the products list (Db_DataCollection) before render_partial(), like so:

<?
$sort = 'name';

function sort_search_results($current, $previous)
{
  global $sort;
 
  if($current->$sort == $previous->$sort)
    return 0;
 
  return $current->$sort < $previous->$sort ? -1 : 1;
}

$items = $products->objectArray;
usort($items, "sort_search_results");
$products->objectArray = $items;
?>


and of course if you use PHP 5.3, you have access to closures:

<?
$sort = 'name';

$items = $products->objectArray;

usort($items, function($current, $previous) use($sort)
{
  if($current->$sort == $previous->$sort)
    return 0;
 
  return $current->$sort < $previous->$sort ? -1 : 1;
});

$products->objectArray = $items;
?>


You may want to check $products->count beforehand, but you get the idea.. Hope this is somewhat helpful.

#6 User is offline   Aleksey 

  • Co-Founder
  • Group: +Administrators
  • Posts: 3,330
  • Joined: 31-October 09

Posted 31 August 2010 - 01:52 PM

Hi, iD!

Great, thank you for the suggestion! :-)

#7 User is offline   Aleksey 

  • Co-Founder
  • Group: +Administrators
  • Posts: 3,330
  • Joined: 31-October 09

Posted 31 August 2010 - 02:06 PM

Hi, iD!

I just realized that the approach you offered will work correctly if you use pagination on the search page. The $products collection (created by the shop:search action) contains only a single page of products. So, if you sort this collection, you will only sort products within a single page. It does not make much sense. Sorting should work inside the Shop_Product::find_products() method, before splitting products to pages. Sorry.

#8 User is offline   Eric 

  • Developer
  • Group: +Administrators
  • Posts: 1,201
  • Joined: 04-August 10

Posted 31 August 2010 - 02:28 PM

Oh, I hadn't thought of that Aleksey. It makes sense, you could set $records param to something like 9999, sort as suggested, then slice out your own PHP pagination from $items, however that would potentially be a considerably heavy SQL query for every page, and thus would only make sense on a single page using DOM pagination. Perhaps specific caching would also help.

These are temporary suggestions for iD, not LS. :)

#9 User is offline   Aleksey 

  • Co-Founder
  • Group: +Administrators
  • Posts: 3,330
  • Joined: 31-October 09

Posted 31 August 2010 - 02:40 PM

Oh, sorry, guys. I didn't notice Frosty and I was thinking here are no people but iD ;-)

Thanks

#10 User is offline   infradawn 

  • Member
  • PipPipPip
  • Group: Members
  • Posts: 85
  • Joined: 19-April 10

Posted 01 September 2010 - 04:37 AM

Aleksey & frosty,

As a practical consideration, there has to be a limit on search results or you create vulnerabilities like DOS. So, I have no difficulty limiting the product search to say 100 items, with feedback to the customer if further matching items exist that were not displayed (for example using a new param $max_results=100 and an overflow flag would also be nice :)), perhaps with a recommendation to use more targeted search keywords.

Just before leaving performance vulnerabilities - Should there be a limit to the number of searches permitted from a single session in a specific time window?

Anyway, back to sorting. As you say, the difficulty is that $products doesn't contain the full list of results so there's no opportunity to sort across all results unless paginated for display on a single page. I know that $products confused the hell out of me until I realized what it represented.

With something like $max_results limiting the number of results perhaps $products can afford to contain the full results list, and sorting now becomes feasible. Maybe that's what you're considering in 'I have some ideas how we can implement a post-query sorting'.

Thanks

iD
0

#11 User is offline   Aleksey 

  • Co-Founder
  • Group: +Administrators
  • Posts: 3,330
  • Joined: 31-October 09

Posted 01 September 2010 - 01:44 PM

Hi, iD!

Thank you for the security ideas. I added them to the to-do list. We will implement them along with the search result sorting.

#12 User is offline   Finster 

  • Member
  • Group: Members
  • Posts: 12
  • Joined: 26-February 10

Posted 11 April 2011 - 07:34 AM

View PostAleksey, on 01 September 2010 - 01:44 PM, said:

Hi, iD!

Thank you for the security ideas. I added them to the to-do list. We will implement them along with the search result sorting.


Sorry to resurrect such an old thread... Just wondering if this was still being worked on and how far off it might be?

Thanks!
0

#13 User is offline   Aleksey 

  • Co-Founder
  • Group: +Administrators
  • Posts: 3,330
  • Joined: 31-October 09

Posted 11 April 2011 - 04:10 PM

View PostFinster, on 11 April 2011 - 07:34 AM, said:

Sorry to resurrect such an old thread... Just wondering if this was still being worked on and how far off it might be?

Thanks!


Hi!

The task is in the Roadmap, but we haven't implemented it yet, sorry.

Which product parameters you want to use for sorting? Product name, price, which else? It is not possible to use any product field for sorting the search result, because of the nature of the search function, so we need to know which fields you expect be implemented.

Thank you

#14 User is offline   Finster 

  • Member
  • Group: Members
  • Posts: 12
  • Joined: 26-February 10

Posted 12 April 2011 - 05:52 AM

View PostAleksey, on 11 April 2011 - 04:10 PM, said:

Hi!

The task is in the Roadmap, but we haven't implemented it yet, sorry.

Which product parameters you want to use for sorting? Product name, price, which else? It is not possible to use any product field for sorting the search result, because of the nature of the search function, so we need to know which fields you expect be implemented.

Thank you


Name and Price are the main ones. Rating and Number Sold could be useful in some scenarios.
0

#15 User is offline   infradawn 

  • Member
  • PipPipPip
  • Group: Members
  • Posts: 85
  • Joined: 19-April 10

Posted 09 May 2011 - 05:59 AM

Hi Aleksey,

To maintain consistency of the user experience the options for manipulating the display of products should be the same whether it's a list of category products or search results. There's no difference from the customer perspective; this is JBOP (Just a Bunch Of Products - to borrow from storage terminology). The customer wants to be presented with a uniform set of display controls that operate predictably and consistently however the product list is generated.

So if, for example, I have sort by: Name, Price, Date Introduced, Ascending/Descending, etc, on all my category product pages than that's what I want, and it's what the customer expects, on the search result pages. Because to do otherwise creates inconsistency and risks frustrating your customer with an environment that they begin not to trust.

I guess for others it's not a biggy, either that or folk choose to implement the behavior outside of the core offering. But I'd still like to see it come in the box :-)


iD

Diverted and (mostly) silent but still impressed.
0

#16 User is offline   Aleksey 

  • Co-Founder
  • Group: +Administrators
  • Posts: 3,330
  • Joined: 31-October 09

Posted 09 May 2011 - 02:05 PM

Hi iD!

I completely agree with you. We will improve the search function. Just cannot do everything at the same time. ;-)

Thanks

#17 User is offline   Aleksey 

  • Co-Founder
  • Group: +Administrators
  • Posts: 3,330
  • Joined: 31-October 09

Posted 18 May 2011 - 10:04 PM

Hi guys,

We just published an update which improves the search functions:

1. The Shop_Product::find_products() method now supports the sorting option. Also the sorting parameter support has been added to the shop:search CMS action, so you can now implement the Sorting drop-down menu on the product search page.
2. Added the SEARCH_MAX_RECORDS configuration parameter, which allows to limit the number of products returned by the shop:search action.
3. Shop_Product::find_products() method has been optimized to use fewer database queries.

Thank you for your input!

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users