Posting to Bluesky via the API from PHP – Part Three – Links

So far we have looked at making a connection to Bluesky, posting text and images. In this post I want to look at how links are handled. Unlike X and Mastodon on Bluesky when you post text that includes one or more links these are not parsed and activated. You have to tell Bluesky that you have links in your text and where they are.

Parsing for Links

In order for links to be handled correctly by Bluesky in addition to the text itself you also need to pass an array as part of the parameters giving the start and end character of each URL and the URL itself.

To do this I have created a new function that parses a given piece of text and returns an array with the information required.

 function mark_urls($text) {

    $regex = '/(https?:\/\/[^\s]+)/';
    preg_match_all($regex, $text, $matches, PREG_OFFSET_CAPTURE);

    $urlData = array();

    foreach ($matches[0] as $match) {
        $url = $match[0];
        $start = $match[1];
        $end = $start + strlen($url);

        $urlData[] = array(
            'start' => $start,
            'end' => $end,
            'url' => $url,
        );
    }

    return $urlData;
  }

Building the Parameters

Like before we next have to create the parameter array in the correct format expected by Bluesky. This requires a separate “features” block for each link that is in the text and returned by the mark_urls function. We put this together as follows:

    // parse for URLS
    $urls = mark_urls($text);
    $links = array();
    if (!empty($urls)){
      foreach ($urls as $url) {
        $a = [
          "index" => [
            "byteStart" => $url['start'],
            "byteEnd" => $url['end'],
          ],
          "features" => [
            [
                '$type' => "app.bsky.richtext.facet#link",
                'uri' => $url['url'], 
            ],
          ],
        ];

        $links[] = $a;
      }
      $links = [
        'facets' =>
          $links,
      ];
    }

Once again this then needs to be merged with the parameters that we created for sending text to Bluesky using the array_merge function to slot the parameters into the correct place.

$args['record'] = array_merge($args['record'], $links);

// send to bluesky
$connection->request('POST', 'com.atproto.repo.createRecord', $args);

It is, of course, possible to post both images and have active links and I’ll look at that in the last post.

Putting it all Together

Taking all of the above and the previous posts together that gives us the following:

    $password = '<your API password>';
    $handle = '<your Bluesky handle>';
    $text = 'Hello World! https://spokenlikeageek.com';

    // connect to Bluesky API
    $connection = bluesky_connect($handle, $password);

    // build the arguments
    $args = [
      'collection' => 'app.bsky.feed.post',
      'repo' => $connection->getAccountDid(),
      'record' => [
        'text' => $text,
        'langs' => ['en'],
        'createdAt' => date('c'),
        '$type' => 'app.bsky.feed.post',
      ],
    ];

    // parse for URLS
    $urls = $this->mark_urls($text);
    $links = array();
    if (!empty($urls)){
      foreach ($urls as $url) {
        $a = [
          "index" => [
            "byteStart" => $url['start'],
            "byteEnd" => $url['end'],
          ],
          "features" => [
            [
                '$type' => "app.bsky.richtext.facet#link",
                'uri' => $url['url'], 
            ],
          ],
        ];

        $links[] = $a;
      }
      $links = [
        'facets' =>
          $links,
      ];
    }

    $args['record'] = array_merge($args['record'], $links);

    // send to bluesky
    $connection->request('POST', 'com.atproto.repo.createRecord', $args);

In the next post we look at how to add previews of weblinks in your posts.

Leave a Reply

Your email address will not be published. Required fields are marked *