Commit 60b97b3f authored by Benjamin Melançon's avatar Benjamin Melançon
Browse files

Issue #3247600: Nothing injected

parent eab6b9ec
Loading
Loading
Loading
Loading
+210 −269
Original line number Diff line number Diff line
<?php

use Drupal\Core\Render\Markup;
/**
 * @file
 *
 */

use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;

/**
 * Implements hook_entity_view().
 * https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Entity!entity.api.php/function/hook_entity_view/8.9.x
 */
//function body_inject_entity_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode) {
//
//  //very useful
//  //https://www.metaltoad.com/blog/drupal-8-entity-api-cheat-sheet
//
//  $entity_type = $entity->getEntityTypeId();
//  $has_body = $entity->hasField('body');
//  //$foo = $entity->getEntityType();
//
//  //only on nodes in full view mode
//  if($entity_type == 'node' && $view_mode == 'full' && $has_body !== false)  {
//
//    $node = $entity;
//
//    //@todo later we check array index against current node type. do body change first.
//    $node_type = $entity->getType();
//
//    //load all config
//    $storage = \Drupal::entityTypeManager()->getStorage('body_inject_profile');
//    $config_entities = $storage->loadMultiple();
//    $inject_list = [];
//    foreach ($config_entities as $id => $entity) {
//      $inject_node_type = $entity->getNodeType();
//
//      $inject_list[$inject_node_type][$id]['label'] = $entity->label();
//      $inject_list[$inject_node_type][$id]['block_reference'] = $entity->getBlock();
//      $inject_list[$inject_node_type][$id]['node_type'] = $entity->getNodeType();
//      $inject_list[$inject_node_type][$id]['parapgraph_operator'] = $entity->getParapgraphOperator();
//      $inject_list[$inject_node_type][$id]['parapgraph_number'] = $entity->getParapgraphNumber();
//      $inject_list[$inject_node_type][$id]['and_or'] = $entity->getAndOr();
//      $inject_list[$inject_node_type][$id]['char_operator'] = $entity->getCharOperator();
//      $inject_list[$inject_node_type][$id]['char_number'] = $entity->getCharNumber();
//      $inject_list[$inject_node_type][$id]['paragraph_offset'] = $entity->getParagraphOffset();
//      $inject_list[$inject_node_type][$id]['paragraph_position'] = $entity->getParagraphPosition();
//      $inject_list[$inject_node_type][$id]['char_position'] = $entity->getCharPosition();
//    }
//
//    //bodys value
//    $body = $node->get('body');
//    $body_value = $body->getValue();
//
//    //todo later
//    //$processed_body = block_inject_adv_process_condition($body_value, $inject_list);
//
////    $foo = $build['#node'];
////    $foo->set('body', array(
////      'summary' => "KING KONG",
////      'value' => "teaser text",
////      'format' => 'basic_html',
////    ));
////    $foo->save(); //care, this will override the actual fields content!
//
//    //$build_node = $build['#node'];
//
//    //here is the actual stuff, we unset it, page is empty
//    //unset($build['_layout_builder']);
//
//    //unset we inject our own!
//    //unset($build['#node']);
//    //$build['#node'] = $foo;
//
//
//
//    $stop=1;
//
//  }
//
//}
// very useful
// https://www.metaltoad.com/blog/drupal-8-entity-api-cheat-sheet

// ideas
// https://www.drupal.org/project/drupal/issues/2626224
@@ -86,47 +12,31 @@ use Drupal\Core\Render\Markup;
/**
 * Implements hook_entity_view_alter().
 * https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Entity!entity.api.php/function/hook_entity_view_alter/8.9.x
 *
 * Leaving this generic as "entity" but we could switch to "node" for our current functionality.
 * That is i had hook_ENTITY_TYPE_view_alter() for nodes, hook_node_view_alter(&$build, $node, $display)
 */
function body_inject_entity_view_alter(array &$build, Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display) {

  //very useful
  //https://www.metaltoad.com/blog/drupal-8-entity-api-cheat-sheet

    //that is not always the case even if the block is the node_body
    //isset($build['body']) ? $has_body = true : $has_body = false;
    isset($build['#view_mode']) ? $view_mode = $build['#view_mode'] : $view_mode = false;
function body_inject_entity_view_alter(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display) {

    $node = $entity;
    $entity_type = $entity->getEntityTypeId();
  $inject_list = body_inject_profiles();

    //@todo later we check array index against current node type. do body change first.

    //load all config
    $storage = \Drupal::entityTypeManager()->getStorage('body_inject_profile');
    $config_entities = $storage->loadMultiple();
    $inject_list = [];
    foreach ($config_entities as $id => $entity) {
      $inject_node_type = $entity->getNodeType();
      $inject_list[$inject_node_type][$id]['label'] = $entity->label();
      $inject_list[$inject_node_type][$id]['block_reference'] = $entity->getBlock();
      $inject_list[$inject_node_type][$id]['node_type'] = $entity->getNodeType();
      $inject_list[$inject_node_type][$id]['paragraph_operator'] = $entity->getParagraphOperator();
      $inject_list[$inject_node_type][$id]['paragraph_number'] = $entity->getParagraphNumber();
      $inject_list[$inject_node_type][$id]['and_or'] = $entity->getAndOr();
      $inject_list[$inject_node_type][$id]['char_operator'] = $entity->getCharOperator();
      $inject_list[$inject_node_type][$id]['char_number'] = $entity->getCharNumber();
      $inject_list[$inject_node_type][$id]['paragraph_offset'] = $entity->getParagraphOffset();
      $inject_list[$inject_node_type][$id]['paragraph_position'] = $entity->getParagraphPosition();
      $inject_list[$inject_node_type][$id]['char_position'] = $entity->getCharPosition();
  // First check if we have blocks to inject here.
  if (!isset($inject_list[$entity->bundle()])) {
    return;
  }

    //@todo is there a way to get what node_type the block is attached to?
  // @TODO Make view mode configurable.
  if ($display->getOriginalMode() !== 'full') {
    return;
  }

  $body_text = NULL;
  if (isset($build['body'][0]['#text'])) {
    $body_text =& $build['body'][0]['#text'];
  } else {
    // Dig for it in the layout builder.
    //ok this is wacky hacky ... but i have no idea how else to do it better. Api? What functions?
    //patches welcome

    $injection_actions = array();

    if (isset($build['_layout_builder'][0])) {
      $layoutbuilder_content = $build['_layout_builder'][0];

@@ -134,50 +44,49 @@ function body_inject_entity_view_alter(array &$build, Drupal\Core\Entity\EntityI
        //skip all indices with #
        if (strpos($key, '#') === FALSE) {
          foreach ($vals as $id => $block_data) {

            //do we have a body block?
            if (isset($block_data['#plugin_id'])) {
              $field_data = explode(':', $block_data['#plugin_id']);

              //we have the body field of the node type!
              // We have the body field of the node!
              if (isset($field_data[1]) && $field_data[1] == 'node' && isset($field_data[3])
                && $field_data[3] == 'body'
              ) {

                if (isset($field_data[2])) {
                  $node_type = $field_data[2];
                $body_text =& $build['_layout_builder'][0][$key][$id]['content'][0]['#text'];
                break 2;
              }
                else {
                  $node_type = 'unknown';
            }
          }
        }
      }
    }
  }
  if (!$body_text) {
    \Drupal::logger('body_inject')->warning('Could not insert block into %path - no body found.',
      [
        '%path' => $entity->toUrl()->toString(),
      ]);
    return;
  }
  // @TODO we could double-check it is processed text, maybe even check that
  // it has token filters enabled, by looking up $build['body'][0]['#format']
  // but requiring that be full_html (as i did originally) is not reasonable.

                $current_body = $build['_layout_builder'][0][$key][$id]['content'][0]['#text'];

                //we have blocks to inject here
                if (isset($inject_list[$node_type])) {
  $injection_actions = [];

                  foreach ($inject_list[$node_type] as $ikey => $inject_data) {
                    $do_inject = block_inject_adv_process_condition($current_body, $inject_data);
  foreach ($inject_list[$entity->bundle()] as $inject_data) {
    $do_inject = body_inject_adv_process_condition($body_text, $inject_data);
    if ($do_inject) {
      $injection_actions[] = $inject_data;
    }
  }

                }

  //now we can do the injections
                $injected_body = block_inject_adv_node($injection_actions, $current_body);
  $injected_body = body_inject_adv_node($injection_actions, $body_text);

  //replace original with our injection
                $build['_layout_builder'][0][$key][$id]['content'][0]['#text'] = $injected_body;
  $body_text = $injected_body;

}
            }
          }
        }
      }
    }
}

//CAN NOT BE USED AS IT ONLY SHOWS BLOCKS PLACED USING THE BLOCK UI!
//function body_inject_block_view_alter(array &$build, \Drupal\Core\Block\BlockPluginInterface $block) {
@@ -189,7 +98,6 @@ function body_inject_entity_view_alter(array &$build, Drupal\Core\Entity\EntityI
//  }
//}


/**
 * Helper function to process the condition for an injection.
 *
@@ -199,10 +107,12 @@ function body_inject_entity_view_alter(array &$build, Drupal\Core\Entity\EntityI
 *
 * @return bool|array False if no condition, or the action data
 * @internal param $node_type The node type*   The node type
 *
 */
function block_inject_adv_process_condition($body, $settings) {
function body_inject_adv_process_condition($body, $settings) {

  if (!$settings['paragraph_number'] && !$settings['char_number']) {
    return TRUE;
  }

  // PARAGRAPHS
  // Break up the body field string into an array of paragraphs and count them.
@@ -224,7 +134,6 @@ function block_inject_adv_process_condition($body, $settings) {
  $char_state = FALSE;
  $inject_state = FALSE;


  //@todo this state handling could be made more generic and better for more cases or data
  //-- AND
  if ($condition_boole == 'and') {
@@ -237,7 +146,7 @@ function block_inject_adv_process_condition($body, $settings) {
        $inject_state = TRUE;
      }
    }
      // only paragraph
    // Only paragraph
    if (isset($paragraph_no)) {
      $paragraph_state = body_inject_operator_check($paragraph_operator, $paragraph_no, $body_paragraphs_count);
      if ($paragraph_state) {
@@ -265,14 +174,14 @@ function block_inject_adv_process_condition($body, $settings) {
        $inject_state = TRUE;
      }
    }
      // only paragraph
    // Only paragraph
    if (isset($paragraph_no)) {
      $paragraph_state = body_inject_operator_check($paragraph_operator, $paragraph_no, $body_paragraphs_count);
      if ($paragraph_state) {
        $inject_state = TRUE;
      }
    }
      //only char
    // Only char
    if (isset($char_no)) {
      $char_state = body_inject_operator_check($char_operator, $char_no, $body_char_count);
      if ($char_state) {
@@ -281,8 +190,7 @@ function block_inject_adv_process_condition($body, $settings) {
    }
  }


  //return true or false if no action will be used (no injection)
  // Return true or false if no action will be used (no injection)
  if ($inject_state) {
    return TRUE;
  }
@@ -292,6 +200,31 @@ function block_inject_adv_process_condition($body, $settings) {

}

/**
 * Helper to load all config for blocks to insert into nodes.
 */
function body_inject_profiles() {
  $storage = \Drupal::entityTypeManager()->getStorage('body_inject_profile');
  $config_entities = $storage->loadMultiple();
  $inject_list = [];
  foreach ($config_entities as $id => $entity) {
    $inject_node_type = $entity->getNodeType();
    $inject_list[$inject_node_type][$id]['label'] = $entity->label();
    $inject_list[$inject_node_type][$id]['block_reference'] = $entity->getBlock();
    $inject_list[$inject_node_type][$id]['node_type'] = $entity->getNodeType();
    $inject_list[$inject_node_type][$id]['paragraph_operator'] = $entity->getParagraphOperator();
    $inject_list[$inject_node_type][$id]['paragraph_number'] = $entity->getParagraphNumber();
    $inject_list[$inject_node_type][$id]['and_or'] = $entity->getAndOr();
    $inject_list[$inject_node_type][$id]['char_operator'] = $entity->getCharOperator();
    $inject_list[$inject_node_type][$id]['char_number'] = $entity->getCharNumber();
    $inject_list[$inject_node_type][$id]['paragraph_offset'] = $entity->getParagraphOffset();
    $inject_list[$inject_node_type][$id]['paragraph_position'] = $entity->getParagraphPosition();
    $inject_list[$inject_node_type][$id]['char_position'] = $entity->getCharPosition();
  }
  return $inject_list;
}


/**
 * Injects the region in the middle of the node.
 *
@@ -303,13 +236,11 @@ function block_inject_adv_process_condition($body, $settings) {
 * The injected body string or false if not enough paragraphs.
 * @internal param int $positioning_data
 */
function block_inject_adv_node($actions, $body) {
function body_inject_adv_node($actions, $body) {

  // Break up the body field string into an array of paragraphs.
  $array_body_paragraphs = explode("<p>", $body);


  foreach ($actions as $key => $action_data) {
  foreach ($actions as $action_data) {

    // load the block content that should be inserted
    $bid = $action_data['block_reference'];
@@ -317,16 +248,26 @@ function block_inject_adv_node($actions, $body) {
//        $block_content = \Drupal::entityTypeManager()->getViewBuilder('block_content')->view($block);
//        $block_markup = \Drupal::service('renderer')->renderPlain($block_content);

    $block_manager = \Drupal::service('plugin.manager.block');
    //just get body content
    $custom_block = \Drupal::entityTypeManager()->getStorage('block_content')->load($bid);
    if (!empty($custom_block)) {
      $block_markup = $custom_block->body->value;
    } else {
      $config = [];
      $plugin_block = $block_manager->createInstance($bid, $config);
      $render = $plugin_block->build();
      // Add the cache tags/contexts.
      // \Drupal::service('renderer')->addCacheableDependency($render, $plugin_block);
      $block_markup = \Drupal::service('renderer')->renderPlain($render);
    }

    // we add a wrapper
    $block_markup = "<div class='body-inject body-inject-$bid'>" . $block_markup . "</div>";

    // 3 actions avaliable, parapgraph_position, char_position, paragraph_offset

        //parapgraph_position
    // paragraph_position
    if (!empty($action_data['paragraph_position'])) {
      //--Insert the renderable region array into paragraph position
      array_splice($array_body_paragraphs, ($action_data['paragraph_position']) + 1, 0, $block_markup);

composer.json

0 → 100644
+16 −0
Original line number Diff line number Diff line
{
  "name": "drupal/body_inject",
  "type": "drupal-module",
  "description": "Body Inject (insert blocks into content)",
  "keywords": ["Drupal", "blocks", "content", "advertising"],
  "license": "GPL-2.0+",
  "homepage": "https://www.drupal.org/project/body_inject",
  "minimum-stability": "dev",
  "support": {
    "issues": "https://www.drupal.org/project/issues/body_inject",
    "source": "https://git.drupalcode.org/project/body_inject"
  },
  "require": {
    "drupal/token_block": "^1"
  }
}
+2 −8
Original line number Diff line number Diff line
@@ -77,7 +77,7 @@ class Profile extends ConfigEntityBase implements ProfileInterface {
  protected $description;

  /**
   * block_reference of this profile.
   * Block this profile targets for injection.
   *
   * @var string
   */
@@ -85,7 +85,7 @@ class Profile extends ConfigEntityBase implements ProfileInterface {


  /**
   * block_reference of this profile.
   * Node type for the block to be injected into.
   *
   * @var string
   */
@@ -151,8 +151,6 @@ class Profile extends ConfigEntityBase implements ProfileInterface {
   */
  protected $char_position;



  /**
   * {@inheritdoc}
   */
@@ -213,7 +211,6 @@ class Profile extends ConfigEntityBase implements ProfileInterface {
    return $this;
  }


  /**
   * {@inheritdoc}
   */
@@ -289,7 +286,6 @@ class Profile extends ConfigEntityBase implements ProfileInterface {
    return $this;
  }


  /**
   * {@inheritdoc}
   */
@@ -305,8 +301,6 @@ class Profile extends ConfigEntityBase implements ProfileInterface {
    return $this;
  }



  /**
   * {@inheritdoc}
   */
+57 −19
Original line number Diff line number Diff line
@@ -8,16 +8,24 @@
namespace Drupal\body_inject\Form\Profile;

use Drupal\block_content\Entity\BlockContent;
use Drupal\Core\Block\BlockManagerInterface;
use Drupal\Core\Entity\EntityForm;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;

use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Base form for profile add and edit forms.
 */
abstract class FormBase extends EntityForm {

  /**
   * The block manager.
   *
   * @var \Drupal\Core\Block\BlockManagerInterface
   */
  protected $blockManager;

  /**
   * The entity being used by this form.
   *
@@ -25,6 +33,29 @@ abstract class FormBase extends EntityForm {
   */
  protected $entity;

  /**
   * FormBase constructor.
   *
   * @param \Drupal\Core\Block\BlockManagerInterface $block_manager
   *   The block manager.
   */
  public function __construct(BlockManagerInterface $block_manager) {
    $this->blockManager = $block_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('plugin.manager.block'),
    );
  }

  /**
   * {@inheritdoc}
   */

  /**
   * {@inheritdoc}
   */
@@ -42,7 +73,7 @@ abstract class FormBase extends EntityForm {
      '#type' => 'machine_name',
      '#default_value' => $this->entity->id(),
      '#machine_name' => [
        'exists' => ['\Drupal\body_inject\Entity\Profile', 'load']
        'exists' => ['\Drupal\body_inject\Entity\Profile', 'load'],
      ],
      '#disabled' => !$this->entity->isNew(),
    ];
@@ -54,29 +85,38 @@ abstract class FormBase extends EntityForm {
      '#description' => $this->t('The text will be displayed on the <em>profile collection</em> page.'),
    ];

    $form['additional_settings'] = array(
    $form['additional_settings'] = [
      '#type' => 'vertical_tabs',
      '#weight' => 99,
    );
    ];

    //block we want to inject
    // Block we want to inject.
    $block_ref = $this->entity->getBlock();
    if (!empty($block_ref)) {
      $entity_block =  BlockContent::load($block_ref);
      $entity_block = $block_ref;
    }
    else {
      $entity_block = '';
    }

    //possible target_type
    //https://drupal.stackexchange.com/questions/208143/what-is-target-type-in-entityautocomplete
    // Only add blocks which work without any context.
    $definitions = $this->blockManager->getFilteredDefinitions('block_ui', [], []);
    // Order by category, and then by admin label.
    $definitions = $this->blockManager->getSortedDefinitions($definitions);
    // Filter out definitions that are not intended to be placed by the UI.
    $definitions = array_filter($definitions, function (array $definition) {
      return empty($definition['_block_ui_hidden']);
    });
    $options = [];
    foreach ($definitions as $plugin_id => $plugin_definition) {
      $options[$plugin_id] = $this->blockManager->createInstance($plugin_id, [])->label() . " - " . $plugin_id;
    }
    $form['block_reference'] = [
      '#type' => 'entity_autocomplete',
      '#target_type' => 'block_content',
      '#type' => 'select',
      '#title' => $this->t('Block to inject'),
      '#required' => 'true',
      '#options' => $options,
      '#default_value' => $entity_block,
      '#size' => 30,
    ];

    $node_types = node_type_get_names();
@@ -86,14 +126,15 @@ abstract class FormBase extends EntityForm {
      '#required' => 'true',
      '#default_value' => $this->entity->getNodeType(),
      '#options' => $node_types,
      '#size' => 30,
    ];


    //paragraph condition
    // Paragraph condition.
    $form['inject_condition'] = [
      '#title' => t('The condition if the block is placed'),
      '#type' => 'fieldset',
      '#description' => t('Leave blank to always try to insert the block.'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
    ];

    $form['inject_condition']['paragraphs'] = [
@@ -147,7 +188,7 @@ abstract class FormBase extends EntityForm {
      '#description' => t('Set this to <em>AND</em> if you would like both to apply. Set it to OR if only one has to be valid for the insert to happen.'),
    );

    //characters
    // Characters.
    $form['inject_condition']['char_cond'] = array(
      '#title' => t('Characters'),
      '#type' => 'fieldset',
@@ -205,7 +246,6 @@ abstract class FormBase extends EntityForm {
    );

    //condition 2, injection after paragraph, length
    //
    $form['body_inject_paragraph_action'] = array(
      '#title' => t('Insert after Paragraph ...'),
      '#type' => 'fieldset',
@@ -220,7 +260,6 @@ abstract class FormBase extends EntityForm {
    );

    //condition 3, after amount of characters
    //
    $form['body_inject_char_action'] = array(
      '#title' => t('Insert after amount of characters ...'),
      '#type' => 'fieldset',
@@ -234,7 +273,6 @@ abstract class FormBase extends EntityForm {
      have that amount of characters. Nothing will be injected.'),
    );


    return parent::form($form, $form_state);
  }

+4 −11
Original line number Diff line number Diff line
@@ -37,18 +37,16 @@ interface ProfileInterface extends ConfigEntityInterface {
   *
   * @return $this
   */

  public function getBlock();


  /**
   * Sets the selected inject block.
   *
   * @param $block_reference
   * @param string $block_reference
   *   The block to inject.
   *
   * @return $this
   */

  public function setBlock($block_reference);

  /**
@@ -56,21 +54,16 @@ interface ProfileInterface extends ConfigEntityInterface {
   *
   * @return $this
   */

  public function getNodeType();


  /**
   * Sets the node type for inject block.
   *
   * @param $node_type
   * @param string $node_type
   *   The type of node to inject the block.
   *
   * @return $this
   */

  public function setNodeType($node_type);




}
Loading