Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show ads among views results #21

Open
wants to merge 6 commits into
base: 8.x-1.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions modules/ad_entity_views/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Advertising Entity in Views
===========================

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea, would be interesting if we could find a "proper" way to accomplish the "injection" of ads between view rows.

How to use:

- Install module
- Add a footer to views
- Ad entity
- Select your ad display
- Choose ads position
- Save
7 changes: 7 additions & 0 deletions modules/ad_entity_views/ad_entity_views.info.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
name: Advertising Entity in Views
type: module
description: Shows ads among views results.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As seen in your prototype, I guess the description could be something like "Enables in-between placing of Advertisement inside Views results"?

core: 8.x
package: Advertising
dependencies:
- drupal:ad_entity
52 changes: 52 additions & 0 deletions modules/ad_entity_views/ad_entity_views.module
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

/**
* @file
* The module file.
*/

use Drupal\views\ViewExecutable;
use Drupal\views\Plugin\views\cache\CachePluginBase;
use Drupal\ad_entity_views\Plugin\views\area\AdEntityArea;

/**
* Implements hook_views_post_render().
*
* Renders ads in views.
*/
function ad_entity_views_views_post_render(ViewExecutable $view, &$output, CachePluginBase $cache) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not the best way to accomplish it. Guess that needs some further lookup to the possibilities we have.
We'd need

  • A standalone place (not the footer) to have a form for the plugin configuration of placing the ads
  • a proper injection point so that the ads will be able to be placed in-between, no matter what type for output format has been chosen (like list of content teaser or table of fields)
  • a way to merge the cache tags and cache contexts of the used configs (ad_display, ad_entity instances) so that the render caching / page caching includes these ones

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep. maybe we should have a look how views attachments work.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure it is so easy-doable with the table display. Maybe overriding views rows might somehow work.

Copy link
Author

@milkovsky milkovsky Mar 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

possible UI solution https://www.drupal.org/project/views_row_insert.
But they use hook_preprocess_HOOK.

if (empty($output)) {
return;
}

$has_ads = FALSE;
if (!empty($view->footer)) {
foreach ($view->footer as $key => $footer) {
if ($footer instanceof AdEntityArea) {
// @todo: Process multiple ad entities?.
$has_ads = TRUE;
unset($view->footer[$key]);
}
}
}

if (!$has_ads || empty($footer)) {
return;
}

$teaser_row = NULL;
// The output can have multiple rows, get the one of the view.
foreach ($output['#rows'] as $key => $rows) {
if (isset($rows['#view']) && $rows['#view'] == $view) {
$teaser_row = &$output['#rows'][$key]['#rows'];
break;
}
}

if ($teaser_row) {
$ad_build = $footer->render();
$position = $footer->options['ad_entity_position'];
// Show ad at the specified position.
array_splice($teaser_row, $position, 0, [$ad_build]);
}
}
23 changes: 23 additions & 0 deletions modules/ad_entity_views/ad_entity_views.views.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

/**
* @file
* Provide views data for diff.module.
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrong

*/

/**
* Implements hook_views_data().
*/
function ad_entity_views_views_data() {
$data = [];

$data['views']['ad_entity_views'] = [
'title' => t('Ad entity'),
'help' => t('Shows ads among views results.'),
'area' => [
'id' => 'ad_entity_views',
],
];

return $data;
}
122 changes: 122 additions & 0 deletions modules/ad_entity_views/src/Plugin/views/area/AdEntityArea.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
<?php

namespace Drupal\ad_entity_views\Plugin\views\area;

use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityViewBuilderInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\views\Plugin\views\area\AreaPluginBase;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
* Shows ads among views results.
*
* @ingroup views_area_handlers
*
* @ViewsArea("ad_entity_views")
*/
class AdEntityArea extends AreaPluginBase {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This plugin looks pretty good already!


/**
* The storage of Display configs for Advertisement.
*
* @var \Drupal\Core\Entity\EntityStorageInterface
*/
protected $adDisplayStorage;

/**
* The view builder for Display configs for Advertisement.
*
* @var \Drupal\Core\Entity\EntityViewBuilderInterface
*/
protected $adDisplayViewBuilder;

/**
* Constructs a new Entity instance.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Entity\EntityStorageInterface $ad_display_storage
* The storage of Display configs for Advertisement.
* @param \Drupal\Core\Entity\EntityViewBuilderInterface $ad_display_view_builder
* The view builder for Display configs for Advertisement.
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $ad_display_storage, EntityViewBuilderInterface $ad_display_view_builder) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->adDisplayStorage = $ad_display_storage;
$this->adDisplayViewBuilder = $ad_display_view_builder;
}

/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$type_manager = $container->get('entity_type.manager');
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$type_manager->getStorage('ad_display'),
$type_manager->getViewBuilder('ad_display')
);
}

/**
* {@inheritdoc}
*/
protected function defineOptions() {
$options = parent::defineOptions();

$options['ad_entity_display'] = ['default' => NULL];
$options['ad_entity_position'] = ['default' => 0];

return $options;
}

/**
* {@inheritdoc}
*/
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
parent::buildOptionsForm($form, $form_state);

$options = [];

$ads = $this->adDisplayStorage->loadMultiple();
/** @var \Drupal\ad_entity\Entity\AdDisplayInterface[] $ads */
if ($ads) {
foreach ($ads as $ad_name => $ad) {
$options[$ad_name] = $ad->label();
}
}

$form['ad_entity_display'] = [
'#title' => $this->t('Ad display'),
'#type' => 'select',
'#default_value' => $this->options['ad_entity_display'],
'#options' => $options,
];

$form['ad_entity_position'] = [
'#title' => $this->t('Ad position'),
'#despricption' => $this->t('Ad position in the rows list starting from 0. If negative, it starts counting from the end of the list.'),
'#type' => 'number',
'#default_value' => $this->options['ad_entity_position'],
];
}

/**
* {@inheritdoc}
*/
public function render($empty = FALSE) {
if (!$empty || !empty($this->options['empty'])) {
$ad = $this->adDisplayStorage->load($this->options['ad_entity_display']);
$build = $this->adDisplayViewBuilder->view($ad);
return $build;
}
}

}