Account created on 3 January 2013, over 11 years ago
#

Recent comments

🇪🇸Spain interdruper

#10 is the easiest fix, also for D10, clearing caches is not necessary.

🇪🇸Spain interdruper

Hi 2dareis2do

thanks for your fast response.

We use XPostManager encapsulated in a custom service, so it can contains logic for any specific context.

E.g.: for scheduling the post of tweets, with the help of modules like Scheduler or our preferred Scheduler Field .

I attached a code sample (skeleton) of a custom service using XPostManager, in case it is useful to someone with the same requirement:

<?php

namespace Drupal\custom_module\Service;

use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\Core\Url;
use Drupal\node\Entity\Node;
use Drupal\social_api\Plugin\NetworkManager;
use Drupal\social_api\User\UserManagerInterface;
use Drupal\social_post_x\Plugin\Network\XPostInterface;
use Drupal\social_post_x\XPostManagerInterface;
use Drupal\taxonomy\Entity\Term;
use Drupal\user\Entity\User;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Post a tweet
 */
class PostTweet {

  use StringTranslationTrait;

  /**
   * The X post network plugin.
   *
   * @var \Drupal\social_post_x\Plugin\Network\XPostInterface
   */
  protected $xPoster;

  /**
   * The network manager.
   *
   * @var \Drupal\social_api\Plugin\NetworkManager
   */
  private NetworkManager $networkManager;

  /**
   * The social api user manager.
   *
   * @var \Drupal\social_post\User\UserManager
   */
  protected $userManager;

  /**
   * The X post network plugin.
   *
   * @var \Drupal\social_post_x\XPostManager
   */
  protected $postManager;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The messenger.
   *
   * @var \Drupal\Core\Messenger\MessengerInterface
   */
  protected $messenger;

  /**
   * The logger factory.
   *
   * @var \Drupal\Core\Logger\LoggerChannelFactoryInterface
   */
  private $logger;

  /**
   * The current user.
   *
   * @var \Drupal\Core\Session\AccountInterface
   */
  protected $currentUser;

  /**
   * The current route match.
   *
   * @var \Drupal\Core\Routing\RouteMatchInterface
   */
  protected $routeMatch;

  /**
   * The constructor.
   *
   * @param \Drupal\social_api\Plugin\NetworkManager $networkManager
   *   The network manager.
   * @param \Drupal\social_api\User\UserManagerInterface $user_manager
   *   The social user manager.
   * @param \Drupal\social_post_x\XPostManagerInterface $post_manager
   *   The X post manager.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\Messenger\MessengerInterface $messenger
   *   The messenger.
   * @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $loggerFactory
   *   The logger factory object.
   * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
   *   The string translation.
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
   *   The current route match
   */
  public function __construct(NetworkManager $networkManager,
                              UserManagerInterface $user_manager,
                              XPostManagerInterface $post_manager,
                              EntityTypeManagerInterface $entity_type_manager,
                              MessengerInterface $messenger,
                              LoggerChannelFactoryInterface $loggerFactory,
                              TranslationInterface $string_translation,
                              AccountInterface $current_user,
                              RouteMatchInterface $route_match) {

    $this->networkManager = $networkManager;
    $this->userManager = $user_manager;
    $this->postManager = $post_manager;
    $this->entityTypeManager = $entity_type_manager;
    $this->messenger = $messenger;
    $this->logger = $loggerFactory->get('custom_module');
    $this->stringTranslation = $string_translation;
    $this->currentUser = $current_user;
    $this->routeMatch = $route_match;

    $this->xPoster = $this->networkManager->createInstance('social_post_x');

    $client = $this->xPoster->getSdk();
    $this->postManager->setClient($client);
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {

    return new static(
      $container->get('plugin.network.manager'),
      $container->get('social_post.user_manager'),
      $container->get('x_post.manager'),
      $container->get('entity_type.manager'),
      $container->get('messenger'),
      $container->get('logger.factory'),
      $container->get('string_translation'),
      $container->get('current_user'),
      $container->get('current_route_match')
    );
  }

  /**
   * Post twweet.
   *
   * @param string $content
   *   Tweet content.
   *
   *  @param array $image_path
   *   Array of full realpaths or URLs to image files.
   *
   * @call \Drupal::service('custom_module.post_tweet')->postTweet($content, $image_paths);
   */

  public function postTweet(string $content, array $image_paths = []) : void {

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

    // Include your custom logic here, using the available injected services...

    $tweet['text'] = $content;
    foreach ($image_paths as $image_path) {
      $tweet['media_paths'][] = $image_path;
    }

    $this->postManager->doPost($tweet);
  }

}

module_custom.service.yml

services:
  custom_module.post_tweet:
    class: '\Drupal\custom_module\Service\PostTweet'
    arguments:
      - '@plugin.network.manager'
      - '@social_post.user_manager'
      - '@x_post.manager'
      - '@entity_type.manager'
      - '@messenger'
      - '@logger.factory'
      - '@string_translation'
      - '@current_user'
      - '@current_route_match'
🇪🇸Spain interdruper

Patch attached. A new release for the module is suggested.

🇪🇸Spain interdruper

#59 does not apply over 2.0.0-alpha2 release.
#58 applies, but it crashes because file /templates/responsive-embed.html.twig from #59 is not included in the patch #58.

🇪🇸Spain interdruper

#25 missed update the function baseFieldDefinitions(). Re-rolled as #26 with the update.

🇪🇸Spain interdruper

#2 is not related. Playlists were not created due to some bugs in the code. This patch fix them.

The patch also enhances the update functions to only save the videos and playlists if there has been any change. In the current release, all video nodes and playlist terms are res-saved on each run.

The patch has been tested over a channel with 130 playlists and 2500 videos on D10 and PHP8.2.

🇪🇸Spain interdruper

Summary renderization was not covered in all cases in the patch #11. New patch attached.

🇪🇸Spain interdruper

Patch for 8.x-1.16 with the approach suggested by @sime in #9 is provided.

🇪🇸Spain interdruper

I did not realize that it was inside bs_theme documentation. Sorry for the mistake.

🇪🇸Spain interdruper

This feature does not seem exist in D10. The keyword preload-font is not documented ( https://www.drupal.org/docs/develop/theming-drupal/defining-a-theme-with-an-infoyml-file ) and after test it in a custom subtheme, it does not add the required statement in the html.html.twig template:

<link rel="preload" as="font" href="/fonts/custom-font.woff2" type="font/woff2" crossorigin="anonymous">
🇪🇸Spain interdruper

@loze is right, that snippet always will be true, and the return will be executed.

$item cannot be null (since it triggers the event), so the check just can be:

    if ($item->original) {
      return;
    }
    if ($order && !in_array($order->getState()->value, ['draft', 'canceled'])) {

      $diff = $item->original->getQuantity() - $item->getQuantity();

for avoiding the warning if $item->Original is NULL.

The code that truly fixes the issue error is the other snippet contained in the patch:

@@ -158,7 +160,7 @@ class OrderEventSubscriber implements EventSubscriberInterface {
    */
   public function onOrderUpdate(OrderEvent $event) {
     $order = $event->getOrder();
-    $original_order = $order->original;
+    $original_order = empty($order->original) ? $order : $order->original;
     $allow_negative = \Drupal::config('commerce_simple_stock.settings')->get('allow_backorder');
 
     if ($original_order) {
🇪🇸Spain interdruper

Patch #63 works fine, but a deprecated notice is triggered under PHP 8.2:
Deprecated function: Creation of dynamic property Drupal\colorbox\Plugin\Field\FieldFormatter\ColorboxResponsiveFormatter::$attachment is deprecated in Drupal\colorbox\Plugin\Field\FieldFormatter\ColorboxResponsiveFormatter->__construct() (line 96 of /colorbox/src/Plugin/Field/FieldFormatter/ColorboxResponsiveFormatter.php)

This patch for 2.0.x fixes the issue.

🇪🇸Spain interdruper

This error is triggered because the code assumes that $order_item->getPurchasedEntity() will always return an entity, but this can return NULL:

/**
 * Gets the purchased entity.
 *
 * @return \Drupal\commerce\PurchasableEntityInterface|null
 *   The purchased entity, or NULL.
 */
public function getPurchasedEntity();

This can easily happen in practice, when locked carts contains a product variation that have been deleted.

An simplier alternative patch to #1 is provided.

🇪🇸Spain interdruper

Besides (correctly) handle the coupon usage per-customer limit functionality, the latest commit also relies in the parent coupon entity date fields:

    $fields['start_date'] = BaseFieldDefinition::create('datetime')
      ->setLabel(t('Start date'))
      ->setDescription(t('The date the coupon becomes valid.'))
      ->setRequired(FALSE)
      ->setSetting('datetime_type', 'datetime')
      ->setSetting('datetime_optional_label', t('Provide a start date'))
      ->setDefaultValueCallback('Drupal\commerce_promotion\Entity\Promotion::getDefaultStartDate')
      ->setDisplayOptions('form', [
        'type' => 'commerce_store_datetime',
        'weight' => 5,
      ]);

    $fields['end_date'] = BaseFieldDefinition::create('datetime')
      ->setLabel(t('End date'))
      ->setDescription(t('The date after which the coupon is invalid.'))
      ->setRequired(FALSE)
      ->setSetting('datetime_type', 'datetime')
      ->setSetting('datetime_optional_label', t('Provide an end date'))
      ->setDisplayOptions('form', [
        'type' => 'commerce_store_datetime',
        'weight' => 6,
      ]);

... but the parent definitions are not backward-compatible with the previous definitions used by this module:

    $fields['start_date'] = BaseFieldDefinition::create('datetime')
      ->setLabel(t('Start date'))
      ->setDescription(t('The date the promotion becomes valid.'))
      ->setRequired(FALSE)
      ->setSetting('datetime_type', 'date')
      ->setDisplayOptions('form', [
        'type' => 'datetime_default',
        'weight' => 8,
      ]);

    $fields['end_date'] = BaseFieldDefinition::create('datetime')
      ->setLabel(t('End date'))
      ->setDescription(t('The date after which the promotion is invalid.'))
      ->setRequired(FALSE)
      ->setSetting('datetime_type', 'date')
      ->setDisplayOptions('form', [
        'type' => 'commerce_end_date',
        'weight' => 9,
      ]);

So any dates defined on coupons created previously using this module are not available after applying the last commit...

🇪🇸Spain interdruper

Initial work to make possible to set a start date and an optional end date. Default values are retrieved from the promotion dates, if they exist.

Production build 0.69.0 2024