Skip to content

Instantly share code, notes, and snippets.

@Kevinlearynet
Created October 16, 2025 02:06
Show Gist options
  • Save Kevinlearynet/f23c10939fa29a95dcfa1c71fc4ed5ef to your computer and use it in GitHub Desktop.
Save Kevinlearynet/f23c10939fa29a95dcfa1c71fc4ed5ef to your computer and use it in GitHub Desktop.
<?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