Currently, when you add a facet block, it is shown on every page.
We should add a setting in the UI so you can choose per facet if the facet is shown on all pages or if it's shown only on the pages that display the facet source. The tricky part is that a view can have different modi, and we need to support them all.

#1 Only show block when the page is equal to the views page.
#2 Only show block when the views block will be rendered at the current page.

In this issue, we're also adding the possiblity for views to be rendered in blocks and to have facets built on that facet source.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

borisson_ created an issue. See original summary.

borisson_’s picture

Status: Active » Needs review
FileSize
1.61 KB

This makes me sad; but it works.

Nick_vh’s picture

I had a conversation with effulgentsia and he had some very interesting thoughts. Some of them aligned with what we were thinking when talking to each other.

His first thought is the one inline with what we were thinking, iterating over the block list and see if it is present.

you can look at BlockPageVariant to see how it figures out what blocks to render, which is to call $this->blockRepository->getVisibleBlocksPerRegion().
So potentially, your facet block can also ask the block repository for that, and then iterate the results to determine if the Views block you're interested is in that list.
That however would couple your facet block to an assumption about how the page is being rendered (i.e., via that query to blockRepository), which is an assumption that something like Panels might break. tim.plunkett might have more insight on that.

His second thought is, in my opinion, way nicer.

if you know the $block entity for the Views block instance you care about, you can just call $block->access('view') on it rather than asking BlockRepository to do so for all the blocks you're not interested in. That access check returns FALSE if there's any visibility condition preventing the block from showing on the current page or rather, in the current context. Again though, $block "entities" is a block.module concept, so Panels might require a different mechanism for this.

If we can pass the block as a context object to our facet block, we can call that function and directly see if we need to show it or not. This allows us to execute this at runtime and does not require a whole lot of coding. We can have similar mechanisms in place for other types of view modes, if they exists. When we get to a PanelViewFacetSourceManager and hence, the generated plugins from them, we can figure out how panels discovered how to show a certain view and act on it.

Hopefully that helps us a bit further?

Nick_vh’s picture

Issue summary: View changes
Nick_vh’s picture

We solved the problem of the views page (See borisson_'s patch) but we still need work in figuring out if the view, in block modus, will be rendered somewhere on the page. For this, we need to send the views block as a context object. This might not be as hard as it sounds. We already pass the view along, so we could most likely also send the $block->access('view') method?

StryKaizer’s picture

@borisson_: the code in #2 will always trigger when the current page is a page view (e.g. frontpage)
If you have a search-index in a block, it will always be hidden because of this.
We need to find out first if the current facet has a page view as facetsource, and only then trigger your code.

StryKaizer’s picture

Attached is a reworked version from #2 where I moved the logic into the datasource (as this should be implemented by the datasource plugin instead of on a global level)

I also refactored the facet interface a bit, making getDataSource return an instance of the datasource plugin.
If you only need the datasource id, you can still do getDataSourceId().
I looked into the Blocks module for this, and they seem to do it like that too.

Remarks from #6 are not addressed yet, but can now live in the datasource plugin.

borisson_’s picture

FileSize
2.75 KB
9.66 KB

Fixed a couple of small nitpicks in the patch.

@Nick_vh explained some things to me and I think I might understand where we should be going with this.

We should split up the functionality for pages and blocks into different facet sources. The current facetSource should be renamed to a base class (SearchApiViewsDeriverBase) and there should be 2 classes implementing that.
SearchApiViewsPageDeriver and SearchApiViewsBlockDeriver. Those 2 new classes should each implement ::isBeingRendered, that way we can split up the support for blocks to a followup.

Getting in page support for views can be based upon this patch.

I'm not sure about ::isBeingRendered as a method name though, I suggest ::isRenderedInCurrentRequest as a more verbose option.

StryKaizer’s picture

We should split up the functionality for pages and blocks into different facet sources. The current facetSource should be renamed to a base class (SearchApiViewsDeriverBase) and there should be 2 classes implementing that.

Yup, that sounds like a good idea!

I'm not sure about ::isBeingRendered as a method name though, I suggest ::isRenderedInCurrentRequest as a more verbose option.

isRenderedInCurrentRequest sounds good.

borisson_’s picture

FileSize
7.36 KB
15.36 KB

What I explained in #8 I did in the attached patch. Still need to rename that method though, coming up.

borisson_’s picture

FileSize
2.19 KB
15.41 KB

As promised in #10.

borisson_’s picture

FileSize
1.8 KB
17.2 KB

Renamed the facet_source to facet_source_id in the schema and integration test as well.

StryKaizer’s picture

WIP

Started from #8 + #12

Current patch is not rendering results anymore atm. I renamed the search_api_view id to search_api_views_page to make the plugin system use the correct plugin.

borisson_’s picture

FileSize
754 bytes

The reason nothing rendered anymore is because this needs a patch to search api. This feels wrong but it makes results appear again.

borisson_’s picture

FileSize
36.81 KB
4.05 KB

Updated the patch in #13, added a config setting and changed the UI / FacetEntity en FacetInterface to make sure that is not just a hardcoded value but that this is actually something that can be configured.

StryKaizer’s picture

FileSize
37.05 KB
7.13 KB

#15 with a bit of variable/documentation changes attached

  • StryKaizer committed 9453ca9 on 8.x-1.x
    Issue #2598902 by borisson_, StryKaizer, Nick_vh: Add 'show only on a...
  • StryKaizer committed ca7738b on 8.x-1.x
    Issue #2598902 by borisson_, StryKaizer, Nick_vh: Add 'show only on a...

Wim Leers’s picture

So, this is a quite interesting problem. Because blocks in theory are meant to be independent of the other blocks on the page. Otherwise you can't render them independently, in parallel or via ESI.

I think I agree part of the solution is to have this "Facet-for-Views-block"-block require a "Views block" Context. But… that would mean that the Views block must expose/emit another context. Which is where we enter a catch-22, enforced by the earlier mentioned requirement that blocks can be rendered independently: the visible blocks are determined by loading all the contexts, and then checking if the visibility conditions are met (see \Drupal\block\BlockAccessControlHandler::checkAccess()). I think it's not possible for that set of run-time contexts to change during a request (i.e. before the Views block is rendered, this "views block is visible" context would be FALSE, and after it is rendered, it'd be TRUE), because then execution order matters, and hence parallelism is broken.

I think you need @eclipsegc and @tim.plunkett's input here.

Nick_vh’s picture

What I *think* we should do is the following. We add support for having a facetsource from a block that was created by views (so not the display mode). Because this block then becomes the facet source, we can pass it as context. We can then execute a $block->access() check to see if the block where the view is in would be shown and if not, we stop rendering the facet and in effect we also don't try to execute the view to get our results. We can then continue to execute our empty behavior for the facet block or whatever we like with this state. Most likely we will need to use the exact same approach when we want to add support for panel pane's with any kind of search api view in it. The pane will be the facet source, not what is in it.

Current facet_source plugins:

  • SearchApiViewsPage.php
  • SearchApiViewsPageDeriver.php

New facet_source plugins:

  • BlockSearchApiViewsBlock.php
  • BlockSearchApiViewsBlockDeriver.php

It would create a facet source for every block defined in the blocks structure that is part of a Search Api Views object that has the block display mode.

Some remarks from @wimleers:
Just be aware then that it's possible to have different "empty" behavior for the Views block and the Facet block: it's possible to hide the Views block and have the Facet block say "no facets available", which may be confusing. I think you may want to have some `hook_requirements()` checks that does sanity checks in those areas to prevent those kinds of misconfigurations.
(or at least warn people)

For reference I include the full conversation with Wim.

wimleers [10:48 AM]
@nick.veenhof: It's an excellent question, one to which we should document the answer, because it'll come up more often

nick.veenhof [10:49 AM]
What I think we will do is read out the visibility settings of the block + the access level of the view as we have that as a context to determine if it can be shown

wimleers [10:49 AM]
@nick.veenhof: But I believe what I wrote captures why this is so difficult: the system is specifically designed to NOT do something like this AFAIK.

nick.veenhof [10:49 AM]
it might not be 100% accurate, but at least it won’t depend at run-time on something somewhere else

wimleers [10:49 AM]
@nick.veenhof: So then it still breaks if the view has an empty result set?

nick.veenhof [10:50 AM]
if the view has an empty result set, the facet will also be empty, and then it triggers the empty behavior of the facet which is show nothing or show empty text

wimleers [10:50 AM]
@nick.veenhof: "visibility + access" -> no need: calling the views block's `access()` method already checks both.

nick.veenhof [10:50 AM]
ah, cool

wimleers [10:51 AM]
@nick.veenhof: Just be ware then that it's possible to have different "empty" behavior for the Views block and the Facet block: it's possible to hide the Views block and have the Facet block say "no facets available", which may be confusing. I think you may want to have some `hook_requirements()` checks that does sanity checks in those areas to prevent those kinds of misconfigurations.

wimleers [10:51 AM]
(or at least warn people)

nick.veenhof [10:52 AM]
@wimleers: true - but at least it doesn’t depend on something in the render pipeline then

nick.veenhof [10:54 AM]
wimleers: ok if I copy/paste this discussion also in that issue?

wimleers [10:59 AM]
@nick.veenhof: of course

Nick_vh’s picture

We could, to avoid the requirements issue (where empty behavior of a view is doing different things compared to an empty facet) execute the block as a whole. The view will be cached and we will need to execute the view anyway to get the results of the search. We are already executing the view when the facet_source is a SearchApiViewsPage, so this is not too different compared to the block.

Thoughts?

borisson_’s picture

FileSize
14.41 KB

Attached patch adds block as a facet source in the backend, haven't tested it yet on the frontend but this is a start.

borisson_’s picture

FileSize
2.68 KB
14.55 KB

Attached patch has some more work put into it, but still doesn't work.

For some reason $facet_results = $results->getExtraData('search_api_facets'); in ::fillFacetsWithResults doesn't return any data.
When tracing this back to \Drupal\search_api_db\Plugin\search_api\backend\Database::search it seems that the call to $query->getOption('search_api_facets') returns null.

borisson_’s picture

Code cleanup + getting it to work.

borisson_’s picture

Title: Add 'show only on a page that contains the facet source' setting. » Add 'show only on a page that contains the facet source' setting and a second facetsource plugin to include view blocks
Issue summary: View changes
borisson_’s picture

FileSize
16.26 KB

This needed a reroll.

  • marthinal committed 2854b76 on 8.x-1.x
    #2598902 fixed 'show only on a page that contains the facet source' for...
marthinal’s picture

With the 'show only on a page that contains the facet source' option selected, facet blocks appear on multiple pages and not only when the facet source is visible. Fixed with my last patch + added integration tests.

borisson_’s picture

I reviewed my own patch. These remarks need to be resolved and then I'll be happy with the result.

  1. +++ b/src/FacetManager/DefaultFacetManager.php
    @@ -184,16 +184,14 @@ class DefaultFacetManager {
    -      if ($facet->getFacetSourceId() == $this->facetsource_id) {
    +      $fs = str_replace("search_api_views:", "", $this->facetsource_id);
    +      if (strpos($facet->getFacetSourceId(), $fs) !== FALSE) {
    

    As mentioned in yesterdays facetapi call, I'm very unhappy with this solution even though it works.

  2. +++ b/src/Form/FacetForm.php
    @@ -533,8 +533,12 @@ class FacetForm extends EntityForm {
    +    elseif ($type === 'block_search_api_views_block') {
    +      list(, , $view_id, $display) = explode(':', $facet_source);
    +    }
    

    This works but doesn't look very elegant.

  3. +++ b/src/Form/FacetForm.php
    @@ -533,8 +533,12 @@ class FacetForm extends EntityForm {
    +
    

    bogus empty line should be removed from patch.

  4. +++ b/src/Plugin/facetapi/facet_source/BlockSearchApiViewsBlock.php
    @@ -0,0 +1,259 @@
    + * Represents a facet source which represents the search api blocks..
    

    2 periods and the wording isn't correct (views blocks)

  5. +++ b/src/Plugin/facetapi/facet_source/BlockSearchApiViewsBlock.php
    @@ -0,0 +1,259 @@
    +  public function isRenderedInCurrentRequest() {
    

    This is currently the same implementation as the one for views pages (and that one was not correct).
    This needs more work.

  6. +++ b/src/Plugin/facetapi/facet_source/BlockSearchApiViewsBlockDeriver.php
    @@ -0,0 +1,151 @@
    +  public function compareDerivatives(array $a, array $b) {
    +    return strnatcasecmp($a['label'], $b['label']);
    +  }
    

    This is currently duplicated in every derivative; this could move to #2603572: Create a SearchApiBaseFacetSource class., I think

Wim Leers’s picture

I'm confused now. What did #27/#28 do, if this issue is still open?

borisson_’s picture

@Wim Leers: in this issue, we've done work on 2 separate but related issues:

1. Add a new facet source: BlockSearchApiViewsBlock
2. Make sure the 'show only on a page that contains the facet source' checkbox works.

#27 did the work for search api views that have a page display. That's a different facet source and needs another implementation of ::isRenderedInCurrentRequest.

borisson_’s picture

FileSize
4.27 KB
15.19 KB

- Moved #29.6 to #2603572: Create a SearchApiBaseFacetSource class.
- Fixed #29.3, .4, .5.

We still need to address #29.1 and #29.2 but I feel like those can be fixed in a followup.

  • marthinal committed b00ebc3 on 8.x-1.x
    #2598902 Use AND instead of OR when checking ids on...
marthinal’s picture

I've detected that if the 'display_id' is the same for 2 different views (I can reproduce with different backends or indexes for example) the facets will be visible in both views. To reproduce you can create 2 indexes with the same display id by default. Then you add 1 facet per facet source. Both views will display 2 facets.

This is fixed in my last patch

borisson_’s picture

FileSize
3.38 KB
13.04 KB

With #2608004: Add a base class for facet source derivers and #2603572: Create a SearchApiBaseFacetSource class. in, this reroll makes this patch somewhat smaller; hurray.

StryKaizer’s picture

Status: Needs review » Needs work

needs reroll

borisson_’s picture

Status: Needs work » Needs review
FileSize
12.74 KB
borisson_’s picture

FileSize
12.49 KB

Needed a reroll because of module name change.

borisson_’s picture

Version: » 8.x-1.x-dev
Status: Needs review » Fixed

We should probably split of the remaining work into a new issue if someone is still interested in this. For now we should probably not include views blocks yet.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.