The block weight set in a pattern is lost when the pattern runs. In fact, only weight -1, 0 and 1 are working, the rest is discarded.
This is because when a block is created, two forms are retrieved and executed: block_add_block_form, and block_admin_display_form. The first form creates or updates block properties, but the region and weight are set in the second form.
The second form (block_admin_display_form) generally displays all the blocks, and allows the user to change the order of the blocks (or change the weights if JS is not enabled). The problem is that, when generating the form, the range of allowed weight (the delta for the field type weight) is calculated from the number of blocks displayed in the form:
$weight_delta = round(count($blocks) / 2);
// [...]
$form[$key]['weight'] = array(
'#type' => 'weight',
'#default_value' => $block['weight'],
'#delta' => $weight_delta,
);
Now, when pattern, for each block, calls (block_admin_display_form), there is only one block in the form, which result in the delta for the field weight to be 1. As a consequence, the allowed weights for a block created/updated by a pattern are: -1, 0 or 1.
The fix has to be made in Drupal core... (unless I am mistaken). Basically, since we almost all the time have several blocks on the page, the only time where we have only one block is when we call the form programmatically, such as pattern does. So we can consider that if the number of blocks in the form is 1, it is because we are generating the form programmatically, and therefore we need to force the weight delta to be an arbitrary number, greater than the potential number of blocks in the system. If the number of blocks is already greater than 1, it is business as usual, we change nothing.
So the patch simply does this: if the number of blocks is 1, we assume that there may be more blocks existing, or to be created, and we set the weight delta to be 999:
$weight_delta = round(count($blocks) / 2);
// [...]
$form[$key]['weight'] = array(
'#type' => 'weight',
'#default_value' => $block['weight'],
'#delta' => ($weight_delta === (float) 1 ? 999 : $weight_delta),
);
This allows us to create blocks in a pattern, and set the weight precisely. Also, since the weight range does not rely on the number of blocks when generating the form programmatically, we can add dozens of blocks with patterns, setting their weight independently of the number of blocks.
| Comment | File | Size | Author |
|---|---|---|---|
| block_weight_with_pattern.patch | 508 bytes | verot |
Comments
Comment #1
vaish commentedHi verot,
Thanks for looking into this. This limitation has been added in D6 sometimes around version 6.4 if I remember correctly. However, your patch is actually supposed to go to block module's issue queue, not patterns.
In my recent test, delta doesn't get reset to 1 always. It gets changed to fit within the delta range that, as you described, depends on the total number of blocks but it preserves desired order of blocks. In other words, I was able to position my block where I wanted. Are you experiencing problems in ordering blocks?
Comment #2
dman commentedIt's still impossible to meaningfully set a block weight.
My (PHP pattern) here:
Always ends up submitting weight=-1.
I traced the code and found the same conclusion as verot. (a block admin form with only one block only allows you to set -1, 0, 1)
But looking at the huge magic within patterns_sync_form_values() - where the submitted select option gets converted to a 'valid' option got scary.
I'm tempted to make block positioning a special code case, rather than get messier with the form manipulation that happens. Weights (and relative weight values) have gone funny in Drupal nowadays, but I still want my pattern to be able to at least say 'place a block below any other existing ones'.
Sorry, no fix from me yet.