Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.30% covered (success)
96.30%
52 / 54
83.33% covered (warning)
83.33%
5 / 6
CRAP
n/a
0 / 0
wpcom_podcast_feed_credit_maybe_hook
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
3.02
wpcom_podcast_feed_credit_append_to_summary
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
wpcom_podcast_feed_credit_append_to_excerpt
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
wpcom_podcast_feed_credit_append_to_content
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
3
wpcom_podcast_feed_credit_text
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
2
wpcom_podcast_feed_credit_show_title
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
5
1<?php
2/**
3 * Appends a "Made with Jetpack Podcast" credit to the podcast feed of sites
4 * without podcast plan access.
5 *
6 * @package automattic/jetpack-mu-wpcom
7 */
8
9use Automattic\Jetpack\Podcast\Feed\Customize_Feed;
10use Automattic\Jetpack\Podcast\Podcast_Gate;
11
12/**
13 * Hook the credit once the podcast package has claimed this request as the
14 * podcast feed. The package registers on `wp` at priority 10, so this runs at 11.
15 */
16function wpcom_podcast_feed_credit_maybe_hook() {
17    if ( ! has_action( 'rss2_head', array( Customize_Feed::class, 'output_channel_tags' ) ) ) {
18        return;
19    }
20    if ( Podcast_Gate::has_product_access() ) {
21        return;
22    }
23    // The package reads the channel summary through `get_option()`, so both
24    // `<description>` and `<itunes:summary>` pick the credit up here.
25    add_filter( 'option_podcasting_summary', 'wpcom_podcast_feed_credit_append_to_summary' );
26    add_filter( 'default_option_podcasting_summary', 'wpcom_podcast_feed_credit_append_to_summary' );
27    // Just below the package's `capture_item_summary()` at PHP_INT_MAX, so the
28    // item `<description>` and the `<itunes:summary>` built from it agree.
29    add_filter( 'the_excerpt_rss', 'wpcom_podcast_feed_credit_append_to_excerpt', PHP_INT_MAX - 1 );
30    add_filter( 'the_content_feed', 'wpcom_podcast_feed_credit_append_to_content' );
31}
32add_action( 'wp', 'wpcom_podcast_feed_credit_maybe_hook', 11 );
33
34/**
35 * `option_podcasting_summary` filter: append the credit to the channel summary.
36 *
37 * @param mixed $summary Option value.
38 * @return string
39 */
40function wpcom_podcast_feed_credit_append_to_summary( $summary ) {
41    $summary = rtrim( (string) $summary );
42    return '' === $summary ? wpcom_podcast_feed_credit_text() : $summary . "\n\n" . wpcom_podcast_feed_credit_text();
43}
44
45/**
46 * `the_excerpt_rss` filter: append the credit to the episode `<description>`.
47 * The template wraps it in CDATA, so `]]>` gets the escape core gives
48 * generated excerpts.
49 *
50 * @param string $excerpt Item excerpt.
51 * @return string
52 */
53function wpcom_podcast_feed_credit_append_to_excerpt( $excerpt ) {
54    $excerpt = rtrim( (string) $excerpt );
55    $credit  = str_replace( ']]>', ']]&gt;', wpcom_podcast_feed_credit_text() );
56    return '' === $excerpt ? $credit : $excerpt . "\n\n" . $credit;
57}
58
59/**
60 * `the_content_feed` filter: append the linked credit to `<content:encoded>`.
61 * Empty content stays empty so core falls back to the excerpt, which already
62 * carries the credit.
63 *
64 * @param string $content Item content.
65 * @return string
66 */
67function wpcom_podcast_feed_credit_append_to_content( $content ) {
68    if ( '' === (string) $content ) {
69        return $content;
70    }
71    $site_url = home_url( '/' );
72    $title    = wpcom_podcast_feed_credit_show_title();
73    $product  = '<a href="https://wordpress.com/podcast/">Jetpack Podcast</a>';
74    $link     = '<a href="' . esc_url( $site_url ) . '">' . esc_html( $site_url ) . '</a>';
75
76    if ( '' === $title ) {
77        $credit = sprintf(
78            /* translators: 1: HTML link to "Jetpack Podcast", 2: HTML link to site URL */
79            esc_html__( 'This podcast is made with %1$s. Full show notes and every episode at %2$s', 'jetpack-mu-wpcom' ),
80            $product,
81            $link
82        );
83    } else {
84        $credit = sprintf(
85            /* translators: 1: podcast title, 2: HTML link to "Jetpack Podcast", 3: HTML link to site URL */
86            esc_html__( '%1$s is made with %2$s. Full show notes and every episode at %3$s', 'jetpack-mu-wpcom' ),
87            esc_html( $title ),
88            $product,
89            $link
90        );
91    }
92    return (string) $content . "\n<p>" . $credit . '</p>';
93}
94
95/**
96 * Plain-text credit, for `<description>` and `<itunes:summary>`.
97 *
98 * @return string
99 */
100function wpcom_podcast_feed_credit_text(): string {
101    $title = wpcom_podcast_feed_credit_show_title();
102
103    if ( '' === $title ) {
104        return sprintf(
105            /* translators: 1: "Jetpack Podcast", 2: site URL */
106            __( 'This podcast is made with %1$s. Full show notes and every episode at %2$s', 'jetpack-mu-wpcom' ),
107            'Jetpack Podcast',
108            home_url( '/' )
109        );
110    }
111
112    return sprintf(
113        /* translators: 1: podcast title, 2: "Jetpack Podcast", 3: site URL */
114        __( '%1$s is made with %2$s. Full show notes and every episode at %3$s', 'jetpack-mu-wpcom' ),
115        $title,
116        'Jetpack Podcast',
117        home_url( '/' )
118    );
119}
120
121/**
122 * The show title for the credit: `podcasting_title`, else the site name.
123 * A site name that is just the site's slug or host is no title at all, so
124 * it yields '' and the credit goes subjectless rather than reading
125 * "example78687615498 is made with".
126 *
127 * @return string '' when there is nothing worth calling the show.
128 */
129function wpcom_podcast_feed_credit_show_title(): string {
130    $host = strtolower( (string) wp_parse_url( home_url(), PHP_URL_HOST ) );
131    $slug = strstr( $host, '.', true );
132    $junk = array_filter( array( $host, false === $slug ? '' : $slug ) );
133
134    foreach ( array( get_option( 'podcasting_title', '' ), get_bloginfo( 'name' ) ) as $candidate ) {
135        $candidate = trim( wp_strip_all_tags( (string) $candidate ) );
136        if ( '' !== $candidate && ! in_array( strtolower( $candidate ), $junk, true ) ) {
137            return $candidate;
138        }
139    }
140    return '';
141}