Automatically tweet published content

Table of contents

In this article, we are going to demonstrate how to use Social API modules to automatically post on social media from your Drupal website. We are going to demonstrate how to tweet when a content gets published. The recipe is also valid for posting on Facebook, LinkedIn or other social networks, as well as reacting to any other kind of events, such as a greeting a new user, announcing end of reservations for your social event, or whatever you have in mind.

To perform this, we will use the Social API suite of modules, built by the Drupal Social Initiatives.

Installation and requirements

During the setup of my website, I felt the suite of modules we will use to be still immature and not ready for Drupal 9. To get things working together, I had to trick the installation process and produce and use a few patches. I will update this article as the patches get included in the modules, hopefully getting this installation as easy as any other Drupal module. Meanwhile, here a complete walkthrough the installation process.

  1. Install Social API module
    This module aims at harmonizing the usage of Social networks in general in Drupal.
    composer require drupal/social_api
    Beware: to use this module in the following, you will need to patch it with:
    https://www.drupal.org/files/issues/2020-10-25/token_encrypted_twice--3178819-3.patch

    See more info on this issue.
  2. Install Social Post module
    This module provides a unified interface for social network autoposting sub-modules.
    git clone --branch 8.x-2.x https://git.drupalcode.org/project/social_post.git
    This module is not yet available for Drupal 9, plus have a few issues. This is the reason why we don't install it via composer. You will also need to patch is with:
    https://www.drupal.org/files/issues/2020-11-06/prepare_for_d9--3156341-6.patch

    See more info on this issue.
  3. Install Social Post Twitter module
    This module prepares this website by setting credentials to use Twitter API. It also provides a mechanism to let users to give permission to Drupal to post on their behalf in their twitter feed.
    composer require drupal/social_post_twitter
    This module is D9 ready in its dev branch. But since it requires Social Post lacking a D9 compatible version, composer won't be able to install it at the moment. In this case, use:
    git clone --branch 8.x-2.x https://git.drupalcode.org/project/social_post_twitter.git

    Also, it takes to patch it with both:
    - https://www.drupal.org/files/issues/2020-10-25/link_drupal_user_twitter_account--3105779-13.patch
    - https://www.drupal.org/files/issues/2020-10-25/undefined_getlogger--3107128-3.patch

    See more info on this issue and this one.
  4. Install Twitter OAuth PHP dependency
    composer require abraham/twitteroauth:~0.7
    This step is not needed on D8 or if Social Post Twitter was installable via composer at previous step.
  5. Activate all three modules: Social API, Social Post, Social Post Twitter
Activate all social modules
Activate all social modules

Configurations

  1. Authenticate your Drupal website using its Twitter App credentials
    1. Go to "Configuration > Social API Settings > Autoposting settings > Twitter" (/admin/config/social-api/social-post/twitter)
    2. Fill your Consumer API Key as well as your Consumer Secret
    3. You will find there the appropriate callback URL to configure Twitter with
    4. Save this configuration
  2. Associate a user to its Twitter account and collect his authorization to post on his behalf.
    1. Go to a user profile edit page
    2. Find the Social Post Twitter panel and click "Add account"
    3. Sign In if necessary and authorize the application
Twitter and Drupal accounts are linked
Twitter and Drupal accounts are linked
If something goes wrong at this stage, have a look at your logs. The module will have logged Twitter reply under the type social_post_twitter and it will surely give you an explicit code number and reason that you can check in twitter documentation.
Example d'erreur d'appairage de compte dans les logs
Example for account authorization error found in Drupal logs.

Usage

Rules integration

One way to use our setup is to integrate the tweet post to a rule. Social Post Twitter module conveniently exposes an action rule for this purpose.

  1. Fix Social Post Twitter action rule
    This step should not be required any more in a near future. But at the moment, we have to patch the module with the following:
    https://www.drupal.org/files/issues/2020-10-26/fix_tweet_rule_action--3178921-2.patch
    (see more about this issue)
  2. Install and enable Rules module
    composer require drupal/rules
    For Drupal 9, currently use: composer require drupal/rules:3.x-dev
  3. Configure your rule. This article is not meant to be a tutorial on rules, so I won't elaborate on how to build it. For our example, we will react to an article being published.
    1. Add a new action
      Add a new rule action
      Add a new rule action.
    2. Choose Tweet action type under the Social Post section.
      Choose Tweet action type
      Choose Tweet action type.
    3. You can now configure any tweet text content. As per any rules, you can use data selector to add variables from the article being published. For instance:
      A new article "{{ node.title.value }}" has been published on my website at {{ node | entity_url }}
      Tweet action for rules: content configuration
      Tweet action for rules: content configuration.

Let's just test our new rule. In this testing scenario, I just have to publish a new article and check my twitter testing account to see a new tweet, automatically published.

New tweet, published by Rules module on my Twitter account
New tweet, published by Rules module on my Twitter account

Programmatic usage

The following section will demonstrate the usage of auto tweeting programmatically. This approach is more powerful than using the Rules UI but requires some confidence in Drupal coding.

For following will consider an enabled custom module named custom_module. Therefore, the following code belongs to custom_module.module file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/**
 * Implements hook_ENTITY_TYPE_update().
 *
 * On articles: auto-tweet when an article is published.
 */
function custom_module_node_update(\Drupal\node\NodeInterface $node) {
 
  // Only react to article node type.
  if ($node->bundle() == 'article') {
 
    // Act on the publishing of an article.
    if (!$node->original->isPublished() && $node->isPublished()) {
 
      // Gets the user manager to retrieve tokens for a user.
      /** @var \Drupal\social_post\User\UserManager $user_manager */
      $user_manager = \Drupal::service('social_post.user_manager');
 
      // Gets all the Twitter accounts associated with the node author account.
      $accounts = $user_manager->getAccounts('social_post_twitter', $node->getOwnerId());
 
      // If no twitter account linked, the rest is useless.
      if (!empty($accounts)) {
 
        // Get tags associated with the node.
        $hashtags = '';
        $tags = $node->get('field_tags')->referencedEntities();
        foreach ((array) $tags as $tag) {
          $hashtags .= "#{$tag->label()} ";
        }
       
        // Build the tweet status.
        $status = t('Hey folks, check out my new blog post !', [], [
            'langcode' => $node->language()->getId()
          ]
        ) . chr(13) . chr(10) . $hashtags;
 
        // Tweets must be less than 140 characters
        // - minus 23 for the wrapped link
        // - minus 2 because of the next linebreak added before the url
        $status = \Drupal\Component\Utility\Unicode::truncate($status, 115, TRUE, TRUE);
 
        // Add the link to the node (added after wrapping the status to not affect the url)
        // it should get transformed to a twitter card.
        $tweet['status'] = $status . chr(13) . chr(10) . $node->toUrl('canonical', [
          'absolute' => TRUE
        ])->toString();
 
        // Gets instance of Social Post Twitter Network plugin.
        /** @var \Drupal\social_post_twitter\Plugin\Network\TwitterPostInterface $plugin */
        $client = \Drupal::service('plugin.network.manager')
          ->createInstance('social_post_twitter')
          ->getSdk();
 
        // Gets the twitter post manager to tweet.
        /** @var \Drupal\social_post_twitter\TwitterPostManager $post_manager */
        $post_manager = \Drupal::service('twitter_post.manager');
 
        /** @var \Drupal\social_post\Entity\SocialPost $account */
        foreach ((array) $accounts as $account) {
          // Build credentials for that particular twitter account.
          $access_token = json_decode($account->getToken(), TRUE);
          // Post our tweet on behalf of the user to this associated twitter account.
          $post_manager
            ->setClient($client)
            ->setOauthToken(
              $access_token['oauth_token'],
              $access_token['oauth_token_secret']
            )
            ->doPost($tweet);
        }
      }
    }
  }
}

The code is far easier than it looks and is probably self-explanatory with the comments embedded. However, here are a few comments:

  • to mimic what we did in Rules UI, we are only going to react to nodes of type article that becomes published. This can be easily be made better by defining a custom per-node third party settings allow/disable the auto-tweet for this node
  • using the social_post user manager, we retrieve the configured Twitter accounts associated with the node author account, such as configured in this article before
  • if twitter accounts have been found, we build the tweet itself. As per twitter API itself, it has to be a string within an array indexed with the key "status". Note the following tricks:
    • usage of langcode key in the t() method: we are translating the tweet in the language of the node itself.
    • by the concatenation of t() method's result and a string, we ensure a pure string in the "status". However, if your tweet is only a translatable string, you will have to use the following to ensure the return type to be a string, not a stringable object:
      t('your tweet')->toString()
    • to post a multiline string, the twitter API has to receive \n\r newlines. This is the purpose of the concatenation of
      chr(13) . chr(10)
  • tweets from the API are limited to 140 characters. Here is how twitter counts it :
    • we want the full URL to be added so it can be transformed to a twitter card, therefore, we must have the URL not be truncated
    • Twitter wraps URL in a shorten 23 characters URLs, so we have to count that out in our truncate
  • we load the twitter_post.manager but it has to be initiated with the twitter client itself configured in the UI has we did earlier in this article. This ensures the usage of a client with proper credentials, authorized by the user to post on his behalf
  • finally, we can set the credentials of the Twitter account itself and post
Tweet automatically published on my twitter account
Tweet automatically published on my twitter account

In a nutshell

In this article, we did setup auto-tweeting from our Drupal website using the Social API modules suite.
We have seen how to configure those modules and use it to post on twitter both using Rules UI and/or programmatically.

In the same way, we can use this suite of modules to publish on other social networks.

Commentaires

Akin

Hello, does this still work?

I can't seem to get beyond adding an account before it throws the the 'user manager' error in log. Any help will be appreciated.

Hi ! It should work fine indeed, I had no trouble to set this up a few weeks ago. Can you let me know more about the error you have ? Do you have some more logs about it ? I am not the module maintainer, but I can patch it for sure.

Alternatively, can you try the following :

  • go to the twitter settings at /admin/config/social-api/social-post/twitter
  • copy the URL given in callback URLs field, it should end up with something like /user/social-post/twitter/auth/callback
  • paste this in your browser, you will get redirected to your user account in drupal
  • from there, retry to "add account" to link with your twitter account

Also make sure you are logged to twitter.

Let me know about all this !

Rar9

Hi I´m also struggling on your post.
I' only llokg for a easy way to post content somewaht automated to social platforms

I only installed all modules via composer as "2.x-dev" and applied your given patches, running under D9.1.2

Social_post + Social_FB +Social_Twitter seam to be Social API (>= 8.x-2.x) (incompatible with version ).

Hi! Please understand that I don't own those modules, so I can't actually fix anything besides offering patches.

I have no idea about social_fb, however, social_post_twitter can be set to work - providing you patch it a lot, like explained in this article. I can confirm you that since this very website uses it to post automatically on my twitter account when I publish an article. The website is always up-to-date with the latest Drupal 9 version. I use it with the second paragraph usage, meaning via the code. I don't use it via rules.

Have you read and follow the article carefully ? No step can be skipped. If you need some help with issue on the module themselves, please consider opening an issue at the module issue queue on drupal.org. However, if you struggle to understand the steps in this article, please give me some more details on where you are, what issue you experience, etc. I may be able to help with the twitter part (I don't use the FB module).

Raro

Please note that twitter.com no longer restricts to 140 but 280 characters

Sparsh

I have successfully installed all the modules with patches. However, I am getting this error while adding an account.

TypeError: Argument 5 passed to Drupal\social_api\Plugin\NetworkBase::__construct() must be an instance of Drupal\Core\Logger\LoggerChannelFactoryInterface, instance of Drupal\Core\Entity\EntityTypeManager given, called in /code/modules/contrib/social_post_twitter/src/Plugin/Network/TwitterPost.php on line 91 in Drupal\social_api\Plugin\NetworkBase->__construct() (line 83 of /code/modules/contrib/social_api/src/Plugin/NetworkBase.php)

Is there any patch that will help to fix it? Any help would be apppreciated.

Add new comment

Your name will be publicly displayed along with your comment.
Your email will be kept private and only used to notify you.
On internet, you can be who you want. Please be someone nice :)