Example #1
0
 /**
  * Shows a list of blocks that can be added to a theme's layout.
  *
  * @param \Symfony\Component\HttpFoundation\Request $request
  *   The current request.
  * @param string $theme
  *   Theme key of the block list.
  *
  * @return array
  *   A render array as expected by the renderer.
  */
 public function listBlocks(Request $request, $theme)
 {
     // Since modals do not render any other part of the page, we need to render
     // them manually as part of this listing.
     if ($request->query->get(MainContentViewSubscriber::WRAPPER_FORMAT) === 'drupal_modal') {
         $build['local_actions'] = $this->buildLocalActions();
     }
     $headers = [['data' => $this->t('Block')], ['data' => $this->t('Category')], ['data' => $this->t('Operations')]];
     // Only add blocks which work without any available context.
     $definitions = $this->blockManager->getDefinitionsForContexts();
     // Order by category, and then by admin label.
     $definitions = $this->blockManager->getSortedDefinitions($definitions);
     $region = $request->query->get('region');
     $rows = [];
     foreach ($definitions as $plugin_id => $plugin_definition) {
         $row = [];
         $row['title']['data'] = ['#markup' => $plugin_definition['admin_label'], '#prefix' => '<div class="block-filter-text-source">', '#suffix' => '</div>'];
         $row['category']['data'] = SafeMarkup::checkPlain($plugin_definition['category']);
         $links['add'] = ['title' => $this->t('Place block'), 'url' => Url::fromRoute('block.admin_add', ['plugin_id' => $plugin_id, 'theme' => $theme]), 'attributes' => ['class' => ['use-ajax'], 'data-dialog-type' => 'modal', 'data-dialog-options' => Json::encode(['width' => 700])]];
         if ($region) {
             $links['add']['query']['region'] = $region;
         }
         $row['operations']['data'] = ['#type' => 'operations', '#links' => $links];
         $rows[] = $row;
     }
     $build['#attached']['library'][] = 'block/drupal.block.admin';
     $build['filter'] = ['#type' => 'search', '#title' => $this->t('Filter'), '#title_display' => 'invisible', '#size' => 30, '#placeholder' => $this->t('Filter by block name'), '#attributes' => ['class' => ['block-filter-text'], 'data-element' => '.block-add-table', 'title' => $this->t('Enter a part of the block name to filter by.')]];
     $build['blocks'] = ['#type' => 'table', '#header' => $headers, '#rows' => $rows, '#empty' => $this->t('No blocks available.'), '#attributes' => ['class' => ['block-add-table']]];
     return $build;
 }
 /**
  * Retrieves suggestions for block category autocompletion.
  *
  * @param \Symfony\Component\HttpFoundation\Request $request
  *   The current request.
  *
  * @return \Symfony\Component\HttpFoundation\JsonResponse
  *   A JSON response containing autocomplete suggestions.
  */
 public function autocomplete(Request $request)
 {
     $typed_category = $request->query->get('q');
     $matches = array();
     foreach ($this->blockManager->getCategories() as $category) {
         if (stripos($category, $typed_category) === 0) {
             $matches[] = array('value' => $category, 'label' => SafeMarkup::checkPlain($category));
         }
     }
     return new JsonResponse($matches);
 }
 /**
  * Tests the block config schema for block plugins.
  */
 public function testBlockConfigSchema()
 {
     foreach ($this->blockManager->getDefinitions() as $block_id => $definition) {
         $id = strtolower($this->randomMachineName());
         $block = Block::create(array('id' => $id, 'theme' => 'stark', 'weight' => 00, 'status' => TRUE, 'region' => 'content', 'plugin' => $block_id, 'settings' => array('label' => $this->randomMachineName(), 'provider' => 'system', 'label_display' => FALSE), 'visibility' => array()));
         $block->save();
         $config = \Drupal::config("block.block.{$id}");
         $this->assertEqual($config->get('id'), $id);
         $this->assertConfigSchema($this->typedConfig, $config->getName(), $config->get());
     }
 }
Example #4
0
 /**
  * Get a list of blocks that can be placed in a mega menu.
  *
  * @param Request $request
  * @param MegaMenuInterface $mega_menu
  * @return array
  */
 public function blockLibrary(Request $request, MegaMenuInterface $mega_menu)
 {
     // Get the query parameters needed.
     $link = $request->query->get('link');
     $region = $request->query->get('region');
     // Only add blocks which work without any available context.
     $blocks = $this->blockManager->getDefinitionsForContexts($this->contextRepository->getAvailableContexts());
     // Order by category, and then by admin label.
     $blocks = $this->blockManager->getSortedDefinitions($blocks);
     $build['filter'] = ['#type' => 'search', '#title' => $this->t('Filter'), '#title_display' => 'invisible', '#size' => 30, '#placeholder' => $this->t('Filter by block name'), '#attributes' => ['class' => ['block-filter-text'], 'data-element' => '.block-add-table', 'title' => $this->t('Enter a part of the block name to filter by.')]];
     $headers = [$this->t('Block'), $this->t('Category'), $this->t('Operations')];
     $build['blocks'] = ['#type' => 'table', '#header' => $headers, '#rows' => [], '#empty' => $this->t('No blocks available.'), '#attributes' => ['class' => ['block-add-table']]];
     // Add each block definition to the table.
     foreach ($blocks as $block_id => $block) {
         $links = ['add' => ['title' => $this->t('Place block'), 'url' => Url::fromRoute('mega_menu.block_add', ['mega_menu' => $mega_menu->id(), 'block_id' => $block_id], ['query' => ['link' => $link, 'region' => $region]]), 'attributes' => ['class' => ['use-ajax'], 'data-dialog-type' => 'modal', 'data-dialog-options' => Json::encode(['width' => 700])]]];
         $build['blocks']['#rows'][] = ['title' => ['data' => ['#type' => 'inline_template', '#template' => '<div class="block-filter-text-source">{{ label }}</div>', '#context' => ['label' => $block['admin_label']]]], 'category' => ['data' => $block['category']], 'operations' => ['data' => ['#type' => 'operations', '#links' => $links]]];
     }
     return $build;
 }
Example #5
0
 /**
  * Tests the config start level and depth.
  */
 public function testConfigLevelDepth()
 {
     // Helper function to generate a configured block instance.
     $place_block = function ($level, $depth) {
         return $this->blockManager->createInstance('system_menu_block:' . $this->menu->id(), array('region' => 'footer', 'id' => 'machinename', 'theme' => 'stark', 'level' => $level, 'depth' => $depth));
     };
     // All the different block instances we're going to test.
     $blocks = ['all' => $place_block(1, 0), 'level_1_only' => $place_block(1, 1), 'level_2_only' => $place_block(2, 1), 'level_3_only' => $place_block(3, 1), 'level_1_and_beyond' => $place_block(1, 0), 'level_2_and_beyond' => $place_block(2, 0), 'level_3_and_beyond' => $place_block(3, 0)];
     // Scenario 1: test all block instances when there's no active trail.
     $no_active_trail_expectations = [];
     $no_active_trail_expectations['all'] = ['test.example1' => [], 'test.example2' => [], 'test.example5' => ['test.example7' => []], 'test.example6' => [], 'test.example8' => []];
     $no_active_trail_expectations['level_1_only'] = ['test.example1' => [], 'test.example2' => [], 'test.example5' => [], 'test.example6' => [], 'test.example8' => []];
     $no_active_trail_expectations['level_2_only'] = ['test.example7' => []];
     $no_active_trail_expectations['level_3_only'] = [];
     $no_active_trail_expectations['level_1_and_beyond'] = $no_active_trail_expectations['all'];
     $no_active_trail_expectations['level_2_and_beyond'] = $no_active_trail_expectations['level_2_only'];
     $no_active_trail_expectations['level_3_and_beyond'] = [];
     foreach ($blocks as $id => $block) {
         $block_build = $block->build();
         $items = isset($block_build['#items']) ? $block_build['#items'] : [];
         $this->assertIdentical($no_active_trail_expectations[$id], $this->convertBuiltMenuToIdTree($items), format_string('Menu block %id with no active trail renders the expected tree.', ['%id' => $id]));
     }
     // Scenario 2: test all block instances when there's an active trail.
     $route = $this->container->get('router.route_provider')->getRouteByName('example3');
     $request = new Request();
     $request->attributes->set(RouteObjectInterface::ROUTE_NAME, 'example3');
     $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, $route);
     $this->container->get('request_stack')->push($request);
     // \Drupal\Core\Menu\MenuActiveTrail uses the cache collector pattern, which
     // includes static caching. Since this second scenario simulates a second
     // request, we must also simulate it for the MenuActiveTrail service, by
     // clearing the cache collector's static cache.
     \Drupal::service('menu.active_trail')->clear();
     $active_trail_expectations = [];
     $active_trail_expectations['all'] = ['test.example1' => [], 'test.example2' => ['test.example3' => ['test.example4' => []]], 'test.example5' => ['test.example7' => []], 'test.example6' => [], 'test.example8' => []];
     $active_trail_expectations['level_1_only'] = ['test.example1' => [], 'test.example2' => [], 'test.example5' => [], 'test.example6' => [], 'test.example8' => []];
     $active_trail_expectations['level_2_only'] = ['test.example3' => [], 'test.example7' => []];
     $active_trail_expectations['level_3_only'] = ['test.example4' => []];
     $active_trail_expectations['level_1_and_beyond'] = $active_trail_expectations['all'];
     $active_trail_expectations['level_2_and_beyond'] = ['test.example3' => ['test.example4' => []], 'test.example7' => []];
     $active_trail_expectations['level_3_and_beyond'] = $active_trail_expectations['level_3_only'];
     foreach ($blocks as $id => $block) {
         $block_build = $block->build();
         $items = isset($block_build['#items']) ? $block_build['#items'] : [];
         $this->assertIdentical($active_trail_expectations[$id], $this->convertBuiltMenuToIdTree($items), format_string('Menu block %id with an active trail renders the expected tree.', ['%id' => $id]));
     }
 }
 /**
  * Presents a list of blocks to add to the variant.
  *
  * @param \Symfony\Component\HttpFoundation\Request $request
  *   The current request.
  * @param \Drupal\page_manager\PageVariantInterface $page_variant
  *   The page entity.
  *
  * @return array
  *   The block selection page.
  */
 public function selectBlock(Request $request, PageVariantInterface $page_variant)
 {
     // Add a section containing the available blocks to be added to the variant.
     $build = ['#type' => 'container', '#attached' => ['library' => ['core/drupal.ajax']]];
     $available_plugins = $this->blockManager->getDefinitionsForContexts($page_variant->getContexts());
     foreach ($available_plugins as $plugin_id => $plugin_definition) {
         // Make a section for each region.
         $category = $plugin_definition['category'];
         $category_key = 'category-' . $category;
         if (!isset($build[$category_key])) {
             $build[$category_key] = ['#type' => 'fieldgroup', '#title' => $category, 'content' => ['#theme' => 'links']];
         }
         // Add a link for each available block within each region.
         $build[$category_key]['content']['#links'][$plugin_id] = ['title' => $plugin_definition['admin_label'], 'url' => Url::fromRoute('page_manager.variant_add_block', ['page' => $page_variant->get('page'), 'page_variant' => $page_variant->id(), 'block_id' => $plugin_id, 'region' => $request->query->get('region')]), 'attributes' => $this->getAjaxAttributes()];
     }
     return $build;
 }
 /**
  * Presents a list of blocks to add to the display variant.
  *
  * @param \Symfony\Component\HttpFoundation\Request $request
  *   The current request.
  * @param \Drupal\page_manager\PageInterface $page
  *   The page entity.
  * @param string $display_variant_id
  *   The display variant ID.
  *
  * @return array
  *   The block selection page.
  */
 public function selectBlock(Request $request, PageInterface $page, $display_variant_id)
 {
     // Add a section containing the available blocks to be added to the variant.
     $build = ['#type' => 'container', '#attached' => ['library' => ['core/drupal.ajax']]];
     $available_plugins = $this->blockManager->getDefinitionsForContexts($page->getContexts());
     foreach ($available_plugins as $plugin_id => $plugin_definition) {
         // Make a section for each region.
         $category = SafeMarkup::checkPlain($plugin_definition['category']);
         $category_key = 'category-' . $category;
         if (!isset($build[$category_key])) {
             $build[$category_key] = ['#type' => 'fieldgroup', '#title' => $category, 'content' => ['#theme' => 'links']];
         }
         // Add a link for each available block within each region.
         $build[$category_key]['content']['#links'][$plugin_id] = ['title' => $plugin_definition['admin_label'], 'url' => Url::fromRoute('page_manager.display_variant_add_block', ['page' => $page->id(), 'display_variant_id' => $display_variant_id, 'block_id' => $plugin_id, 'region' => $request->query->get('region')]), 'attributes' => ['class' => ['use-ajax'], 'data-dialog-type' => 'modal', 'data-dialog-options' => Json::encode(['width' => 'auto'])]];
     }
     return $build;
 }
 /**
  * Drupal AJAX compatible route for rendering a given Block Plugin's form.
  *
  * @param string $panels_storage_type
  *   The id of the storage plugin.
  * @param string $panels_storage_id
  *   The id within the storage plugin for the requested Panels display.
  * @param string $plugin_id
  *   The requested Block Plugin ID.
  * @param string $block_uuid
  *   The Block UUID, if this is an existing Block.
  *
  * @return Response
  */
 public function getBlockPluginForm($panels_storage_type, $panels_storage_id, $plugin_id, $block_uuid = NULL)
 {
     $panels_display = $this->loadPanelsDisplay($panels_storage_type, $panels_storage_id);
     // Get the configuration in the block plugin definition.
     $definitions = $this->blockManager->getDefinitionsForContexts($panels_display->getContexts());
     // Check if the block plugin is defined.
     if (!isset($definitions[$plugin_id])) {
         throw new NotFoundHttpException();
     }
     // Build a Block Plugin configuration form.
     $form = $this->formBuilder()->getForm('Drupal\\panels_ipe\\Form\\PanelsIPEBlockPluginForm', $plugin_id, $panels_display, $block_uuid);
     // Return the rendered form as a proper Drupal AJAX response.
     $response = new AjaxResponse();
     $command = new AppendCommand('.ipe-block-plugin-form', $form);
     $response->addCommand($command);
     return $response;
 }
 /**
  * Drupal AJAX compatible route for rendering a given Block Plugin's form.
  *
  * @param \Drupal\page_manager\PageVariantInterface $page_variant
  *   The current variant.
  * @param string $plugin_id
  *   The requested Block Plugin ID.
  * @param string $block_uuid
  *   The Block UUID, if this is an existing Block.
  *
  * @return Response
  */
 public function getBlockPluginForm(PageVariantInterface $page_variant, $plugin_id, $block_uuid = NULL)
 {
     $page_variant = $this->loadPageVariant($page_variant);
     // Get the configuration in the block plugin definition.
     $definitions = $this->blockManager->getDefinitionsForContexts($page_variant->getContexts());
     // Check if the block plugin is defined.
     if (!isset($definitions[$plugin_id])) {
         throw new NotFoundHttpException();
     }
     // Build a Block Plugin configuration form.
     $form = $this->formBuilder()->getForm('Drupal\\panels_ipe\\Form\\PanelsIPEBlockPluginForm', $plugin_id, $page_variant, $block_uuid);
     // Return the rendered form as a proper Drupal AJAX response.
     // This is needed as forms often have custom JS and CSS that need added,
     // and it isn't worth replicating things that work in Drupal with Backbone.
     $response = new AjaxResponse();
     $command = new AppendCommand('.ipe-block-plugin-form', $form);
     $response->addCommand($command);
     return $response;
 }
 /**
  * {@inheritdoc}
  */
 public function submitForm(array &$form, FormStateInterface $form_state)
 {
     $configurable_types = $form['#language_types'];
     $stored_values = $this->languageTypes->get('configurable');
     $customized = array();
     $method_weights_type = array();
     foreach ($configurable_types as $type) {
         $customized[$type] = in_array($type, $stored_values);
         $method_weights = array();
         $enabled_methods = $form_state->getValue(array($type, 'enabled'));
         $enabled_methods[LanguageNegotiationSelected::METHOD_ID] = TRUE;
         $method_weights_input = $form_state->getValue(array($type, 'weight'));
         if ($form_state->hasValue(array($type, 'configurable'))) {
             $customized[$type] = !$form_state->isValueEmpty(array($type, 'configurable'));
         }
         foreach ($method_weights_input as $method_id => $weight) {
             if ($enabled_methods[$method_id]) {
                 $method_weights[$method_id] = $weight;
             }
         }
         $method_weights_type[$type] = $method_weights;
         $this->languageTypes->set('negotiation.' . $type . '.method_weights', $method_weights_input)->save();
     }
     // Update non-configurable language types and the related language
     // negotiation configuration.
     $this->negotiator->updateConfiguration(array_keys(array_filter($customized)));
     // Update the language negotiations after setting the configurability.
     foreach ($method_weights_type as $type => $method_weights) {
         $this->negotiator->saveConfiguration($type, $method_weights);
     }
     // Clear block definitions cache since the available blocks and their names
     // may have been changed based on the configurable types.
     if ($this->blockStorage) {
         // If there is an active language switcher for a language type that has
         // been made not configurable, deactivate it first.
         $non_configurable = array_keys(array_diff($customized, array_filter($customized)));
         $this->disableLanguageSwitcher($non_configurable);
     }
     $this->blockManager->clearCachedDefinitions();
     $form_state->setRedirect('language.negotiation');
     drupal_set_message($this->t('Language detection configuration saved.'));
 }
Example #11
0
 /**
  * Implements \Drupal\Core\Form\FormInterface::buildForm().
  *
  * Form constructor for the main block administration form.
  */
 public function buildForm(array $form, FormStateInterface $form_state)
 {
     $placement = FALSE;
     if ($this->request->query->has('block-placement')) {
         $placement = $this->request->query->get('block-placement');
         $form['#attached']['drupalSettings']['blockPlacement'] = $placement;
     }
     $entities = $this->load();
     $form['#theme'] = array('block_list');
     $form['#attached']['library'][] = 'core/drupal.tableheader';
     $form['#attached']['library'][] = 'block/drupal.block';
     $form['#attached']['library'][] = 'block/drupal.block.admin';
     $form['#attributes']['class'][] = 'clearfix';
     // Add a last region for disabled blocks.
     $block_regions_with_disabled = $this->regions + array(BlockInterface::BLOCK_REGION_NONE => BlockInterface::BLOCK_REGION_NONE);
     $form['block_regions'] = array('#type' => 'value', '#value' => $block_regions_with_disabled);
     // Weights range from -delta to +delta, so delta should be at least half
     // of the amount of blocks present. This makes sure all blocks in the same
     // region get an unique weight.
     $weight_delta = round(count($entities) / 2);
     // Build the form tree.
     $form['edited_theme'] = array('#type' => 'value', '#value' => $this->theme);
     $form['blocks'] = array('#type' => 'table', '#header' => array(t('Block'), t('Category'), t('Region'), t('Weight'), t('Operations')), '#attributes' => array('id' => 'blocks'));
     // Build blocks first for each region.
     foreach ($entities as $entity_id => $entity) {
         $definition = $entity->getPlugin()->getPluginDefinition();
         $blocks[$entity->getRegion()][$entity_id] = array('label' => $entity->label(), 'entity_id' => $entity_id, 'weight' => $entity->getWeight(), 'entity' => $entity, 'category' => $definition['category']);
     }
     // Loop over each region and build blocks.
     foreach ($block_regions_with_disabled as $region => $title) {
         $form['blocks']['#tabledrag'][] = array('action' => 'match', 'relationship' => 'sibling', 'group' => 'block-region-select', 'subgroup' => 'block-region-' . $region, 'hidden' => FALSE);
         $form['blocks']['#tabledrag'][] = array('action' => 'order', 'relationship' => 'sibling', 'group' => 'block-weight', 'subgroup' => 'block-weight-' . $region);
         $form['blocks'][$region] = array('#attributes' => array('class' => array('region-title', 'region-title-' . $region), 'no_striping' => TRUE));
         $form['blocks'][$region]['title'] = array('#markup' => $region != BlockInterface::BLOCK_REGION_NONE ? $title : t('Disabled', array(), array('context' => 'Plural')), '#wrapper_attributes' => array('colspan' => 5));
         $form['blocks'][$region . '-message'] = array('#attributes' => array('class' => array('region-message', 'region-' . $region . '-message', empty($blocks[$region]) ? 'region-empty' : 'region-populated')));
         $form['blocks'][$region . '-message']['message'] = array('#markup' => '<em>' . t('No blocks in this region') . '</em>', '#wrapper_attributes' => array('colspan' => 5));
         if (isset($blocks[$region])) {
             foreach ($blocks[$region] as $info) {
                 $entity_id = $info['entity_id'];
                 $form['blocks'][$entity_id] = array('#attributes' => array('class' => array('draggable')));
                 if ($placement && $placement == Html::getClass($entity_id)) {
                     $form['blocks'][$entity_id]['#attributes']['class'][] = 'color-warning';
                     $form['blocks'][$entity_id]['#attributes']['class'][] = 'js-block-placed';
                 }
                 $form['blocks'][$entity_id]['info'] = array('#markup' => SafeMarkup::checkPlain($info['label']), '#wrapper_attributes' => array('class' => array('block')));
                 $form['blocks'][$entity_id]['type'] = array('#markup' => $info['category']);
                 $form['blocks'][$entity_id]['region-theme']['region'] = array('#type' => 'select', '#default_value' => $region, '#empty_value' => BlockInterface::BLOCK_REGION_NONE, '#title' => t('Region for @block block', array('@block' => $info['label'])), '#title_display' => 'invisible', '#options' => $this->regions, '#attributes' => array('class' => array('block-region-select', 'block-region-' . $region)), '#parents' => array('blocks', $entity_id, 'region'));
                 $form['blocks'][$entity_id]['region-theme']['theme'] = array('#type' => 'hidden', '#value' => $this->theme, '#parents' => array('blocks', $entity_id, 'theme'));
                 $form['blocks'][$entity_id]['weight'] = array('#type' => 'weight', '#default_value' => $info['weight'], '#delta' => $weight_delta, '#title' => t('Weight for @block block', array('@block' => $info['label'])), '#title_display' => 'invisible', '#attributes' => array('class' => array('block-weight', 'block-weight-' . $region)));
                 $form['blocks'][$entity_id]['operations'] = $this->buildOperations($info['entity']);
             }
         }
     }
     // Do not allow disabling the main system content block when it is present.
     if (isset($form['blocks']['system_main']['region'])) {
         $form['blocks']['system_main']['region']['#required'] = TRUE;
     }
     $form['actions'] = array('#tree' => FALSE, '#type' => 'actions');
     $form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save blocks'), '#button_type' => 'primary');
     $form['place_blocks']['title'] = array('#type' => 'container', '#markup' => '<h3>' . t('Place blocks') . '</h3>', '#attributes' => array('class' => array('entity-meta-header')));
     $form['place_blocks']['filter'] = array('#type' => 'search', '#title' => t('Filter'), '#title_display' => 'invisible', '#size' => 30, '#placeholder' => t('Filter by block name'), '#attributes' => array('class' => array('block-filter-text'), 'data-element' => '.entity-meta', 'title' => t('Enter a part of the block name to filter by.')));
     $form['place_blocks']['list']['#type'] = 'container';
     $form['place_blocks']['list']['#attributes']['class'][] = 'entity-meta';
     // Only add blocks which work without any available context.
     $definitions = $this->blockManager->getDefinitionsForContexts();
     $sorted_definitions = $this->blockManager->getSortedDefinitions($definitions);
     foreach ($sorted_definitions as $plugin_id => $plugin_definition) {
         $category = SafeMarkup::checkPlain($plugin_definition['category']);
         $category_key = 'category-' . $category;
         if (!isset($form['place_blocks']['list'][$category_key])) {
             $form['place_blocks']['list'][$category_key] = array('#type' => 'details', '#title' => $category, '#open' => TRUE, 'content' => array('#theme' => 'links', '#links' => array(), '#attributes' => array('class' => array('block-list'))));
         }
         $form['place_blocks']['list'][$category_key]['content']['#links'][$plugin_id] = array('title' => $plugin_definition['admin_label'], 'url' => Url::fromRoute('block.admin_add', ['plugin_id' => $plugin_id, 'theme' => $this->theme]), 'attributes' => array('class' => array('use-ajax', 'block-filter-text-source'), 'data-dialog-type' => 'modal', 'data-dialog-options' => Json::encode(array('width' => 700))));
     }
     return $form;
 }
 /**
  * Gets a list of all available blocks sorted by category and label.
  *
  * @return array[]
  */
 public function getSystemBlocks()
 {
     $contexts = $this->contextRepository->getAvailableContexts();
     $blocks = $this->blockManager->getDefinitionsForContexts($contexts);
     return $this->blockManager->getSortedDefinitions($blocks);
 }