Skip to content

Instantly share code, notes, and snippets.

@rachellawson
Created November 16, 2016 16:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rachellawson/36f7c8d99085d98ab561a263834ac304 to your computer and use it in GitHub Desktop.
Save rachellawson/36f7c8d99085d98ab561a263834ac304 to your computer and use it in GitHub Desktop.
Getting all that facebook comment malarkey off into a tab, that only appears when the field_facebook_comment field on the node is true.
(function ($) {
Drupal.behaviors.facebook_comment = Drupal.behaviors.facebook_comment || {
attach: function (context, settings) {
(function (d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s);
js.id = id;
js.src = "//connect.facebook.net/en_GB/sdk.js#xfbml=1&version=v2.8";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
}
}
})(jQuery);
name: Social Commentary
type: module
description: provides Facebook comments tab on enabled content
core: 8.x
package: HU8
facebook_comment:
js:
js/facebook-comment.js: {preprocess: false}
<?php
/**
* @file
* Contains social_commentary.module..
*/
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
*/
function social_commentary_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
// Main module help for the social_commentary module.
case 'help.page.social_commentary':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('provides Facebook comments tab on enabled content') . '</p>';
return $output;
default:
}
}
# In order to to create pages it is necessary to define routes for them.
# A route maps a URL path to a controller. It defines what function
# or method will be called when a URL is accessed.
# If the user accesses http://drupal8.dev/node/{node}/facebook, the routing
# system will look for a route with that path. In this case it will find a
# match, and execute the _controller callback. In this case the callback is
# defined as a classname
# ("\Drupal\social_commentary\Controller\DefaultController")
# and a method ("content").
social_commentary.social_comment:
path: 'node/{node}/social'
defaults:
_controller: '\Drupal\social_commentary\Controller\DefaultController::content'
_title_callback: '\Drupal\social_commentary\Controller\DefaultController::title'
requirements:
_custom_access: '\Drupal\social_commentary\Controller\DefaultController::access'
<?php
namespace Drupal\social_commentary\Controller;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Routing\Access\AccessInterface;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
/**
* Class DefaultController.
*
* @package Drupal\social_commentary\Controller
*/
class DefaultController extends ControllerBase implements AccessInterface {
/**
* @return string
* Facebook comment tag.
*/
public function content($node) {
// Create a meta tag for the facebook app id.
$app_id = array(
'#tag' => 'meta',
'#attributes' => array(
'property' => 'fb:app_id',
'content' => array('#plain_text' => '12345'),
),
);
// Return content, including tags and js libraries.
$options = ['absolute' => TRUE];
$url_object = Url::fromRoute('entity.node.canonical', ['node' => $node], $options);
return [
'#type' => 'markup',
'#markup' => '<div class="fb-comments" data-width="100%" data-href="' . $url_object->toString() . '" data-numposts="5">Facebook comments for this content are loading...</div>',
'#attached' => array(
'library' => array(
'social_commentary/facebook_comment'
),
'html_head' => array(
array(
$app_id, 'app_id'
),
),
),
];
}
/**
* A custom access check.
*
* @param \Drupal\Core\Session\AccountInterface $account
* Run access checks for this account.
*
* @return AccessResult if the access is allowed.
*/
public function access(AccountInterface $account) {
$node = $this->getNode();
// Check permissions and combine that with any custom access checking needed. Pass forward
// parameters from the route and/or request as needed.
return AccessResult::allowedIf($account->hasPermission('access content') && $this->hasFacebookCommentEnabled($node));
}
public function title() {
$node = $this->getNode();
return t('Social comment on %title', array(
'%title' => $node->title->value)
);
}
/**
* Determine if this node has a Facebook social comment enabled.
*
* @return boolean the Facebook comment status.
*/
protected function hasFacebookCommentEnabled($node) {
$facebook_enabled = ($node->hasField('field_facebook_comment')) ? $node->field_facebook_comment->value : FALSE;
if ($facebook_enabled) {
return TRUE;
}
return false;
}
/**
* @return \Drupal\Core\Entity\EntityInterface|mixed|null
*/
private function getNode() {
$node = \Drupal::request()->attributes->get('node');
if (!is_object($node)) {
$node = \Drupal::entityTypeManager()
->getStorage('node')
->load($node);
}
return $node;
}
}
@jpstacey
Copy link

jpstacey commented Nov 16, 2016

Hardwired \Drupal:: is to be avoided (it makes the code harder to test or reuse), so I'd recommend replacing one with $this->entityTypeManager() which ControllerBase gives you, and the other with:

  protected $requestStack;

  /**
   * {@inheritDoc}
   */
  public static function create(ContainerInterface $container) {
    return new static($container->get('request_stack'));
  }
 
  public function __construct(\Symfony\Component\HttpFoundation\RequestStack $requestStack) {
    $this->requestStack = $requestStack;
  }

This turns your getNode() into:

  private function getNode() {
    $node = $requestStack->getCurrentRequest()->attributes->get('node');
    if (!is_object($node)) {
      $node = $this->entityTypeManager()
        ->getStorage('node')
        ->load($node);
    }
    return $node;
  }

The DI is a few extra lines but it saves you heartache in future. For example, if you want to decouple the entity type manager too, you only need to modify a couple of lines:

  protected $requestStack;

  /**
   * {@inheritDoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('request_stack'),
      $container->get('entity_type.manager')
    );
  }
 
  public function __construct(
    \Symfony\Component\HttpFoundation\RequestStack $requestStack,
    \Drupal\Core\Entity\EntityTypeManagerInterface $entityTypeManager
  ) {
    $this->requestStack = $requestStack;
    $this->entityTypeManager = $entityTypeManager;
  }

@rachellawson
Copy link
Author

rachellawson commented Nov 17, 2016

@jpstacey - I presume in getNode()

$node = $requestStack->getCurrentRequest()->attributes->get('node');

must be

$node = $this->requestStack->getCurrentRequest()->attributes->get('node');

@jpstacey
Copy link

Yes, sorry - copypasta error

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment