Skip to main content

Supply a transcript URL from your own service

Free Intermediate

Core’s Podcasting 2.0 auto-detection scans an episode’s attached media for a single .vtt, .srt or .txt file and writes the one it finds to the Transcript URL field. This filter is the seam for everything else — a transcription service, an S3 bucket, a naming convention on your own CDN.

It runs only when the Transcript URL field is empty, so a URL you return can never overwrite one the podcaster typed — you don’t need to check that yourself.

$url is core’s detected URL, or null when core found nothing usable — either no transcript-shaped attachment, or more than one, which core deliberately refuses to guess between. You cannot tell those two apart from here; if you need to, read the attachments yourself.

Returning a non-empty string also suppresses the “several transcript files are attached” admin notice, because the field no longer needs a human to fill it. Return null (or '') to leave the field alone — that is how you switch core detection off.

The stored type is inferred from the URL’s extension (.vtttext/vtt, .srtapplication/srt, .jsonapplication/json, .txttext/plain, .htmltext/html). An extension not in that list leaves the stored type untouched rather than forcing a wrong one — so a URL with no extension, or one behind a signing endpoint, keeps whatever the podcaster chose in the dropdown.

It fires inside EpisodeMetaSaver::save(), which every save path routes through, so one callback covers the React editor’s REST save, the classic editor and your own save() calls. ⚠ It does not fire on a save that never reaches the saver — a bare wp_update_post() with no Benecaster meta in play writes nothing and detects nothing.

To disable core detection entirely — for instance because your own admin screen owns the field:

add_filter( 'benecaster_podcast2_transcript_autodetect', '__return_null', 99 );

Code

<?php
add_filter(
    'benecaster_podcast2_transcript_autodetect',
    function ( ?string $url, int $episode_id ): ?string {
        // Let core's media-library detection win when it found something.
        if ( null !== $url ) {
            return $url;
        }

        $external_id = get_post_meta( $episode_id, '_my_service_transcript_id', true );
        if ( '' === $external_id ) {
            return null; // Nothing to offer — leave the field empty.
        }

        // Keep the extension: it is what sets the transcript type.
        return 'https://transcripts.example.com/' . rawurlencode( (string) $external_id ) . '.vtt';
    },
    10,
    2
);

View on GitHub →

Hooks Used

Need this built rather than just documented? See our services →