forked from beezwax/WP-Publish-to-Apple-News
-
Notifications
You must be signed in to change notification settings - Fork 70
/
Copy pathclass-automation.php
375 lines (345 loc) · 10.5 KB
/
class-automation.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
<?php
/**
* Publish to Apple News Admin: Automation class
*
* Contains a class which is used to manage Automation settings.
*
* @package Apple_News
* @since 2.4.0
*/
namespace Apple_News\Admin;
use Apple_News;
/**
* This class is in charge of handling the management of Apple News automation.
*
* @since 2.4.0
*/
class Automation {
/**
* The option name for automation.
*/
const OPTION_KEY = 'apple_news_automation';
/**
* The page name for the automation settings screen.
*/
const PAGE_NAME = 'apple-news-automation';
/**
* The schema for automation rules.
*/
const SCHEMA = [
'type' => 'array',
'items' => [
'type' => 'object',
'properties' => [
'field' => [
'default' => '',
'type' => 'string',
],
'taxonomy' => [
'default' => '',
'type' => 'string',
],
'term_id' => [
'default' => 0,
'type' => 'integer',
],
'value' => [
'default' => '',
'type' => 'string',
],
],
],
];
/**
* Keeps track of the original title of posts by ID so we can refer to them when prepending.
*
* @var array
*/
private static array $original_titles = [];
/**
* Initialize functionality of this class by registering hooks.
*/
public static function init(): void {
add_action( 'init', [ __CLASS__, 'action__init' ] );
add_action( 'admin_menu', [ __CLASS__, 'action__admin_menu' ], 100 );
add_filter( 'apple_news_active_theme', [ __CLASS__, 'filter__apple_news_active_theme' ], 0, 2 );
add_filter( 'apple_news_article_metadata', [ __CLASS__, 'filter__apple_news_article_metadata' ], 0, 2 );
add_filter( 'apple_news_exporter_slug', [ __CLASS__, 'filter__apple_news_exporter_slug' ], 0, 2 );
add_filter( 'apple_news_exporter_title', [ __CLASS__, 'filter__apple_news_exporter_title' ], 0, 2 );
add_filter( 'apple_news_generate_json', [ __CLASS__, 'filter__apple_news_generate_json' ], 0, 2 );
add_filter( 'apple_news_metadata', [ __CLASS__, 'filter__apple_news_metadata' ], 0, 2 );
}
/**
* A callback function for the admin_init action hook.
*/
public static function action__init(): void {
register_setting(
self::PAGE_NAME,
self::OPTION_KEY,
[
'default' => [],
'description' => __( 'Automation settings for Publish to Apple News.', 'apple-news' ),
'show_in_rest' => [ 'schema' => self::SCHEMA ],
'type' => 'array',
]
);
}
/**
* A callback function for the admin_menu action hook.
*/
public static function action__admin_menu(): void {
add_submenu_page(
'apple_news_index',
__( 'Apple News Automation', 'apple-news' ),
__( 'Automation', 'apple-news' ),
/** This filter is documented in admin/class-admin-apple-settings.php */
apply_filters( 'apple_news_settings_capability', 'manage_options' ),
self::PAGE_NAME,
[ __CLASS__, 'render_submenu_page' ]
);
}
/**
* A callback function for the apple_news_active_theme filter.
*
* @param string $theme_name The name of the theme to use.
* @param ?int $post_id The ID of the post being exported.
*
* @return string The filtered theme name.
*/
public static function filter__apple_news_active_theme( $theme_name, $post_id ) {
if ( $post_id ) {
$rules = self::get_automation_for_post( $post_id );
foreach ( $rules as $rule ) {
if ( 'theme' === ( $rule['field'] ?? '' ) && ! empty( $rule['value'] ) ) {
$theme_name = $rule['value'];
}
}
}
return $theme_name;
}
/**
* A callback function for the apple_news_article_metadata filter.
*
* @param array $metadata An array of metadata keys and values.
* @param int $post_id The ID of the post being pushed to Apple News.
*
* @return array The modified array of metadata.
*/
public static function filter__apple_news_article_metadata( $metadata, $post_id ) {
// Trim down the list of matched rules to only those affecting article metadata.
$metadata_rules = array_values(
array_filter(
self::get_automation_for_post( $post_id ),
function ( $rule ) {
return 'article_metadata' === self::get_fields()[ $rule['field'] ]['location'] ?? '';
}
)
);
// Loop through each matched rule and apply the value to metadata.
foreach ( $metadata_rules as $rule ) {
if ( false === strpos( $rule['field'], '.' ) ) {
$metadata[ $rule['field'] ] = 'true' === $rule['value'];
}
}
return $metadata;
}
/**
* A callback function for the apple_news_exporter_slug filter.
*
* @param string $slug The slug to use.
* @param int $post_id The post ID associated with the slug.
*
* @return string The filtered slug value.
*/
public static function filter__apple_news_exporter_slug( $slug, $post_id ) {
$rules = self::get_automation_for_post( $post_id );
foreach ( $rules as $rule ) {
if ( 'slug.#text#' === ( $rule['field'] ?? '' ) ) {
$slug = $rule['value'] ?? '';
}
}
return $slug;
}
/**
* A callback function for the apple_news_exporter_title filter.
*
* @param string $title The title to use.
* @param int $post_id The post ID associated with the title.
*
* @return string The filtered title value.
*/
public static function filter__apple_news_exporter_title( $title, $post_id ) {
// Make a backup of the original title so we can refer to it later.
self::$original_titles[ $post_id ] = $title;
// Process rules.
$rules = self::get_automation_for_post( $post_id );
foreach ( $rules as $rule ) {
if ( 'headline.prepend' === ( $rule['field'] ?? '' ) ) {
$title = sprintf( '%s %s', $rule['value'] ?? '', self::$original_titles[ $post_id ] );
}
}
return $title;
}
/**
* Applies automation rules after the JSON has been generated.
*
* @param array $json Generated JSON for the article.
* @param int $post_id The post ID associated with the JSON.
*
* @return array Filtered JSON for the article.
*/
public static function filter__apple_news_generate_json( $json, $post_id ) {
$rules = self::get_automation_for_post( $post_id );
$json['title'] = self::$original_titles[ $post_id ];
foreach ( $rules as $rule ) {
if ( 'title.prepend' === ( $rule['field'] ?? '' ) ) {
$prepend = ! empty( $rule['value'] ) ? $rule['value'] . ' ' : '';
$json['title'] = $prepend . self::$original_titles[ $post_id ];
}
}
return $json;
}
/**
* Adds or sets metadata based on automation rules.
*
* @param array $meta Apple News metadata for a post.
* @param int $post_id The ID of the post.
*
* @return array The modified array of metadata.
*/
public static function filter__apple_news_metadata( $meta, $post_id ) {
// Trim down the list of matched rules to only those affecting metadata.
$metadata_rules = array_values(
array_filter(
self::get_automation_for_post( $post_id ),
function ( $rule ) {
return 'metadata' === self::get_fields()[ $rule['field'] ]['location'] ?? '';
}
)
);
// Loop through each matched rule and apply the value to metadata.
foreach ( $metadata_rules as $rule ) {
$meta[ $rule['field'] ] = $rule['value'];
}
return $meta;
}
/**
* Given a post ID, returns an array of matching automation rules.
*
* @param int $post_id The post ID to query.
*
* @return array An array of matching automation rules.
*/
public static function get_automation_for_post( int $post_id ): array {
return array_values(
array_filter(
self::get_automation_rules(),
function ( $rule ) use ( $post_id ) {
return has_term( $rule['term_id'] ?? '', $rule['taxonomy'] ?? '', $post_id );
}
)
);
}
/**
* Returns an array of automation rules defined in the database.
*
* @return array An array of automation rules.
*/
public static function get_automation_rules(): array {
/**
* Allow the automation rules to be filtered and set via code.
*
* @since 2.4.0
*
* @param array $rules An array of automation rules.
*/
return apply_filters( 'apple_news_automation_rules', get_option( self::OPTION_KEY, [] ) );
}
/**
* Returns an array of valid automation fields with information about data type and
* location within what is sent to Apple News.
*
* @return array An array of fields.
*/
public static function get_fields(): array {
return [
'contentGenerationType' => [
'location' => 'metadata',
'type' => 'string',
'label' => 'contentGenerationType',
],
'headline.prepend' => [
'location' => 'component',
'type' => 'string',
'label' => __( 'Headline: Prepend Text', 'apple-news' ),
],
'isHidden' => [
'location' => 'article_metadata',
'type' => 'string',
'label' => 'isHidden',
],
'isPaid' => [
'location' => 'article_metadata',
'type' => 'string',
'label' => 'isPaid',
],
'isPreview' => [
'location' => 'article_metadata',
'type' => 'string',
'label' => 'isPreview',
],
'isSponsored' => [
'location' => 'article_metadata',
'type' => 'string',
'label' => 'isSponsored',
],
'title.prepend' => [
'location' => 'component',
'type' => 'string',
'label' => __( 'Metadata Title: Prepend Text', 'apple-news' ),
],
'links.sections' => [
'location' => 'article_metadata',
'type' => 'string',
'label' => __( 'Section', 'apple-news' ),
],
'slug.#text#' => [
'location' => 'component',
'type' => 'string',
'label' => __( 'Slug', 'apple-news' ),
],
'theme' => [
'location' => 'exporter',
'type' => 'string',
'label' => __( 'Theme', 'apple-news' ),
],
];
}
/**
* A callback to load automation settings scripts and styles and render target div for the React submenu page.
*/
public static function render_submenu_page(): void {
// Enqueue page specific scripts.
wp_enqueue_script(
'apple-news-admin-settings',
plugins_url( 'build/adminSettings.js', __DIR__ ),
[ 'wp-block-editor', 'wp-api-fetch', 'wp-api', 'wp-i18n', 'wp-components', 'wp-element', 'wp-tinymce' ],
Apple_News::$version,
true
);
wp_enqueue_style( 'wp-edit-blocks' );
wp_localize_script(
'apple-news-admin-settings',
'AppleNewsAutomationConfig',
[
'fields' => self::get_fields(),
'sections' => \Admin_Apple_Sections::get_sections(),
'taxonomies' => get_taxonomies( [ 'public' => 'true' ] ),
'themes' => \Apple_Exporter\Theme::get_registry(),
]
);
add_filter( 'should_load_block_editor_scripts_and_styles', '__return_true' );
// Render target div for React app.
echo '<div id="apple-news-options__page"></div>';
}
}