It seems from the tests I have been doing that content gets loaded by the order in which regions (or rows, I'm not sure) are created. I would like content to be loaded using a top-down left-right approach. Is it possible somehow?

In case you are wondering why would I need that, I am using Views and to create blocks of content listings.

Comments

sharpbites’s picture

I have just noticed the order doesn't depend on when rows or regions are created either.

pazzypunk’s picture

I have this question too.

sharpbites’s picture

Version: 6.x-3.8 » 6.x-3.9

I didn't notice the first message got broken.
What I was trying to say is that I wanted to use Views in combination with Views exclude previous [1] to create blocks of content listings, and I would like blocks appearing higher in the panel to execute first.

[1] http://drupal.org/project/views_exclude_previous

paranojik’s picture

Title: Is it possible to control the order in which content is loaded? » Allow the possibility to control the order in which content is rendered
Version: 6.x-3.9 » 7.x-3.x-dev
Category: support » feature
StatusFileSize
new22.29 KB
new5.94 KB

We had exactly the same use case as in #3. As we discovered there is currently no mechanism that would allow us to set the order in which pane content is rendered. Rendering doesn't even follow the visual layout. but the order in which panes were entered into the database.
The attached patch allows you to set pane weights and orders the panes in ascending weight order before rendering.

sharpbites’s picture

Thank you paranojik!
If we need this again I use your patch and update here the results.

merlinofchaos’s picture

Status: Active » Closed (won't fix)

Content already has a 'render last' or 'render first' property, which you can use to ensure that content that needs to know what's already rendered can do so. It seemed unlikely that fine grained weighting of render order would ever be needed, so these 2 settings were deemed enough.

Controlling render order is so rarely needed that I really don't believe it should be in the UI. That simply adds confusion to an already confusing interface.

These two flags will have to be enough.

paranojik’s picture

Can we at least introduce a new hook, so this could still be possible to achieve.

paranojik’s picture

Status: Closed (won't fix) » Active

Can we disscuss the above mentioned possibility?

Letharion’s picture

What is the use-case for controlling the render order? Since it is currently considered so rare, I don't really see why there should be a hook either. While less of a burden, that would still add to code complexity.
I believe that this is going to be a case where you should just write a ctools plugin to wrap the content you need to control the order for.
But since you want to discuss paranojik, please give a few examples of use-cases.

paranojik’s picture

The use-case was mentioned in #3. I would like to use panels to layout a number of blocks (e.g. in a two column layout). Each block displays (let's say) 10 articles with a specified tag (taxonomy term) ordered by post date. Because of the nature of tagging, articles would usually appear in several blocks so I use Views in combination with a similar mechanism mentioned in #3 which is a view filter that modifies subsequent queries to exclude the articles that were already loaded (by a query for the previously loaded articles block).

Now, if I insert blocks A, B, C and D (in that order) on a panel, they get their unique database IDs -pid (let's say they are 1 for A, 2 for B, 3 for C and 4 for D). When Panels prepares content for display it loads these block in that order (in order of increasing pids).
So I have the following layout:
A | B
C | D
Everything is fine now. Block A loads before block B (and C and D), so it contains the newest articles. Let's say block A and C share 1 article (because it's tagged so). When block C loads and the view for block C fires it's query, we have the information about the articles loaded in A, so we can exclude them. The article which would (without the use of this extra filter) appear in block A and C, now only appears in A.

Let's reorder those blocks:
D | C
B | A
What one would expect to happen is that now block C would contain the most recent articles, but because these blocks are rendered in the order of their increasing pids, the result is exactly the same as in the previous example.

If Panels don't provide a way to define the order in which content is rendered this kind of functionality is very hard to achieve. The Panels admin interface is über-powerful and also very very visual (you can define all kinds of layouts, insert all kind of content, preview,...), but from this perspective also somewhat misleading.

Letharion’s picture

So that's one usecase, are the any others? Implementing this for solving a single use-case, still doesn't seem right. If I had just this use-case, I would pass the "previously used" taxonomies on to the next pane, as an argument that the View used for excluding.

And I think that's the main argument against this, we have a general and flexible system for solving a great number of use-cases, and in my opinion, this one too. It then seems strange to implement additional functionality, that is so specific.

merlinofchaos’s picture

Status: Active » Closed (won't fix)

I agree, the proper way to handle this is with a context object. If you can do it with a single view then everything probably just works as if; if not you might need something custom, but it sounds like you've got some custom stuff going on anyway.

osopolar’s picture

Status: Closed (won't fix) » Active

I have a Search API view and use the Facets API blocks. The view needs to be executed first, but currently the blocks are rendered first. So I'd like to use 'render first' for the view or 'render last' for the blocks. But as it is plugin based I can't use this options.

Is this just another usecase? Or is there a workaround - I use a custom layout plugin, changing the order in the layout-lugin-name.inc seems to not have an impact to the render order.

merlinofchaos’s picture

Status: Active » Fixed

Perhaps hook_ctools_plugins_post_alter() will allow you to add 'render last' to the facet API blocks.

If they're truly blocks and not actual content panes, this is more readily done with hook_ctools_block_info for the module that owns the block. See the bottom of ctools/plugins/content_types/block/block.inc for all of the versions of this done for core. Possibly search api or something should already be doing this for those blocks so that they can always render last, which they almost certainly should.

osopolar’s picture

Status: Fixed » Needs work

Thank you merlinofchaos for your help. But it does not work.

the logic for render_last is in panels_renderer_standard::prepare_panes(), right? There you have a $content_type = ctools_get_content_type($pane->type); and then you look into $content_type['render last']. But this is just the content-type plugin info and won't be influenced by the ctools_block_info. Is it possible to change prepare_panes to reflect the block info?

/**
 * Implements hook_ctools_block_info().
 * 
 * Changes the ctools content-type plugin settings of the facet api
 * blocks (i.e. used in pannels).
 */
function facetapi_ctools_block_info($module, $delta, &$info) {
  $info['icon'] = 'icon_core_searchform.png';
  $info['category'] = t('Miscellaneous');
  $info['render last'] = TRUE;
}

Your first hint with hook_ctools_plugin_post_alter() works, but I don't like it. Facetapi uses real blocks. So I have to change the behavior for all blocks to render last. If another module needs to render all blocks first there will be a conflict. I would like to see the code in facetapi, but I won't recommend facetapi to implement this behavior:

/**
 * Implements hook_ctools_plugin_post_alter().
 */
function facetapi_ctools_plugin_post_alter(&$plugin, &$info) {
  // Workaround to render facet blocks last, this actually set all block
  // to render last.
  if ('content_types' == $plugin['plugin type'] && 'block' == $plugin['name']) {
    $plugin['render last'] = TRUE;
  }
}
Letharion’s picture

Category: feature » support
Status: Needs work » Active

this has turned into a support request, and there is no patch, so this is active.

bigsyke’s picture

This may also have something to do with the order you add content to panels. I redid my layout and all my Facets disappeared, or went off a different search pane.

Edit: I see that this was already stated.

danielnolde’s picture

The original request is very valid and points to a very common problem, which is:

"ensure that pane content A is exectued after pane content B because B depends on A's results".

May i suggest panels maintainers try to be a bit more open to this request, since there have been already two quite common use cases been stated:

  • Being able to exclude already showed content on panels generated pages to prevent duplicate outpu
  • Being able to build facetted search pages based on panels

For this problem, there should be a solution. If it's accessible programmatically, its probably okay for many developers present in this discussion, but if there's a simple solution which can be made accessible to mere site builders, that way should be preferred, so, for example, a sitebuilder can actually build a facetted search result page based on panels without being forced to code. Introducing a hook to reordering (or probably generally altering) panel content before rendering should be simple to include. Introducing a render weight doesn't sound too complex, either. Don't you think? Again: The problem is a quite common one with several use cases often encountered by developers and power users.

If maintainers still won't accept peoples help to code this kind of solution into panels (i'd love to help/do it!), what would be the suggested way to solve the general problem or the specific use cases? If a hook or a weight is still out of question for maintainers, then please help us and tell us:

How can "render last" be injected programmatically to a specific block or view placed in a panel?

Above examples allow only for a whole class of ctools plugins (like "block") to be "rendered last", but not for individual instances of that class (like a particular block in a particular panel), or am im wrong here?

Again: A hook or weight would be right way to solve the problem.

danielnolde’s picture

Category: support » feature

Merlin and others.

The pane-type-wise "first/normal/last" rendering is _way_ too crude and to be honest seems like a uber-ugly workaround for something that should be handled more flexible and cleanly. Several people here need this finer grained control over pane rendering order and gave several good use cases. I am willing to implement that simple and very flexible hook based solution, so please consider this.

So: if i extend class panels_renderer_standard method prepare_panes to include a hook for rearranging pane render order (between lines 253 and 254), would that get considered for inclusion in panels dev branch?

cheers,

daniel

sdboyer’s picture

@danielnolde - first/normal/last is a crude tool, but it was adequate for most simpler cases, and IS adequate for the case you cite in #18:

ensure that pane content A is exectued after pane content B because B depends on A's results

as the 'render last' capability allows you to ensure that B is placed after A perfectly well. having the 'first' option as well gives you another layer through which you can control this. ideally, as merlin pointed out in #12, this would be handled by a context object, but that's not always going to be the case.

when i rewrote the rendering system into plugins, it did occur to me that we might want to provide more granular control over rendering order (as it is fairly arbitrary at the moment), but we didn't have pressing use cases at the time. without a pressing use case, and given the difficulty of implementing any kind of UI for controlling this behavior, i left it be. so while there are cases for this, it remains tricky, because of your question:

How can "render last" be injected programmatically to a specific block or view placed in a panel?

changing rendering order at the level of the plugin is easy, but targeting a specific pane instance within a specific panel is tough, because most of the identifying information you would need to know the panel & pane instance is gone by the time you make it into panels_renderer_standard::prepare(). for the most part, you'll have a display id and a pane id. and hardcoding renders the panel non-exportable. there are ways to do it, but it'd be mostly tricks.

but i would accept a patch that met the following criteria:

  • keeps the contract implied by the 'render {first,last,} properties intact. a hook-based approach is free to allow them to be overridden, but the normal non-altered datastructure must respect these settings.
  • if you should choose to build a UI, does not *require* any additional engagement by users for the current functionality to be achieved (where render order is determined by the order panes were added to the db).
  • does not create a new renderer plugin. this is not something worthy of shipping an additional renderer in panels core.
  • does not implicitly create a requirement for panels applications (panelizer, panel nodes, panel pages/page manager) to pass more contextual information in for use in any kind of hook. the info in core panels is stripped-down, but it's what you get.
danielnolde’s picture

Hey Sam,

the criteria you define seem fine to me and exactly what i was planning anyway.

#context info: If only display id and a pane id are available as context information, that should suffice for most use cases. An implementation of that hook would have to look up more detailed information in the db with those ids, which is not the best way but not bad either.

#render-order:
Add-order: Sadly, i had some cases, where the "add order" which of course i used to define initial render order, was shuffled when exporting/using an panel via feature (i don't know how this happened, but that's what i observed).
Sadly, use case #18 is _not_ solvable with first/last-mechanism, since this is applicable only by type, not by instance, and all the panes that have to be ordered ni a certain way are both of the same type. Only way to solve this with first/last would be to custom-duplicate a ctools content type, which seems to be the utterly wrong approach to achieve this goal/use-case <;)

So, great: I'll care for a simple but flexible hook-based solution and i'll prepare a patch for this - Thanks, Sam for the input and cooperation!

paranojik’s picture

StatusFileSize
new992 bytes

This, is my first attempt. It's very simple and respects all points stated in #20. I'm just not sure about passing the whole display_renderer object as a parameter to the hook. Please give some advice on that.

paranojik’s picture

Anybody got a chance to look at this?

das-peter’s picture

Status: Active » Needs review
+++ b/plugins/display_renderers/panels_renderer_standard.class.php
@@ -259,6 +259,10 @@ class panels_renderer_standard {
+
+    // Allow other modules the alter the prepared panes array
+    drupal_alter('panels_panes_prepared', $this->prepared['panes'], $this);

Only thing I found: Inline comments require a dot at the end of the comment.
Hint: If you've a patch you'd like people take a look into - set the issue status to "needs review" :)

I'd say this is pretty straight forward and provides the necessary preconditions to achieve the goal with a contrib module.

kars-t’s picture

Except the missing "." the patch seems clean and a nice addition.

paranojik’s picture

StatusFileSize
new993 bytes

Added missing dot :). Patch still applies.

kars-t’s picture

Status: Needs review » Reviewed & tested by the community

Okay I say this would be a great addition and RTBC it.

merlinofchaos’s picture

Status: Reviewed & tested by the community » Fixed

Committed and pushed.

Status: Fixed » Closed (fixed)

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

lorenx’s picture

sorry to reopen this issue but... is it possible that the patch provided here isn't in the 7.x-3.3+41-dev release yet?
thank you.

kopeboy’s picture

Version: 7.x-3.x-dev » 7.x-3.4
Issue summary: View changes
Status: Closed (fixed) » Needs review

Is this included in a stable release? How to know it? (Sorry for reopening)

Came here because I can't get Facets to work in Panels

The last submitted patch, 4: panels-pane-rendering-order.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 26: 1018420-alter_pane_rendering_order-26.patch, failed testing.

The last submitted patch, 22: 1018420-alter_pane_rendering_order-22.patch, failed testing.

Andreas Radloff’s picture

Status: Needs work » Closed (fixed)

For anyone who wants to render panes in the order they are displayed (or rather, the order regions are defined) in the layout, this is how you can do it using the drupal_alter hook implemented in this issue and present in the 7.x-3.4 version at least:

/**
 * Sort the array of panes to be rendered in the order they are defined in the layout
 *
 * @param $vars
 * @param $context
 */
function yourtheme_panels_panes_prepared_alter(&$vars, $context) {
  $region_weight = $context->plugins['layout']['regions'];
  $index = 0;

  foreach($region_weight as $key => $value) {
    $region_weight[$key] = $index * 100;
    $index++;
  }

  foreach($vars as $pid => $pane) {
    $vars[$pid]->render_weight = $region_weight[$pane->panel] + $pane->position;
  }

  uasort($vars, function ($item1, $item2) {
    return $item1->render_weight - $item2->render_weight;
  });

}

Thought I could post it here as an usage example. Closing since it works.

proteo’s picture

@Andreas, your function works wonderfully, it saved my day. Many thanks!