diff --git a/core/modules/block/custom_block/config/custom_block.type.basic.yml b/core/modules/block/custom_block/config/custom_block.type.basic.yml
new file mode 100644
index 0000000..e2bb99e
--- /dev/null
+++ b/core/modules/block/custom_block/config/custom_block.type.basic.yml
@@ -0,0 +1,3 @@
+id: basic
+label: Basic block
+revision: '0'
diff --git a/core/modules/block/custom_block/custom_block.admin.inc b/core/modules/block/custom_block/custom_block.admin.inc
new file mode 100644
index 0000000..be1e32e
--- /dev/null
+++ b/core/modules/block/custom_block/custom_block.admin.inc
@@ -0,0 +1,91 @@
+render();
+}
+
+/**
+ * Page callback: Presents the custom block type creation form.
+ *
+ * @return array
+ * A form array as expected by drupal_render().
+ *
+ * @see custom_block_menu()
+ */
+function custom_block_type_add() {
+ drupal_set_title(t('Add custom block type'));
+ $block_type = entity_create('custom_block_type', array());
+ return entity_get_form($block_type);
+}
+
+/**
+ * Page callback: Presents the custom block type edit form.
+ *
+ * @param Drupal\custom_block\Plugin\Core\Entity\CustomBlockType $block_type
+ * The custom block type to edit.
+ *
+ * @return array
+ * A form array as expected by drupal_render().
+ *
+ * @see custom_block_menu()
+ */
+function custom_block_type_edit(CustomBlockType $block_type) {
+ drupal_set_title(t('Edit %label custom block type', array('%label' => $block_type->label())), PASS_THROUGH);
+ return entity_get_form($block_type);
+}
+
+/**
+ * Page callback: Form constructor for the custom block type deletion form.
+ *
+ * @param Drupal\custom_block\Plugin\Core\Entity\CustomBlockType $block_type
+ * The custom block type to be deleted.
+ *
+ * @see custom_block_menu()
+ * @see custom_block_type_delete_form_submit()
+ *
+ * @ingroup forms
+ */
+function custom_block_type_delete_form($form, &$form_state, CustomBlockType $block_type) {
+ $form_state['custom_block_type'] = $block_type;
+ $form['id'] = array(
+ '#type' => 'value',
+ '#value' => $block_type->id(),
+ );
+
+ return confirm_form(
+ $form,
+ t('Are you sure you want to delete %label?', array('%label' => $block_type->label())),
+ 'admin/structure/custom-blocks',
+ t('This action cannot be undone.'),
+ t('Delete')
+ );
+}
+
+/**
+ * Form submission handler for custom_block_type_delete_form().
+ */
+function custom_block_type_delete_form_submit($form, &$form_state) {
+ $block_type = $form_state['custom_block_type'];
+ $block_type->delete();
+
+ drupal_set_message(t('Custom block type %label has been deleted.', array('%label' => $block_type->label())));
+ watchdog('custom_block', 'Custom block type %label has been deleted.', array('%label' => $block_type->label()), WATCHDOG_NOTICE);
+
+ $form_state['redirect'] = 'admin/structure/custom-blocks';
+}
diff --git a/core/modules/block/custom_block/custom_block.install b/core/modules/block/custom_block/custom_block.install
index 4a0e4b0..2f9ecd0 100644
--- a/core/modules/block/custom_block/custom_block.install
+++ b/core/modules/block/custom_block/custom_block.install
@@ -19,12 +19,11 @@ function custom_block_schema() {
'not null' => TRUE,
'description' => "The block's {block}.bid.",
),
- 'body' => array(
- 'type' => 'text',
+ 'uuid' => array(
+ 'description' => 'Unique Key: Universally unique identifier for this entity.',
+ 'type' => 'varchar',
+ 'length' => 128,
'not null' => FALSE,
- 'size' => 'big',
- 'description' => 'Block contents.',
- 'translatable' => TRUE,
),
'info' => array(
'type' => 'varchar',
@@ -33,17 +32,98 @@ function custom_block_schema() {
'default' => '',
'description' => 'Block description.',
),
- 'format' => array(
+ 'machine_name' => array(
'type' => 'varchar',
- 'length' => 255,
+ 'length' => 128,
+ 'not null' => TRUE,
+ 'default' => '',
+ 'description' => 'Machine name of block.',
+ ),
+ // Defaults to NULL in order to avoid a brief period of potential
+ // deadlocks on the index.
+ 'vid' => array(
+ 'description' => 'The current {block_custom_revision}.vid version identifier.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
'not null' => FALSE,
- 'description' => 'The {filter_format}.format of the block body.',
+ 'default' => NULL,
),
+ 'type' => array(
+ 'description' => 'The type of this custom block.',
+ 'type' => 'varchar',
+ 'length' => 32,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
+ 'langcode' => array(
+ 'description' => 'The {language}.langcode of this node.',
+ 'type' => 'varchar',
+ 'length' => 12,
+ 'not null' => TRUE,
+ 'default' => '',
+ ),
+ 'tnid' => array(
+ 'description' => 'The translation set id for this node, which equals the node id of the source post in each set.',
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ 'translate' => array(
+ 'description' => 'A boolean indicating whether this translation page needs to be updated.',
+ 'type' => 'int',
+ 'not null' => TRUE,
+ 'default' => 0,
+ ),
+ ),
+ 'indexes' => array(
+ 'block_custom_type' => array(array('type', 4)),
+ 'tnid' => array('tnid'),
+ 'translate' => array('translate'),
),
'unique keys' => array(
+ 'vid' => array('vid'),
+ 'uuid' => array('uuid'),
'info' => array('info'),
),
+ 'foreign keys' => array(
+ 'block_custom_revision' => array(
+ 'table' => 'block_custom_revision',
+ 'columns' => array('vid' => 'vid'),
+ ),
+ ),
'primary key' => array('bid'),
);
+
+ $schema['block_custom_revision'] = array(
+ 'description' => 'Stores contents of custom-made blocks.',
+ 'fields' => array(
+ 'bid' => array(
+ 'type' => 'int',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ 'default' => 0,
+ 'description' => "The block's {block}.bid.",
+ ),
+ // Defaults to NULL in order to avoid a brief period of potential
+ // deadlocks on the index.
+ 'vid' => array(
+ 'description' => 'The current version identifier.',
+ 'type' => 'serial',
+ 'unsigned' => TRUE,
+ 'not null' => TRUE,
+ ),
+ 'log' => array(
+ 'description' => 'The log entry explaining the changes in this version.',
+ 'type' => 'text',
+ 'not null' => TRUE,
+ 'size' => 'big',
+ ),
+ ),
+ 'unique keys' => array(
+ 'vid' => array('vid'),
+ ),
+ 'primary key' => array('vid'),
+ );
return $schema;
}
diff --git a/core/modules/block/custom_block/custom_block.js b/core/modules/block/custom_block/custom_block.js
new file mode 100644
index 0000000..a35d438
--- /dev/null
+++ b/core/modules/block/custom_block/custom_block.js
@@ -0,0 +1,30 @@
+/**
+ * @file
+ * Defines Javascript behaviors for the custom_block module.
+ */
+
+(function ($) {
+
+"use strict";
+
+Drupal.behaviors.customBlockDetailsSummaries = {
+ attach: function (context) {
+ var $context = $(context);
+ $context.find('.custom-block-form-revision-information').drupalSetSummary(function (context) {
+ var $context = $(context);
+ var revisionCheckbox = $context.find('.form-item-revision input');
+
+ // Return 'New revision' if the 'Create new revision' checkbox is checked,
+ // or if the checkbox doesn't exist, but the revision log does. For users
+ // without the "Administer content" permission the checkbox won't appear,
+ // but the revision log will if the content type is set to auto-revision.
+ if (revisionCheckbox.is(':checked') || (!revisionCheckbox.length && $context.find('.form-item-log textarea').length)) {
+ return Drupal.t('New revision');
+ }
+
+ return Drupal.t('No revision');
+ });
+ }
+};
+
+})(jQuery);
diff --git a/core/modules/block/custom_block/custom_block.module b/core/modules/block/custom_block/custom_block.module
index d3e1588..42b77c7 100644
--- a/core/modules/block/custom_block/custom_block.module
+++ b/core/modules/block/custom_block/custom_block.module
@@ -5,6 +5,9 @@
* Allows the creaation of custom blocks through the user interface.
*/
+use Drupal\custom_block\Plugin\Core\Entity\CustomBlockType;
+use Drupal\custom_block\Plugin\Core\Entity\CustomBlock;
+
/**
* Implements hook_menu().
*/
@@ -19,15 +22,92 @@ function custom_block_menu() {
$items['admin/structure/block/list/' . $plugin_id . '/add/custom_blocks'] = array(
'title' => 'Add custom block',
'description' => 'Create a block with custom content and settings.',
- 'page callback' => 'drupal_get_form',
- 'page arguments' => array('block_admin_configure', 'custom_block:custom_block', $theme),
- 'access callback' => TRUE,
+ 'page callback' => 'drupal_goto',
+ 'page arguments' => array(
+ 'block/add',
+ array('query' => array('theme' => $theme))
+ ),
+ 'access arguments' => array('administer blocks'),
'type' => MENU_LOCAL_ACTION,
- 'file' => 'block.admin.inc',
- 'file path' => drupal_get_path('module', 'block'),
);
}
}
+
+ $items['admin/structure/custom-blocks'] = array(
+ 'title' => 'Block types',
+ 'description' => 'Manage custom block types.',
+ 'page callback' => 'custom_block_type_list',
+ 'access arguments' => array('administer blocks'),
+ 'file' => 'custom_block.admin.inc',
+ );
+ $items['admin/structure/custom-blocks/add'] = array(
+ 'title' => 'Add custom block type',
+ 'page callback' => 'custom_block_type_add',
+ 'access arguments' => array('administer blocks'),
+ 'type' => MENU_LOCAL_ACTION,
+ 'weight' => 1,
+ 'file' => 'custom_block.admin.inc',
+ );
+ $items['admin/structure/custom-blocks/manage/%custom_block_type'] = array(
+ 'title' => 'Edit custom block type',
+ 'title callback' => 'entity_page_label',
+ 'title arguments' => array(4),
+ 'page callback' => 'custom_block_type_edit',
+ 'page arguments' => array(4),
+ 'access arguments' => array('administer blocks'),
+ 'file' => 'custom_block.admin.inc',
+ );
+ $items['admin/structure/custom-blocks/manage/%custom_block_type/edit'] = array(
+ 'title' => 'Edit',
+ 'type' => MENU_DEFAULT_LOCAL_TASK,
+ 'weight' => -10,
+ );
+ $items['admin/structure/custom-blocks/manage/%custom_block_type/delete'] = array(
+ 'title' => 'Delete',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('custom_block_type_delete_form', 4),
+ 'access arguments' => array('administer blocks'),
+ 'type' => MENU_LOCAL_TASK,
+ 'weight' => 10,
+ 'file' => 'custom_block.admin.inc',
+ );
+
+ $items['block/add'] = array(
+ 'title' => 'Add custom block',
+ 'page callback' => 'custom_block_add_page',
+ 'access arguments' => array('administer blocks'),
+ 'file' => 'custom_block.pages.inc',
+ );
+
+ $items['block/add/%custom_block_type'] = array(
+ 'title callback' => 'entity_page_label',
+ 'title arguments' => array(2),
+ 'page callback' => 'custom_block_add',
+ 'page arguments' => array(2),
+ 'access arguments' => array('administer blocks'),
+ 'description' => 'Add custom block',
+ 'file' => 'custom_block.pages.inc',
+ );
+ $items['block/%custom_block_machine_name/edit'] = array(
+ 'title' => 'Edit',
+ 'page callback' => 'custom_block_edit',
+ 'page arguments' => array(1),
+ 'access arguments' => array('administer blocks'),
+ 'weight' => 0,
+ 'type' => MENU_LOCAL_TASK,
+ 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
+ 'file' => 'custom_block.pages.inc',
+ );
+ $items['block/%custom_block_machine_name/delete'] = array(
+ 'title' => 'Delete',
+ 'page callback' => 'drupal_get_form',
+ 'page arguments' => array('custom_block_delete_confirm', 1),
+ 'access arguments' => array('administer blocks'),
+ 'weight' => 1,
+ 'type' => MENU_LOCAL_TASK,
+ 'context' => MENU_CONTEXT_INLINE,
+ 'file' => 'custom_block.pages.inc',
+ );
return $items;
}
@@ -53,3 +133,156 @@ function theme_custom_block_block($variables) {
return check_markup($body, $format);
}
+
+/**
+ * Loads a custom block type.
+ *
+ * @param int $id
+ * The ID of the custom block type to load.
+ *
+ * @return Drupal\custom_block\Plugin\Core\Entity\CustomBlockType|false
+ * A CustomBlockType object or FALSE if the requested $id does not exist.
+ */
+function custom_block_type_load($id) {
+ return entity_load('custom_block_type', $id);
+}
+
+/**
+ * Loads a custom block.
+ *
+ * @param int $bid
+ * The bid of the custom block.
+ *
+ * @return Drupal\custom_block\Plugin\Core\Entity\CustomBlock|false
+ * A CustomBlock object or FALSE if the requested $id does not exist.
+ */
+function custom_block_load($bid) {
+ return entity_load('custom_block', $bid);
+}
+
+/**
+ * Loads a custom block.
+ *
+ * @param string $machine_name
+ * The machine name of the custom block.
+ *
+ * @return Drupal\custom_block\Plugin\Core\Entity\CustomBlock|false
+ * A CustomBlock object or FALSE if the requested $id does not exist.
+ */
+function custom_block_machine_name_load($machine_name) {
+ $block_ids = entity_query('custom_block')->condition('machine_name', $machine_name)->execute();
+ if (!empty($block_ids) && ($block_id = reset($block_ids))) {
+ return entity_load('custom_block', $block_id);
+ }
+ return FALSE;
+}
+
+/**
+ * Entity URI callback.
+ *
+ * @param Drupal\custom_block\Plugin\Core\Entity\CustomBlockType $block_type
+ * A custom block type entity.
+ *
+ * @return array
+ * An array with 'path' as the key and the path to the custom block type as
+ * the value.
+ */
+function custom_block_type_uri(CustomBlockType $block_type) {
+ return array(
+ 'path' => 'admin/structure/custom-blocks/manage/' . $block_type->id(),
+ );
+}
+
+/**
+ * Implements hook_entity_info().
+ */
+function custom_block_entity_info_alter(&$types) {
+ foreach (config_get_storage_names_with_prefix('custom_block.type.') as $config_name) {
+ $config = config($config_name);
+ $types['custom_block']['bundles'][$config->get('id')] = array(
+ 'label' => $config->get('label'),
+ 'admin' => array(
+ 'path' => 'admin/structure/custom-blocks/manage/%',
+ 'real path' => 'admin/structure/custom-blocks/manage/' . $config->get('id'),
+ 'bundle argument' => 4,
+ 'access arguments' => array('administer blocks'),
+ ),
+ );
+ }
+}
+
+/**
+ * Adds the default body field to a custom block type.
+ *
+ * @param string $block_type_id
+ * Id of the block type.
+ * @param string $label
+ * (optional) The label for the body instance. Defaults to 'Block body'
+ *
+ * @return array()
+ * Body field instance.
+ */
+function custom_block_add_body_field($block_type_id, $label = 'Block body') {
+ // Add or remove the body field, as needed.
+ $field = field_info_field('block_body');
+ $instance = field_info_instance('custom_block', 'block_body', $block_type_id);
+ if (empty($field)) {
+ $field = array(
+ 'field_name' => 'block_body',
+ 'type' => 'text_with_summary',
+ 'entity_types' => array('custom_block'),
+ );
+ $field = field_create_field($field);
+ }
+ if (empty($instance)) {
+ $instance = array(
+ 'field_name' => 'block_body',
+ 'entity_type' => 'custom_block',
+ 'bundle' => $block_type_id,
+ 'label' => $label,
+ 'widget' => array('type' => 'text_textarea_with_summary'),
+ 'settings' => array('display_summary' => FALSE),
+ );
+ $instance = field_create_instance($instance);
+
+ // Assign display settings for the 'full'.
+ entity_get_display('custom_block', $block_type_id, 'full')
+ ->setComponent($field['field_name'], array(
+ 'label' => 'hidden',
+ 'type' => 'text_default',
+ ))
+ ->save();
+ }
+
+ return $instance;
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter() for block_plugin_ui().
+ */
+function custom_block_form_block_plugin_ui_alter(&$form, $form_state) {
+ foreach ($form['left']['plugin_library']['#rows'] as $plugin_id => &$row) {
+ @list($base, $derivative) = explode(':', $plugin_id);
+ if ($base !== 'custom_block') {
+ continue;
+ }
+ $row['1']['data']['#links']['edit'] = array(
+ 'title' => t('Edit'),
+ 'href' => 'block/' . $derivative . '/edit'
+ );
+ }
+}
+
+/**
+ * Implements hook_admin_paths().
+ */
+function custom_block_admin_paths() {
+ $paths = array(
+ 'block/add' => TRUE,
+ 'block/add/*' => TRUE,
+ 'block/*/edit' => TRUE,
+ 'block/*/delete' => TRUE,
+ 'admin/structure/custom-blocks/*' => TRUE,
+ );
+ return $paths;
+}
diff --git a/core/modules/block/custom_block/custom_block.pages.inc b/core/modules/block/custom_block/custom_block.pages.inc
new file mode 100644
index 0000000..958a610
--- /dev/null
+++ b/core/modules/block/custom_block/custom_block.pages.inc
@@ -0,0 +1,139 @@
+ array('theme' => $_GET['theme'])
+ );
+ }
+ $types = config_get_storage_names_with_prefix('custom_block.type.');
+ if (count($types) == 1) {
+ $config = config(reset($types));
+ drupal_goto('block/add/' . $config->get('id'), $options);
+ }
+ // Multiple custom block types exist, present a list of links.
+ $links = array();
+
+ foreach ($types as $config_name) {
+ $config = config($config_name);
+ $links[] = l($config->get('label'), 'block/add/' . $config->get('id'), $options);
+ }
+ return array(
+ '#theme' => array(
+ 'item_list',
+ 'item_list__custom_block_add'
+ ),
+ '#items' => $links,
+ '#title' => t('Choose a block type to continue.')
+ );
+}
+
+/**
+ * Page callback: Presents the custom block creation form.
+ *
+ * @param Drupal\custom_block\Plugin\Core\Entity\CustomBlockType $block_type
+ * The custom block type to add.
+ *
+ * @return array
+ * A form array as expected by drupal_render().
+ *
+ * @see custom_block_menu()
+ */
+function custom_block_add(CustomBlockType $block_type) {
+ drupal_set_title(t('Add %type custom block', array(
+ '%type' => $block_type->label()
+ )), PASS_THROUGH);
+ $block = entity_create('custom_block', array(
+ 'type' => $block_type->id()
+ ));
+ $options = array();
+ if (isset($_GET['theme']) && in_array($_GET['theme'], array_keys(list_themes()))) {
+ // We have navigated to this page from the block library and will keep track
+ // of the theme for redirecting the user to the configuration page for the
+ // newly created block in the given theme.
+ $block->setTheme($_GET['theme']);
+ }
+ return entity_get_form($block);
+}
+
+/**
+ * Page callback: Presents the custom block edit form.
+ *
+ * @param Drupal\custom_block\Plugin\Core\Entity\CustomBlock $block
+ * The custom block to edit.
+ *
+ * @return array
+ * A form array as expected by drupal_render().
+ *
+ * @see custom_block_menu()
+ */
+function custom_block_edit(CustomBlock $block) {
+ drupal_set_title(t('Edit custom block %label', array('%label' => $block->label())), PASS_THROUGH);
+ return entity_get_form($block);
+}
+
+/**
+ * Page callback: Form constructor for the custom block deletion form.
+ *
+ * @param Drupal\custom_block\Plugin\Core\Entity\CustomBlock $block
+ * The custom block to be deleted.
+ *
+ * @see custom_block_menu()
+ * @see custom_block_delete_form_submit()
+ *
+ * @ingroup forms
+ */
+function custom_block_delete_form($form, &$form_state, CustomBlock $block) {
+ $form_state['custom_block'] = $block;
+ $form['id'] = array(
+ '#type' => 'value',
+ '#value' => $block->id(),
+ );
+
+ return confirm_form(
+ $form,
+ t('Are you sure you want to delete %label?', array('%label' => $block->label())),
+ 'admin/structure/block',
+ t('This action cannot be undone.'),
+ t('Delete')
+ );
+}
+
+/**
+ * Form submission handler for custom_block_delete_form().
+ */
+function custom_block_delete_form_submit($form, &$form_state) {
+ // @todo Delete all configured instances of the block.
+ $block = $form_state['custom_block'];
+ $block->delete();
+
+ drupal_set_message(t('Custom block %label has been deleted.', array('%label' => $block->label())));
+ watchdog('custom_block', 'Custom block %label has been deleted.', array('%label' => $block->label()), WATCHDOG_NOTICE);
+
+ $form_state['redirect'] = 'admin/structure/block';
+}
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php
new file mode 100644
index 0000000..8cfdbdd
--- /dev/null
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockFormController.php
@@ -0,0 +1,240 @@
+type);
+ // If this is a new custom block, fill in the default values.
+ if (isset($block->bid)) {
+ $block->log = NULL;
+ }
+ // Always use the default revision setting.
+ $block->setNewRevision($block_type->revision);
+
+ module_invoke_all('custom_block_prepare', $block);
+ }
+
+ /**
+ * Overrides Drupal\Core\Entity\EntityFormController::form().
+ */
+ public function form(array $form, array &$form_state, EntityInterface $block) {
+
+ // Override the default CSS class name, since the user-defined custom block
+ // type name in 'TYPE-block-form' potentially clashes with third-party class
+ // names.
+ $form['#attributes']['class'][0] = drupal_html_class('block-' . $block->type . '-form');
+
+ // Basic block information.
+ // These elements are just values so they are not even sent to the client.
+ foreach (array('bid', 'vid') as $key) {
+ $form[$key] = array(
+ '#type' => 'value',
+ '#value' => isset($block->$key) ? $block->$key : NULL,
+ );
+ }
+
+ $form['info'] = array(
+ '#type' => 'textfield',
+ '#title' => t('Block description'),
+ '#required' => TRUE,
+ '#default_value' => $block->info,
+ '#weight' => -5,
+ '#description' => t('A brief description of your block. Used on the Blocks administration page.', array('@overview' => url('admin/structure/block'))),
+ );
+
+ $form['machine_name'] = array(
+ '#type' => 'machine_name',
+ '#default_value' => $block->machine_name,
+ '#machine_name' => array(
+ 'exists' => 'custom_block_load',
+ 'source' => array('info')
+ ),
+ '#weight' => -4,
+ '#disabled' => !$block->isNew(),
+ );
+
+ $language_configuration = module_invoke('language', 'get_default_configuration', 'custom_block', $block->type);
+ $form['langcode'] = array(
+ '#title' => t('Language'),
+ '#type' => 'language_select',
+ '#default_value' => $block->langcode,
+ '#languages' => LANGUAGE_ALL,
+ '#access' => isset($language_configuration['language_hidden']) && !$language_configuration['language_hidden'],
+ );
+
+ $form['additional_settings'] = array(
+ '#type' => 'vertical_tabs',
+ '#weight' => 99,
+ );
+
+ // Add a log field if the "Create new revision" option is checked, or if the
+ // current user has the ability to check that option.
+ $form['revision_information'] = array(
+ '#type' => 'details',
+ '#title' => t('Revision information'),
+ '#collapsible' => TRUE,
+ // Collapsed by default when "Create new revision" is unchecked.
+ '#collapsed' => !$block->isNewRevision(),
+ '#group' => 'additional_settings',
+ '#attributes' => array(
+ 'class' => array('custom-block-form-revision-information'),
+ ),
+ '#attached' => array(
+ 'js' => array(drupal_get_path('module', 'custom_block') . '/custom_block.js'),
+ ),
+ '#weight' => 20,
+ '#access' => $block->isNewRevision() || user_access('administer blocks'),
+ );
+
+ $form['revision_information']['revision'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Create new revision'),
+ '#default_value' => $block->isNewRevision(),
+ '#access' => user_access('administer blocks'),
+ );
+
+ // Check the revision log checkbox when the log textarea is filled in.
+ // This must not happen if "Create new revision" is enabled by default,
+ // since the state would auto-disable the checkbox otherwise.
+ if (!$block->isNewRevision()) {
+ $form['revision_information']['revision']['#states'] = array(
+ 'checked' => array(
+ 'textarea[name="log"]' => array('empty' => FALSE),
+ ),
+ );
+ }
+
+ $form['revision_information']['log'] = array(
+ '#type' => 'textarea',
+ '#title' => t('Revision log message'),
+ '#rows' => 4,
+ '#default_value' => !empty($block->log) ? $block->log : '',
+ '#description' => t('Briefly describe the changes you have made.'),
+ );
+
+ return parent::form($form, $form_state, $block);
+ }
+
+ /**
+ * Overrides Drupal\Core\Entity\EntityFormController::validate().
+ */
+ public function validate(array $form, array &$form_state) {
+ $block = $this->buildEntity($form, $form_state);
+
+ foreach (module_implements('custom_block_validate') as $module) {
+ $function = $module . '_custom_block_validate';
+ $function($block, $form, $form_state);
+ }
+
+ parent::validate($form, $form_state);
+ }
+
+ /**
+ * Updates the custom block object by processing the submitted values.
+ *
+ * This function can be called by a "Next" button of a wizard to update the
+ * form state's entity with the current step's values before proceeding to the
+ * next step.
+ *
+ * Overrides Drupal\Core\Entity\EntityFormController::submit().
+ */
+ public function submit(array $form, array &$form_state) {
+ // Build the block object from the submitted values.
+ $block = parent::submit($form, $form_state);
+
+ // Save as a new revision if requested to do so.
+ if (!empty($form_state['values']['revision'])) {
+ $block->setNewRevision();
+ }
+
+ foreach (module_implements('custom_block_submit') as $module) {
+ $function = $module . '_custom_block_submit';
+ $function($block, $form, $form_state);
+ }
+
+ return $block;
+ }
+
+ /**
+ * Overrides Drupal\Core\Entity\EntityFormController::save().
+ */
+ public function save(array $form, array &$form_state) {
+ $block = $this->getEntity($form_state);
+ $insert = empty($block->bid);
+ $block->save();
+ $watchdog_args = array('@type' => $block->bundle(), '%info' => $block->label());
+ $block_type = entity_load('custom_block_type', $block->type);
+ $t_args = array('@type' => $block_type->label(), '%info' => $block->label());
+
+ if ($insert) {
+ watchdog('content', '@type: added %info.', $watchdog_args, WATCHDOG_NOTICE);
+ drupal_set_message(t('@type %info has been created.', $t_args));
+ }
+ else {
+ watchdog('content', '@type: updated %info.', $watchdog_args, WATCHDOG_NOTICE);
+ drupal_set_message(t('@type %info has been updated.', $t_args));
+ }
+
+ if ($block->bid) {
+ $form_state['values']['bid'] = $block->bid;
+ $form_state['bid'] = $block->bid;
+ if ($insert) {
+ if ($theme = $block->getTheme()) {
+ $form_state['redirect'] = 'admin/structure/block/manage/custom_block:' . $block->machine_name . '/' . $theme;
+ }
+ else {
+ $form_state['redirect'] = 'admin/structure/block/manage/custom_block:' . $block->machine_name . '/' . variable_get('theme_default', 'stark');
+ }
+ }
+ else {
+ $form_state['redirect'] = 'admin/structure/block';
+ }
+ }
+ else {
+ // In the unlikely case something went wrong on save, the block will be
+ // rebuilt and block form redisplayed.
+ drupal_set_message(t('The block could not be saved.'), 'error');
+ $form_state['rebuild'] = TRUE;
+ }
+
+ // Clear the page and block caches.
+ cache_invalidate_tags(array('content' => TRUE));
+ }
+
+ /**
+ * Overrides Drupal\Core\Entity\EntityFormController::delete().
+ */
+ public function delete(array $form, array &$form_state) {
+ $destination = array();
+ if (isset($_GET['destination'])) {
+ $destination = drupal_get_destination();
+ unset($_GET['destination']);
+ }
+ $block = $this->getEntity($form_state);
+ $form_state['redirect'] = array('block/' . $block->bid . '/delete', array('query' => $destination));
+ }
+
+}
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockRenderController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockRenderController.php
new file mode 100644
index 0000000..eb227d3
--- /dev/null
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockRenderController.php
@@ -0,0 +1,29 @@
+bid) && $view_mode == 'full') {
+ $build['#contextual_links']['custom_block'] = array('custom_block', array($entity->machine_name));
+ }
+ }
+
+}
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php
new file mode 100644
index 0000000..1d3dcb1
--- /dev/null
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockStorageController.php
@@ -0,0 +1,60 @@
+isNewRevision()) {
+ // When inserting either a new custom block or a new custom_block
+ // revision, $entity->log must be set because {block_custom_revision}.log
+ // is a text column and therefore cannot have a default value. However,
+ // it might not be set at this point (for example, if the user submitting
+ // the form does not have permission to create revisions), so we ensure
+ // that it is at least an empty string in that case.
+ // @todo: Make the {block_custom_revision}.log column nullable so that we
+ // can remove this check.
+ if (!isset($record->log)) {
+ $record->log = '';
+ }
+ }
+ elseif (!isset($record->log) || $record->log === '') {
+ // If we are updating an existing custom_block without adding a new
+ // revision, we need to make sure $entity->log is unset whenever it is
+ // empty. As long as $entity->log is unset, drupal_write_record() will not
+ // attempt to update the existing database column when re-saving the
+ // revision; therefore, this code allows us to avoid clobbering an
+ // existing log entry with an empty one.
+ unset($record->log);
+ }
+
+ }
+
+ /**
+ * Overrides Drupal\Core\Entity\DatabaseStorageController::postSave().
+ */
+ function postSave(EntityInterface $block, $update) {
+ // Invalidate the block cache to update custom block-based derivatives.
+ if (module_exists('block')) {
+ drupal_container()->get('plugin.manager.block')->clearCachedDefinitions();
+ }
+ }
+
+}
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeFormController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeFormController.php
new file mode 100644
index 0000000..e17e040
--- /dev/null
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeFormController.php
@@ -0,0 +1,85 @@
+ 'textfield',
+ '#title' => t('Label'),
+ '#maxlength' => 255,
+ '#default_value' => $block_type->label(),
+ '#description' => t("Provide a label for this block type to help identify it in the administration pages."),
+ '#required' => TRUE,
+ );
+ $form['id'] = array(
+ '#type' => 'machine_name',
+ '#default_value' => $block_type->id(),
+ '#machine_name' => array(
+ 'exists' => 'custom_block_type_load',
+ ),
+ '#disabled' => !$block_type->isNew(),
+ );
+
+ $form['revision'] = array(
+ '#type' => 'checkbox',
+ '#title' => t('Create new revision'),
+ '#default_value' => $block_type->revision,
+ '#desciption' => t('Create a new revision by default for this block type.')
+ );
+
+ $form['actions'] = array('#type' => 'actions');
+ $form['actions']['submit'] = array(
+ '#type' => 'submit',
+ '#value' => t('Save'),
+ );
+
+ return $form;
+ }
+
+ /**
+ * Overrides Drupal\Core\Entity\EntityFormController::save().
+ */
+ public function save(array $form, array &$form_state) {
+ $block_type = $this->getEntity($form_state);
+ $status = $block_type->save();
+
+ $uri = $block_type->uri();
+ if ($status == SAVED_UPDATED) {
+ drupal_set_message(t('Custom block type %label has been updated.', array('%label' => $block_type->label())));
+ watchdog('custom_block', 'Custom block type %label has been updated.', array('%label' => $block_type->label()), WATCHDOG_NOTICE, l(t('Edit'), $uri['path'] . '/edit'));
+ }
+ else {
+ drupal_set_message(t('Custom block type %label has been added.', array('%label' => $block_type->label())));
+ watchdog('custom_block', 'Custom block type %label has been added.', array('%label' => $block_type->label()), WATCHDOG_NOTICE, l(t('Edit'), $uri['path'] . '/edit'));
+ }
+
+ $form_state['redirect'] = 'admin/structure/custom-blocks';
+ }
+
+ /**
+ * Overrides Drupal\Core\Entity\EntityFormController::delete().
+ */
+ public function delete(array $form, array &$form_state) {
+ $block_type = $this->getEntity($form_state);
+ $form_state['redirect'] = 'admin/structure/custom-blocks/manage/' . $block_type->id() . '/delete';
+ }
+
+}
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListController.php
new file mode 100644
index 0000000..a59799e
--- /dev/null
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeListController.php
@@ -0,0 +1,58 @@
+uri();
+ $operations['manage-fields'] = array(
+ 'title' => t('Manage fields'),
+ 'href' => $uri['path'] . '/fields',
+ 'options' => $uri['options'],
+ 'weight' => 11,
+ );
+ $operations['manage-display'] = array(
+ 'title' => t('Manage display'),
+ 'href' => $uri['path'] . '/display',
+ 'options' => $uri['options'],
+ 'weight' => 12,
+ );
+ }
+ return $operations;
+ }
+
+ /**
+ * Overrides Drupal\Core\Entity\EntityListController::buildHeader().
+ */
+ public function buildHeader() {
+ $row['type'] = t('Block type');
+ $row['operations'] = t('Operations');
+ return $row;
+ }
+
+ /**
+ * Overrides Drupal\Core\Entity\EntityListController::buildRow().
+ */
+ public function buildRow(EntityInterface $entity) {
+ $row['type'] = check_plain($entity->label());
+ $row['operations']['data'] = $this->buildOperations($entity);
+ return $row;
+ }
+
+}
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeStorageController.php b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeStorageController.php
new file mode 100644
index 0000000..2e27b39
--- /dev/null
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/CustomBlockTypeStorageController.php
@@ -0,0 +1,44 @@
+id());
+ }
+ elseif ($entity->original->id() != $entity->id()) {
+ field_attach_rename_bundle('custom_block', $entity->original->id(), $entity->id());
+ }
+ custom_block_add_body_field($entity->id());
+ }
+
+ /**
+ * Overrides \Drupal\Core\Config\Entity\ConfigStorageController::postDelete().
+ */
+ protected function postDelete($entities) {
+ parent::postDelete($entities);
+
+ foreach ($entities as $entity) {
+ field_attach_delete_bundle('custom_block', $entity->id());
+ }
+ }
+
+}
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php
new file mode 100644
index 0000000..7428aee
--- /dev/null
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlock.php
@@ -0,0 +1,207 @@
+bid;
+ }
+
+ /**
+ * Implements Drupal\Core\Entity\EntityInterface::bundle().
+ */
+ public function bundle() {
+ return $this->type;
+ }
+
+ /**
+ * Implements Drupal\Core\Entity\EntityInterface::label().
+ */
+ public function label($langcode = NULL) {
+ return $this->info;
+ }
+
+ /**
+ * Overrides Drupal\Core\Entity\Entity::createDuplicate().
+ */
+ public function createDuplicate() {
+ $duplicate = parent::createDuplicate();
+ $duplicate->vid = NULL;
+ return $duplicate;
+ }
+
+ /**
+ * Overrides Drupal\Core\Entity\Entity::getRevisionId().
+ */
+ public function getRevisionId() {
+ return $this->vid;
+ }
+
+ /**
+ * Sets the theme value.
+ *
+ * When creating a new custom block from the block library, the user is
+ * redirected to the configure form for that block in the given theme. The
+ * theme is stored against the block when the custom block add form is shown.
+ *
+ * @param string $theme
+ * The theme name.
+ */
+ public function setTheme($theme) {
+ $this->theme = $theme;
+ }
+
+ /**
+ * Gets the theme value.
+ *
+ * When creating a new custom block from the block library, the user is
+ * redirected to the configure form for that block in the given theme. The
+ * theme is stored against the block when the custom block add form is shown.
+ *
+ * @return string
+ * The theme name.
+ */
+ public function getTheme() {
+ return $this->theme;
+ }
+}
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlockType.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlockType.php
new file mode 100644
index 0000000..fb6f2b5
--- /dev/null
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/Core/Entity/CustomBlockType.php
@@ -0,0 +1,65 @@
+derivatives[$result->bid] = $base_plugin_definition;
- $this->derivatives[$result->bid]['settings'] = array(
+ $this->derivatives[$result->machine_name] = $base_plugin_definition;
+ $this->derivatives[$result->machine_name]['settings'] = array(
'info' => $result->info,
- 'body' => $result->body,
- 'format' => $result->format,
) + $base_plugin_definition['settings'];
- $this->derivatives[$result->bid]['subject'] = $result->info;
+ $this->derivatives[$result->machine_name]['subject'] = $result->info;
}
- $this->derivatives['custom_block'] = $base_plugin_definition;
return $this->derivatives;
}
}
diff --git a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/block/block/CustomBlock.php b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/block/block/CustomBlock.php
index 8b142ef..7a7bc00 100644
--- a/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/block/block/CustomBlock.php
+++ b/core/modules/block/custom_block/lib/Drupal/custom_block/Plugin/block/block/CustomBlock.php
@@ -1,6 +1,6 @@
'',
+ 'view_mode' => 'full'
);
}
@@ -47,8 +47,7 @@ public function getConfig() {
$this->configuration = parent::getConfig();
$this->configuration['status'] = $definition['settings']['status'];
$this->configuration['info'] = $definition['settings']['info'];
- $this->configuration['body'] = $definition['settings']['body'];
- $this->configuration['format'] = $definition['settings']['format'];
+ $this->configuration['view_mode'] = $definition['settings']['view_mode'];
return $this->configuration;
}
@@ -58,25 +57,17 @@ public function getConfig() {
* Adds body and description fields to the block configuration form.
*/
public function blockForm($form, &$form_state) {
- // @todo Disable this field when editing an existing block and provide a
- // separate interface for administering custom blocks.
- $form['custom_block']['info'] = array(
- '#type' => 'textfield',
- '#title' => t('Block description'),
- '#required' => TRUE,
- '#default_value' => $this->configuration['info'],
- '#description' => t('A brief description of your block. Used on the Blocks administration page. Changing this field will change the description for all copies of this block.', array('@overview' => url('admin/structure/block'))),
- );
- // @todo Disable this field when editing an existing block and provide a
- // separate interface for administering custom blocks.
- $form['custom_block']['body'] = array(
- '#type' => 'text_format',
- '#title' => t('Block body'),
- '#default_value' => $this->configuration['body'],
- '#format' => isset($this->configuration['format']) ? $this->configuration['format'] : filter_default_format(),
- '#description' => t('The content of the block as shown to the user. Changing this field will change the block body everywhere it is used.'),
- '#rows' => 15,
- '#required' => TRUE,
+ $view_modes = array();
+ $info = entity_get_info('custom_block');
+ foreach ($info['view_modes'] as $view_mode => $detail) {
+ $view_modes[$view_mode] = $detail['label'];
+ }
+ $form['custom_block']['view_mode'] = array(
+ '#type' => 'select',
+ '#options' => $view_modes,
+ '#title' => t('View mode'),
+ '#description' => t('Output the block in this view mode.'),
+ '#default_value' => $this->configuration['view_mode']
);
$form['custom_block']['title']['#description'] = t('The title of the block as shown to the user.');
return $form;
@@ -86,15 +77,6 @@ public function blockForm($form, &$form_state) {
* Overrides \Drupal\block\BlockBase::blockSubmit().
*/
public function blockSubmit($form, &$form_state) {
- list(, $bid) = explode(':', $this->getPluginId());
- $block = array(
- 'info' => $form_state['values']['info'],
- 'body' => $form_state['values']['body']['value'],
- 'format' => $form_state['values']['body']['format'],
- 'bid' => is_numeric($bid) ? $bid : NULL,
- );
- drupal_write_record('block_custom', $block, !is_null($block['bid']) ? array('bid') : array());
- $this->configuration['id'] = 'custom_block:' . $block['bid'];
// Invalidate the block cache to update custom block-based derivatives.
if (module_exists('block')) {
drupal_container()->get('plugin.manager.block')->clearCachedDefinitions();
@@ -105,12 +87,19 @@ public function blockSubmit($form, &$form_state) {
* Implements \Drupal\block\BlockBase::blockBuild().
*/
public function blockBuild() {
- // Populate the block with the user-defined block body.
- return array(
- '#theme' => 'custom_block_block',
- '#body' => $this->configuration['body'],
- '#format' => $this->configuration['format'],
- );
+ list(, $machine_name) = explode(':', $this->getPluginId());
+ if ($block = custom_block_machine_name_load($machine_name)) {
+ return entity_view($block, $this->configuration['view_mode']);
+ }
+ else {
+ return array(
+ '#markup' => t('Block with name %name does not exist, please create it.', array(
+ '%name' => $block_id,
+ '!url' => 'block/add'
+ )),
+ '#access' => user_access('administer blocks')
+ );
+ }
}
}
diff --git a/core/modules/block/lib/Drupal/block/Plugin/system/plugin_ui/BlockPluginUI.php b/core/modules/block/lib/Drupal/block/Plugin/system/plugin_ui/BlockPluginUI.php
index 260eb9e..f2f1226 100644
--- a/core/modules/block/lib/Drupal/block/Plugin/system/plugin_ui/BlockPluginUI.php
+++ b/core/modules/block/lib/Drupal/block/Plugin/system/plugin_ui/BlockPluginUI.php
@@ -64,7 +64,7 @@ public function form($form, &$form_state, $facet = NULL) {
$rows = array();
foreach ($plugins as $plugin_id => $display_plugin_definition) {
if (empty($facet) || $this->facetCompare($facet, $display_plugin_definition)) {
- $rows[] = $this->row($plugin_id, $display_plugin_definition);
+ $rows[$plugin_id] = $this->row($plugin_id, $display_plugin_definition);
}
foreach ($plugin_definition['facets'] as $key => $title) {
$facets[$key][$display_plugin_definition[$key]] = $this->facetLink($key, $plugin_id, $display_plugin_definition);