Created
October 16, 2025 02:06
-
-
Save Kevinlearynet/f23c10939fa29a95dcfa1c71fc4ed5ef to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?php | |
| /** | |
| * Apple News | |
| */ | |
| function puck_applenews_author_byline($post_id) { | |
| $post = get_post($post_id); | |
| $slug = get_post_field('post_name', $post_id); | |
| $first_author_id = $post->post_author; | |
| $first_author_name = get_the_author_meta('display_name', $first_author_id); | |
| $first_author_url = get_author_posts_url($first_author_id) . "?utm_source=apple-news&utm_medium=referral&utm_content=author-byline&utm_campaign={$slug}"; | |
| $authors = ["<a href='$first_author_url'>$first_author_name</a>"]; | |
| $second_author_id = get_field('second_author', $post_id); | |
| if (isset($second_author_id) && $second_author_id) { | |
| $second_author_name = get_the_author_meta('display_name', $second_author_id); | |
| $second_author_url = get_author_posts_url($second_author_id) . "?utm_source=apple-news&utm_medium=referral&utm_content=author-byline&utm_campaign={$slug}"; | |
| $authors[] = "<a href='$second_author_url'>$second_author_name</a>"; | |
| } | |
| $third_author_id = get_field('third_author', $post_id); | |
| if (isset($third_author_id) && $third_author_id) { | |
| $third_author_name = get_the_author_meta('display_name', $third_author_id); | |
| $third_author_url = get_author_posts_url($third_author_id) . "?utm_source=apple-news&utm_medium=referral&utm_content=author-byline&utm_campaign={$slug}"; | |
| $authors[] = "<a href='$third_author_url'>$third_author_name</a>"; | |
| } | |
| if (count($authors) == 1) { | |
| $byline = 'By ' . $authors[0]; | |
| } elseif (count($authors) == 2) { | |
| $byline = 'By ' . $authors[0] . ' and ' . $authors[1]; | |
| } else { | |
| $byline = 'By ' . implode(', ', array_slice($authors, 0, -1)) . ', and ' . end($authors); | |
| } | |
| return $byline; | |
| } | |
| /** | |
| * Get attachment caption with photo credit | |
| * | |
| * @param int $attachment_id The attachment ID | |
| * | |
| * @return string The caption with credit appended if available | |
| */ | |
| function puck_applenews_attachment_caption($attachment_id, $italicized = false) { | |
| $caption = wp_get_attachment_caption($attachment_id); | |
| $photo_credit = get_field('credit', $attachment_id); | |
| if ($photo_credit) { | |
| if ($italicized) { | |
| $caption .= ' <em style="color:#767676">'; | |
| } | |
| $caption .= " $photo_credit"; | |
| if ($italicized) { | |
| $caption .= '</em>'; | |
| } | |
| } | |
| return $caption; | |
| } | |
| /** | |
| * Get attachment ID by URL | |
| * | |
| * @param string $url The attachment URL | |
| * | |
| * @return int|null The attachment ID or null if not found | |
| */ | |
| function puck_applenews_attachment_id($url) { | |
| global $wpdb; | |
| $attachment_id = $wpdb->get_var($wpdb->prepare( | |
| "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'attachment' AND guid = %s", | |
| $url | |
| )); | |
| return $attachment_id ? (int) $attachment_id : null; | |
| } | |
| function puck_applenews_authors($post_id) { | |
| $post = get_post($post_id); | |
| $slug = get_post_field('post_name', $post_id); | |
| $authors = []; | |
| $first_author_id = $post->post_author; | |
| if ($first_author_id) { | |
| $authors[] = get_the_author_meta('display_name', $first_author_id); | |
| } | |
| $second_author_id = get_field('second_author', $post_id); | |
| if ($second_author_id) { | |
| $authors[] = get_the_author_meta('display_name', $second_author_id); | |
| } | |
| $third_author_id = get_field('third_author', $post_id); | |
| if ($third_author_id) { | |
| $authors[] = get_the_author_meta('display_name', $third_author_id); | |
| } | |
| return $authors; | |
| } | |
| /** | |
| * Article Theme/Style | |
| */ | |
| add_filter('apple_news_write_json', function ($json, $post_id) { | |
| global $wpdb; | |
| $article = json_decode($json, true); | |
| $post = get_post($post_id); | |
| $category_name = puck_yoast_primary_category('name', $post_id); | |
| $category_slug = puck_yoast_primary_category('slug', $post_id); | |
| $subhead = get_field('subhead', $post_id); | |
| $thumbnail_id = get_post_thumbnail_id($post_id); | |
| $slug = get_post_field('post_name', $post_id); | |
| // Related articles | |
| $related_posts = get_posts([ | |
| 'category' => $category_slug, | |
| 'numberposts' => 3, | |
| 'post__not_in' => [$post_id], | |
| 'post_type' => 'post', | |
| ]); | |
| $article['documentStyle']['backgroundColor'] = '#ffffff'; | |
| $article['layout']['columns'] = 9; | |
| $article['layout']['width'] = 768; | |
| $article['layout']['margin'] = 60; | |
| $article['layout']['gutter'] = 16; | |
| $article['componentTextStyles']['default-title']['fontName'] = 'PuckSerifDisplay-Regular'; | |
| $article['componentTextStyles']['default-title']['fontSize'] = 48; | |
| $article['componentTextStyles']['default-title']['lineHeight'] = 54; | |
| $article['componentTextStyles']['default-title']['textColor'] = '#000000'; | |
| $article['componentTextStyles']['default-title']['tracking'] = 0; | |
| $article['componentTextStyles']['default-author']['fontName'] = 'Inter-Bold'; | |
| $article['componentTextStyles']['default-author']['fontSize'] = 12; | |
| $article['componentTextStyles']['default-author']['lineHeight'] = 12; | |
| $article['componentTextStyles']['default-author']['textColor'] = '#d40000'; | |
| $article['componentTextStyles']['default-author']['tracking'] = 0; | |
| $article['componentTextStyles']['default-author']['textAlignment'] = 'center'; | |
| $article['componentTextStyles']['default-author']['textTransform'] = 'uppercase'; | |
| $article['componentTextStyles']['default-date']['fontName'] = 'Inter-Regular'; | |
| $article['componentTextStyles']['default-date']['fontSize'] = 10; | |
| $article['componentTextStyles']['default-date']['lineHeight'] = 10; | |
| $article['componentTextStyles']['default-date']['textColor'] = '#B2B2B2'; | |
| $article['componentTextStyles']['default-date']['tracking'] = 0; | |
| $article['componentTextStyles']['default-date']['textAlignment'] = 'center'; | |
| // Text styles | |
| $article['componentTextStyles']['default-body'] = [ | |
| 'textAlignment' => 'left', | |
| 'fontName' => 'Inter-Regular', | |
| 'tracking' => 0, | |
| 'fontSize' => 16, | |
| 'lineHeight' => 24, | |
| 'textColor' => '#000000', | |
| 'linkStyle' => [ | |
| 'textColor' => '#d40000', | |
| ], | |
| 'paragraphSpacingBefore' => 18, | |
| 'paragraphSpacingAfter' => 18, | |
| 'hyphenation' => false, | |
| ]; | |
| $article['componentTextStyles']['default-heading-2'] = [ | |
| 'fontName' => 'PuckSerifDisplay-Regular', | |
| 'fontSize' => 30, | |
| 'lineHeight' => 36, | |
| 'textAlignment' => 'left', | |
| 'textColor' => '#000000', | |
| ]; | |
| $article['componentTextStyles']['default-heading-3'] = [ | |
| 'fontName' => 'PuckSerifDisplay-Regular', | |
| 'fontSize' => 30, | |
| 'lineHeight' => 36, | |
| 'textAlignment' => 'left', | |
| 'textColor' => '#000000', | |
| ]; | |
| $article['componentTextStyles']['default-heading-4'] = [ | |
| 'fontName' => 'PuckSerifDisplay-Regular', | |
| 'fontSize' => 30, | |
| 'lineHeight' => 36, | |
| 'textAlignment' => 'left', | |
| 'textColor' => '#000000', | |
| ]; | |
| $article['componentTextStyles']['default-heading-5'] = [ | |
| 'fontName' => 'PuckSerifDisplay-Regular', | |
| 'fontSize' => 30, | |
| 'lineHeight' => 36, | |
| 'textAlignment' => 'left', | |
| 'textColor' => '#000000', | |
| ]; | |
| $article['componentTextStyles']['default-heading-6'] = [ | |
| 'fontName' => 'PuckSerifDisplay-Regular', | |
| 'fontSize' => 30, | |
| 'lineHeight' => 36, | |
| 'textAlignment' => 'center', | |
| 'textColor' => '#000000', | |
| ]; | |
| $article['componentTextStyles']['dropcapBodyStyle'] = [ | |
| 'textAlignment' => 'left', | |
| 'fontName' => 'Inter-Regular', | |
| 'fontSize' => 17, | |
| 'tracking' => 0, | |
| 'lineHeight' => 26, | |
| 'textColor' => '#000000', | |
| 'linkStyle' => [ | |
| 'textColor' => '#d40000', | |
| ], | |
| 'paragraphSpacingBefore' => 18, | |
| 'paragraphSpacingAfter' => 18, | |
| 'dropCapStyle' => [ | |
| 'numberOfLines' => 3, | |
| 'numberOfCharacters' => 1, | |
| 'padding' => 0, | |
| 'fontName' => 'PuckSerifDisplay-Regular', | |
| 'textColor' => '#d40000', | |
| 'numberOfRaisedLines' => 0, | |
| ], | |
| 'conditional' => [ | |
| [ | |
| 'conditions' => [ | |
| 'minViewportWidth' => 415, | |
| ], | |
| 'dropCapStyle' => [ | |
| 'numberOfLines' => 4, | |
| 'numberOfCharacters' => 1, | |
| 'padding' => 0, | |
| 'fontName' => 'PuckSerifDisplay-Regular', | |
| 'textColor' => '#d40000', | |
| 'numberOfRaisedLines' => 0, | |
| ], | |
| ], | |
| ], | |
| ]; | |
| $article['textStyles']['default-tag-cite']['fontName'] = 'Inter-Regular'; | |
| $article['textStyles']['default-tag-code']['fontName'] = 'Inter-Regular'; | |
| $article['textStyles']['default-tag-pre']['fontName'] = 'Inter-Regular'; | |
| $article['textStyles']['default-tag-samp']['fontName'] = 'Inter-Regular'; | |
| $byline = puck_applenews_author_byline($post_id); | |
| // Update header photo caption font | |
| foreach ($article['components'] as &$component) { | |
| if ($component['role'] === 'header') { | |
| // Get existing header image URL and process through CDN | |
| $header_image_url = ''; | |
| if (isset($component['components'])) { | |
| foreach ($component['components'] as $subComponent) { | |
| if ($subComponent['role'] === 'photo' && isset($subComponent['URL'])) { | |
| $original_url = $subComponent['URL']; | |
| $filename = basename($original_url); | |
| $header_image_url = 'https://wsrv.nl/?url=' . $original_url . '&bg=white&tint=c5aeae&gam=1.3&con=-20&filename=' . $filename . '&w=1366'; | |
| break; | |
| } | |
| } | |
| } | |
| $caption = puck_applenews_attachment_caption($thumbnail_id); | |
| $component = [ | |
| 'role' => 'header', | |
| 'layout' => [ | |
| 'ignoreDocumentMargin' => true, | |
| 'ignoreDocumentGutter' => true, | |
| 'ignoreViewportPadding' => true, | |
| 'padding' => [ | |
| 'top' => 24, | |
| 'bottom' => 24, | |
| ], | |
| 'margin' => [ | |
| 'bottom' => 24, | |
| ], | |
| ], | |
| 'style' => [ | |
| 'backgroundColor' => '#000000', | |
| ], | |
| 'conditional' => [ | |
| [ | |
| 'conditions' => [ | |
| 'preferredColorScheme' => 'dark', | |
| ], | |
| 'style' => [ | |
| 'backgroundColor' => '#000000', | |
| ], | |
| ], | |
| ], | |
| 'components' => [ | |
| [ | |
| 'role' => 'title', | |
| 'text' => $article['title'], | |
| 'format' => 'html', | |
| 'textStyle' => [ | |
| 'textColor' => '#FFFFFF', | |
| 'textAlignment' => 'center', | |
| 'fontName' => 'PuckSerifDisplay-Regular', | |
| 'fontSize' => 40, | |
| 'lineHeight' => 40, | |
| ], | |
| 'layout' => [ | |
| 'margin' => ['bottom' => 8], | |
| ], | |
| ], | |
| [ | |
| 'role' => 'intro', | |
| 'text' => $subhead, | |
| 'textStyle' => [ | |
| 'textColor' => '#FFFFFF', | |
| 'fontName' => 'Inter-Regular', | |
| 'fontSize' => 19, | |
| 'lineHeight' => 28, | |
| 'textAlignment' => 'center', | |
| ], | |
| 'format' => 'html', | |
| 'layout' => [ | |
| 'margin' => ['bottom' => 20], | |
| ], | |
| ], | |
| [ | |
| 'role' => 'image', | |
| 'URL' => $header_image_url, | |
| 'layout' => [ | |
| 'ignoreDocumentMargin' => true, | |
| 'ignoreViewportPadding' => true, | |
| 'margin' => ['bottom' => 16], | |
| ], | |
| 'conditional' => [ | |
| [ | |
| 'conditions' => [ | |
| 'preferredColorScheme' => 'dark', | |
| ], | |
| 'style' => [ | |
| 'backgroundColor' => '#000000', | |
| ], | |
| ], | |
| [ | |
| 'conditions' => [ | |
| 'minViewportWidth' => 415, | |
| ], | |
| 'layout' => [ | |
| 'ignoreDocumentMargin' => true, | |
| 'margin' => [ | |
| 'bottom' => 24, | |
| ], | |
| ], | |
| ], | |
| ], | |
| ], | |
| [ | |
| 'role' => 'caption', | |
| 'text' => $caption, | |
| 'textStyle' => [ | |
| 'fontName' => 'Inter-Regular', | |
| 'textColor' => '#ffffff', | |
| 'fontSize' => 10, | |
| 'lineHeight' => 14, | |
| ], | |
| 'format' => 'html', | |
| ], | |
| ], | |
| ]; | |
| break; | |
| } | |
| } | |
| // Body container | |
| foreach ($article['components'] as &$component) { | |
| if ($component['role'] === 'container' && isset($component['components'])) { | |
| // Remove title | |
| foreach ($component['components'] as $index => $subComponent) { | |
| if ($subComponent['role'] === 'title') { | |
| unset($component['components'][$index]); | |
| $component['components'] = array_values($component['components']); // Reindex array | |
| break; | |
| } | |
| } | |
| // Add captions after photos | |
| foreach ($component['components'] as $index => &$subComponent) { | |
| if ($subComponent['role'] === 'photo') { | |
| $attachment_url = preg_replace('/-\d+x\d+\.([a-z]+)$/i', '.$1', $subComponent['URL']); | |
| $attachment_fullsize = "https://wsrv.nl/?url=$attachment_url&w=1280&output=webp"; | |
| $subComponent['URL'] = $attachment_fullsize; | |
| $attachment_id = puck_applenews_attachment_id($attachment_url); | |
| $caption = puck_applenews_attachment_caption($attachment_id, true); | |
| if (! $caption) { | |
| continue; | |
| } | |
| $subComponent['layout'] = 'full-width-image-with-caption'; | |
| $caption_component = [ | |
| 'role' => 'caption', | |
| 'text' => $caption, | |
| 'format' => 'html', | |
| 'layout' => 'photo-caption', | |
| 'textStyle' => [ | |
| 'fontName' => 'Inter-Regular', | |
| 'textColor' => '#000000', | |
| 'fontSize' => 10, | |
| 'lineHeight' => 12, | |
| ], | |
| ]; | |
| array_splice($component['components'], $index + 1, 0, [$caption_component]); | |
| } | |
| } | |
| } | |
| } | |
| // Update author and byline components | |
| foreach ($article['components'] as &$component) { | |
| if ($component['role'] === 'container' && isset($component['components'])) { | |
| foreach ($component['components'] as &$subComponent) { | |
| if ($subComponent['role'] === 'author') { | |
| $subComponent['text'] = $byline; | |
| $subComponent['format'] = 'html'; | |
| } | |
| if ($subComponent['role'] === 'byline') { | |
| $subComponent['text'] = get_post_time('F j, Y', false, $post_id); | |
| } | |
| } | |
| } | |
| if ($component['role'] === 'container' && isset($component['style']['backgroundColor']) && $component['style']['backgroundColor'] === '#fafafa') { | |
| $component['style']['backgroundColor'] = '#ffffff'; | |
| } | |
| } | |
| // Add category/section text component before authors | |
| foreach ($article['components'] as &$component) { | |
| if ($component['role'] === 'container' && isset($component['components'])) { | |
| $author_index = null; | |
| foreach ($component['components'] as $index => $subComponent) { | |
| if ($subComponent['role'] === 'author') { | |
| $author_index = $index; | |
| break; | |
| } | |
| } | |
| if ($author_index !== null) { | |
| $category_component = [ | |
| 'role' => 'body', | |
| 'text' => "<a href='https://puck.news/category/$category_slug/?utm_source=apple-news&utm_medium=link&utm_content=category&utm_campaign=$slug'>$category_name</a>", | |
| 'format' => 'html', | |
| 'textStyle' => [ | |
| 'textAlignment' => 'center', | |
| 'fontName' => 'PuckSerifDisplay-Bold', | |
| 'fontSize' => 20, | |
| 'lineHeight' => 24, | |
| 'textColor' => '#d40000', | |
| ], | |
| 'layout' => [ | |
| 'margin' => ['bottom' => 12], | |
| ], | |
| ]; | |
| array_splice($component['components'], $author_index, 0, [$category_component]); | |
| } | |
| break; | |
| } | |
| } | |
| // Add dividers before and after authors | |
| foreach ($article['components'] as &$component) { | |
| if ($component['role'] === 'container' && isset($component['components'])) { | |
| $author_index = null; | |
| foreach ($component['components'] as $index => $subComponent) { | |
| if ($subComponent['role'] === 'author') { | |
| $author_index = $index; | |
| break; | |
| } | |
| } | |
| if ($author_index !== null) { | |
| // Add divider before author | |
| $divider_before = [ | |
| 'role' => 'divider', | |
| 'stroke' => [ | |
| 'color' => '#D9D9D9', | |
| 'width' => 1, | |
| ], | |
| ]; | |
| // Add divider after author | |
| $divider_after = [ | |
| 'role' => 'divider', | |
| 'stroke' => [ | |
| 'color' => '#D9D9D9', | |
| 'width' => 1, | |
| ], | |
| 'layout' => [ | |
| 'margin' => [ | |
| 'bottom' => 12, | |
| ], | |
| ], | |
| ]; | |
| array_splice($component['components'], $author_index, 0, [$divider_before]); | |
| array_splice($component['components'], $author_index + 2, 0, [$divider_after]); | |
| } | |
| break; | |
| } | |
| } | |
| // Inject trial image after the second paragraph | |
| foreach ($article['components'] as &$component) { | |
| if ($component['role'] === 'container' && isset($component['components'])) { | |
| $body_count = 0; | |
| $insert_index = null; | |
| foreach ($component['components'] as $index => $subComponent) { | |
| if ($subComponent['role'] === 'body') { | |
| $body_count++; | |
| if ($body_count === 3) { | |
| $insert_index = $index + 1; | |
| break; | |
| } | |
| } | |
| } | |
| if ($insert_index === null) { | |
| continue; | |
| } | |
| // Divider before | |
| $divider_before = [ | |
| 'role' => 'divider', | |
| 'stroke' => [ | |
| 'color' => '#D9D9D9', | |
| 'width' => 1, | |
| ], | |
| ]; | |
| // Divider after | |
| $divider_after = [ | |
| 'role' => 'divider', | |
| 'stroke' => [ | |
| 'color' => '#D9D9D9', | |
| 'width' => 1, | |
| ], | |
| 'layout' => [ | |
| 'margin' => [ | |
| 'bottom' => 24, | |
| ], | |
| ], | |
| ]; | |
| $trial_banner = [ | |
| 'role' => 'container', | |
| 'layout' => [ | |
| 'padding' => [ | |
| 'top' => 16, | |
| 'bottom' => 16, | |
| 'left' => 16, | |
| 'right' => 16, | |
| ], | |
| ], | |
| 'conditional' => [ | |
| [ | |
| 'layout' => [ | |
| 'padding' => [ | |
| 'top' => 16, | |
| 'bottom' => 16, | |
| 'left' => 50, | |
| 'right' => 50, | |
| ], | |
| ], | |
| 'conditions' => [ | |
| 'minViewportWidth' => 415, | |
| ], | |
| ], | |
| ], | |
| 'components' => [ | |
| [ | |
| 'role' => 'container', | |
| 'style' => [ | |
| 'fill' => [ | |
| 'type' => 'image', | |
| 'URL' => 'https://wsrv.nl/?url=https://puck.news/wp-content/themes/puck/resources/assets/images/puck-logo.svg&w=600&output=png', | |
| 'fillMode' => 'fit', | |
| 'verticalAlignment' => 'center', | |
| ], | |
| ], | |
| 'layout' => [ | |
| 'minimumHeight' => 24, | |
| 'margin' => [ | |
| 'top' => 0, | |
| 'bottom' => 18, | |
| ], | |
| ], | |
| 'components' => [ | |
| [ | |
| 'role' => 'body', | |
| 'text' => '', | |
| ], | |
| ], | |
| ], | |
| [ | |
| 'role' => 'heading3', | |
| 'text' => 'The inside story at the intersection of Hollywood, Washington, Wall Street, as well as the business of fashion, media, art, sports, and A.I.', | |
| 'textStyle' => [ | |
| 'textAlignment' => 'center', | |
| 'fontName' => 'PuckSerifDisplay-Regular', | |
| 'fontSize' => 20, | |
| 'lineHeight' => 24, | |
| 'textColor' => '#000000', | |
| ], | |
| 'layout' => [ | |
| 'margin' => [ | |
| 'bottom' => 18, | |
| 'top' => 0, | |
| ], | |
| ], | |
| ], | |
| [ | |
| 'role' => 'body', | |
| 'text' => 'One subscription to Puck gets you access to private emails from every category that matters to you.', | |
| 'textStyle' => [ | |
| 'textAlignment' => 'center', | |
| 'fontName' => 'Inter-Regular', | |
| 'fontSize' => 16, | |
| 'lineHeight' => 18, | |
| 'textColor' => '#00 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment