Giantpaper.org

Tag: php

  • Activitypub: “Video” Post Tweak

    Activitypub: “Video” Post Tweak

    // Make sure Activitypub services embed videos
    // plugin will skip embedding videos if it detects a feat. image
    // @param obj $ap_obj    An object array of the post for Activitypub to use
    add_filter('activitypub_activity_object_array', function($ap_obj){
      // The "id" key is actually the URL/permalink of the post, not the post ID.
      // Get post ID from the permalink
      $post_id = url_to_postid($ap_obj['id']);
      // Check if a #video micropost
      if (has_tag('video', $post_id) && has_category('microblog', $post_id)) {
        // Remove any media attachments
        $ap_obj['attachment'] = [];
      }
      return $ap_obj;
    }, 100);

    This code assumes you categorize and tag your posts the same way I do (“Microblog” for as the category, and “video” for tag). You might want to change it to fit your own system.

    Change this line: if (has_tag('video', $post_id) && has_category('microblog', $post_id)) {

    The Activitypub Object Array?

    The filter activitypub_activity_object_array is used to modify the object array of the post. This is completely different from WP_Post. You can see the object array of each post by appending /activitypub to a post. Ex. https://test.giantpaper.org/microblog/10766/200-kids-sing-civilization-theme/activitypub/ (source)

    Background

    I have a lot of “video” type posts, where the main content is a single video. If the post contains a “post thumbnail”, the Activitypub plugin automatically considers it media (along with any other images you might have added).

    This post on Mastodon

    In video posts, this is usually the poster image/thumbnail/preview image of the video. Which would be great, EXCEPT I want the video itself (as in, actually embedded) to be the main feature, not the video thumbnail. The above code removes the featured image from the media array, so the video gets embedded instead.

  • Giantpaper on the Fediverse: Back and Better than Ever!

    Giantpaper on the Fediverse: Back and Better than Ever!

    Ever since the Great Federating of Giantpaper, I’ve been thinking about how I would get Activitypub to correctly display the different types of blog posts I have set up. Ex: this post, which looked like this on Mastodon:

    Or this one, which turned into this:

    There were some things I learned about WP posts ending up on the Fediverse through this plugin:

    • Custom fields (like those generated by Advanced Custom Fields) don’t get included, so links from my linklog posts won’t appear (which is why this post was posted as a micropost instead of a linkpost)
    • Most HTML gets stripped out by some Fedi services like Mastodon, which is why videos weren’t appearing on microposts

    The Activitypub plugin has a setting for tweaking the template that gets used for federation:

    …but there’s no template tag for custom fields (and no way to not have the plugin render video URLs as video embeds).

    Enter Filters

    I saw that there was a PR for making the post template filterable, that was upcoming for v2.0.0. And against my judgement, I jumped at it when it released, thinking there would be some sort of documentation for the new filters, but NOPE. I didn’t even know what the filter was called!! 😬 I did see the addition of a new filter name in v2.0.0.0, which is what I thought it was going to be, but actually trying to use it to filter stuff got me the dreaded “Your author URL does not return valid JSON for application/activity+json. Please check if your hosting supports alternate Accept headers.” error in WordPress’s Site Health page. And also I (somehow) found that outputting the contents of $template from the first parameter that it was actually meant to alter the post template (from the screenshot above with the [ap_....] tags), but I’m trying to figure out how to modify the HTML output of [ap_content]. So that wasn’t it.

    I saw that the plugin repo has a discussion board! And that people actually use said discussion board! I searched “filters” and found “Modifying ActivityPub posts via WordPress filter? #228“. Trying to add a filter for activitypub_post got me an error. So that wasn’t it either.

    (FYI, the filter name wasn’t what I was looking for, but I did find a Very Important Piece of info in the linked thread that helped me debug my code later. More on that later.)

    AND THEN, the search bar at the top, I searched for apply_filters (because if there’s a new way to filter content, it for sure would be added to the code via apply_filters()):

    searching for apply_filters() on Github automattic/wordpress-activitypub

    And there it was: Line 623 in includes/transformer/class-post.php:

    Screenshot showing activitypub_the_content being applied

    After some trial and error, I fiiiiiiiinally got it to work. 😩

    screenshot showing Now or Never by Audiomachine on Mastodon

    Behind the Scenes!

    Here is my (very unofficial) documentation for this:

    /**
     *
     * @param string  $content The outputted HTML of [ap_content]
     * @param WP_Post $post    The post object -- see https://developer.wordpress.org/reference/classes/wp_post/ and https://developer.wordpress.org/reference/functions/get_post/ for more info
     *
     */
    add_filter('activitypub_the_content', function($content, $post){
    
      // add code here
    
      return $content
    
    }, 100, 2);

    First the videos…

    This is just some normal non-WP specific code. So if you’re already familiar with PHP, you might already know this. But to make sure your videos show up in your fediposts:

      // Remove iframes from Youtube videos
      $content = preg_replace(
        "#<figure[^>]+><div[^>]+><iframe.+ src=\"https://www\.youtube\.com/embed/(.+)\?[^\"]+\".+></iframe></div></figure>#",
        "<p><a href=\"https://youtube.com/watch?v=\\1\">https://youtube.com/watch?v=\\1</a></p>",
        $content
      );
      // Remove iframes from Vimeo videos
      $content = preg_replace(
        "#<figure[^>]+><div[^>]+><iframe.+ src=\"https://player\.vimeo.com/video/(.+)\?[^\"]+\".+></iframe></div></figure>#",
        "<p><a href=\"https://vimeo.com/\\1\">https://vimeo.com/\\1</a></p>",
        $content
      );

    You’re basically removing the iframes and surrounding <figure> and <div> tags from around the videos and reformatting the embed URLs (inside the src="" attribute) back to their web accessible URLs (so https://www.youtube.com/embed/t476sB13EOghttps://www.youtube.com/watch?v=t476sB13EOg). And then linking to themselves, which will make Mastodon (and maybe other fediservers) think “oh hey, this is a link, let’s put up a preview”, and embeds the video.

    So from this:

    <figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper"><iframe loading="lazy" title="The Prince of Peace" width="500" height="375" src="https://www.youtube.com/embed/AQZqaz10TOM?feature=oembed" frameborder="0" allow="web-share" allowfullscreen></iframe></div></figure>

    To this:

    <p><a href="https://youtube.com/watch?v=AQZqaz10TOM">https://youtube.com/watch?v=AQZqaz10TOM</a></p>

    And the links!

    This uses some more WP-specific PHP to detect what post you’re displaying, but here’s what I have:

    // Linklog -- prepend external link to post
    $href = get_field('external_url', $post->ID);
    if (has_category('linklog', $post)) {
      $content = '<p><a href="' .$href. '">' .$href. '</a></p>' . $content;
    }

    All together now:

    add_filter('activitypub_the_content', function($content, $post){
    	// Remove iframes from Youtube videos
    	$content = preg_replace(
    		"#<figure[^>]+><div[^>]+><iframe.+ src=\"https://www\.youtube\.com/embed/(.+)\?[^\"]+\".+></iframe></div></figure>#",
    		"<p><a href=\"https://youtube.com/watch?v=\\1\">https://youtube.com/watch?v=\\1</a></p>",
    		$content
    	);
    	// Remove iframes from Vimeo videos
    	$content = preg_replace(
    		"#<figure[^>]+><div[^>]+><iframe.+ src=\"https://player\.vimeo.com/video/(.+)\?[^\"]+\".+></iframe></div></figure>#",
    		"<p><a href=\"https://vimeo.com/\\1\">https://vimeo.com/\\1</a></p>",
    		$content
    	);
    
    	// Linklog -- prepend external link to post
    	$href = get_field('external_url', $post->ID);
    	if (has_category('linklog', $post)) {
    		$content = '<p><a href="' .$href. '">' .$href. '</a></p>' .$content;
    	}
    	return $content;
    }, 100, 2);

    Edit

    Updated code to handle syntax highlighting better (it looks REEEALLY bad on Mastodon).

    Edit #2

    Mastodon does not apply monospace fonts to <pre>. TIL

    Edit #3

    Fixed syntax error in the last code snippet. Getting PHP and Javascript mixed up.

  • Bandcamp snippet for self-hosted WordPress sites

    Bandcamp snippet for self-hosted WordPress sites

    Git Update

    Ok, nevermind, it’s on Github. To download, you can clone it to your computer. Or if you’re not a Github user and don’t care about Github, go to the main repo page and click the big green Code button at the top right and Download ZIP File.

    Github options to download a repo

    Also, I made some big changes with how the parameters get plugged into the iframe (better flexibility, so issues like the one that happened today won’t happen), but does not change your usage of the shortcode. Just a heads up, if you’ve modified your version of the code.

    Update // 2021.09.30

    Fixed a bug with percentages as widths/heights—If you’re using a percentage as your width/height in your shortcode (ex. width=100%), it will output as width="100%px". Obviously not ideal, so this has been updated.

    Fixed a bug with different player sizes—For some reason, I didn’t think about the iframe’s src URL changing if you select a different player size (ex. size=small instead of size=large which is what I used for this snippet). So this takes into account the different player sizes, as well as artwork sizes.

    The lines that were updated were:

    • 13
    • 23-28
    • 31
    • 39

    (I may create a git repo for this, with all the changes.)

    Update // 2021.03.19:

    Just saw this post:

    bandcamp embed code not working — Apparently, the official method of adding Bandcamp support is to install the Jetpack plugin. 😬 If you’re already using it for other stuff, I’m sure it’s a great way to go. But I don’t want to install Jetpack just for that one embed code. Bleh. I’ll take my homebrewed method any day, thanks!

    Update // 2021.04.10

    Lighthouse yelled at me for not adding a title attribute to the iframe (for accessibility purposes). So I tweaked the code to allow a customizable title attribute. When you copy and paste your shortcode into WP, just add title="Your title" to the shortcode, obviously replacing “Your title” with the actual name of the album you’re embedding. In the case above, I changed the shortcode to:

    Be sure to enclose the attribute value with double quotes if there’s going to be a space, otherwise only the first word will be used for the title. So in this case:

    …only Cosmagora would be included in the title and everything else will be ignored.


    Original Post

    Apparently WordPress.com already has support for Bandcamp shortcodes. But what if you’re on a self-hosted WordPress site? You can create your own shortcode, using add_shortcode().

    Here’s what I have in my functions.php file:

    <?php
    
    add_shortcode('bandcamp', function($attr=[]){
        $attr = shortcode_atts([
            'width' => 350,
            'height' => 470,
            'album' => null,
            'title' => null,
            'size' => 'large',
            'bgcol' => 'ffffff',
            'url' => null,
            'linkcol' => '0687f5',
            'tracklist' => 'false',
            'title' => null,
            'artwork' => null,
        ], $attr);
    
        extract($attr);
    
        if ($album == null)
            return false;
    
        if ( preg_match("#^[0-9]+$#", $width) ) {
            $width = $width.'px';
        }
        if ( preg_match("#^[0-9]+$#", $height) ) {
            $height = $height.'px';
        }
    
        // the embed code itself
        $iframe = sprintf('<iframe style="border: 0; width: %s; height: %s;" src="https://bandcamp.com/EmbeddedPlayer/album=%s/size=%s/bgcol=%s/linkcol=%s/tracklist=%s/transparent=true/artwork=%s/" title="%s" seamless></iframe>',
    	$width,
    	$height,
            $album,
            $size,
            $bgcol,
            $linkcol,
            $tracklist,
            $artwork,
            $title,
        );
    
        // if your site uses Gutenberg
        // this is veerrrry....sloppily creating your own block
        return '<figure class="wp-block-embed-bandcamp wp-block-embed is-type-audio is-provider-bandcamp wp-embed-aspect-16-9 wp-has-aspect-ratio js">' . '<div class="wp-block-embed__wrapper">' . $iframe . '</div>' . '</figure>';
    });

    The $iframe variable is the important part. Obviously, if you’re not using Gutenberg, you can just delete the entire return sprintf('<figure thing of code and end the entire function with return $iframe;

    (Yes, Gutenberg lets you easily add an HTML snippet, but it considers Bandcamp embed codes “invalid”. Uh huh.)

    Generating a Bandcamp shortcode

    Go the album you want to embed (we’ll use Cosmagora as an example). Under the album artwork, click Share / Embed, then Embed This Album.

    You’ll get a window showing the different player styles.

    You’ll get another window with options to customize your player further, along with the embed code.

    Two important things:

    • be sure to check wordpress.com in the top left, so it gives you the shortcode, rather than the HTML version
    • customizing it might add some HTML attributes not in the above PHP code. If that’s the case, you can add them through the shortcode_atts() function

    Aaaand that’s it! Happy Bandcamping!

    More info:

  • Cleaning up Rank Math Turds!

    Cleaning up Rank Math Turds!

    Daaaaaayuuum, Rank Math.

    I was using Rank Math for a while after switching over from the SEO Framework. Then I decided to give TSF another try after reading some unfavorable reviews about Rank Math.

    (more…)