PluginProbe
Parse.ly / 2.5.1
Parse.ly v2.5.1
3.24.1 3.24.0 3.23.7 3.23.6 3.23.5 3.23.4 3.23.3 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.17.0 3.18.0 3.18.1 3.19.0 3.19.1 3.19.2 3.19.3 3.2.0 3.2.1 3.20.0 3.20.1 3.20.2 3.20.3 All 105 releases
← All changes | src/class-parsely.php +1295 -420 3.2.12.5.1 View file →
@@ -5,18 +5,13 @@
5 5 * @package Parsely
6 6 * @since 2.5.0
7 7 */
8 8
9 -declare(strict_types=1);
10 -
11 -namespace Parsely;
12 -
13 -use WP_Post;
14 -use WP_User;
15 -
16 9 /**
17 10 * Holds most of the logic for the plugin.
18 11 *
12 + * @internal This needs splitting up in the future.
13 + *
19 14 * @since 1.0.0
20 15 * @since 2.5.0 Moved from plugin root file to this file.
21 16 */
22 17 class Parsely {
@@ -21,18 +16,20 @@
21 16 */
22 17 class Parsely {
23 18 /**
24 19 * Declare our constants
20 + *
21 + * @codeCoverageIgnoreStart
25 22 */
26 - public const VERSION = PARSELY_VERSION;
27 - public const MENU_SLUG = 'parsely'; // Defines the page param passed to options-general.php.
28 - public const OPTIONS_KEY = 'parsely'; // Defines the key used to store options in the WP database.
29 - public const CAPABILITY = 'manage_options'; // The capability required for the user to administer settings.
23 + const VERSION = PARSELY_VERSION;
24 + const MENU_SLUG = 'parsely'; // Defines the page param passed to options-general.php.
25 + const OPTIONS_KEY = 'parsely'; // Defines the key used to store options in the WP database.
26 + const CAPABILITY = 'manage_options'; // The capability required for the user to administer settings.
30 27
31 28 /**
32 - * Declare some class properties
29 + * Declare some class propeties
33 30 *
34 - * @var array<string, mixed> $option_defaults The defaults we need for the class.
31 + * @var array $option_defaults The defaults we need for the class.
35 32 */
36 33 private $option_defaults = array(
37 34 'apikey' => '',
38 35 'content_id_prefix' => '',
@@ -88,15 +85,14 @@
88 85 'Movie',
89 86 );
90 87
91 88 /**
92 - * Register action and filter hook callbacks.
89 + * The constructor
93 90 *
94 - * Also, immediately upgrade options if needed.
95 - *
96 - * @return void
91 + * @category Function
92 + * @package Parsely
97 93 */
98 - public function run(): void {
94 + public function __construct() {
99 95 // Run upgrade options if they exist for the version currently defined.
100 96 $options = $this->get_options();
101 97 if ( empty( $options['plugin_version'] ) || self::VERSION !== $options['plugin_version'] ) {
102 98 $method = 'upgrade_plugin_to_version_' . str_replace( '.', '_', self::VERSION );
@@ -107,22 +103,42 @@
107 103 $options['plugin_version'] = self::VERSION;
108 104 update_option( self::OPTIONS_KEY, $options );
109 105 }
110 106
111 - // phpcs:ignore WordPress.WP.CronInterval.CronSchedulesInterval
112 - add_filter( 'cron_schedules', array( $this, 'wpparsely_add_cron_interval' ) );
107 + // admin_menu and a settings link.
108 + add_action( 'admin_head-settings_page_parsely', array( $this, 'add_admin_header' ) );
109 + add_action( 'admin_menu', array( $this, 'add_settings_sub_menu' ) );
110 + add_action( 'admin_init', array( $this, 'initialize_settings' ) );
111 + // display warning when plugin hasn't been configured.
112 + add_action( 'admin_footer', array( $this, 'display_admin_warning' ) );
113 +
114 + add_filter(
115 + 'plugin_action_links_' . PARSELY_PLUGIN_BASENAME,
116 + array( $this, 'add_plugin_meta_links' )
117 + );
118 +
119 + add_filter( 'cron_schedules', [ $this, 'wpparsely_add_cron_interval' ] );
113 120 add_action( 'parsely_bulk_metas_update', array( $this, 'bulk_update_posts' ) );
121 + // inserting parsely code.
122 + add_action( 'wp_head', array( $this, 'insert_parsely_page' ) );
123 + add_action( 'init', array( $this, 'register_js' ) );
124 +
125 + // load_js_api should be called prior to load_js_tracker so the relevant scripts are enqueued in order.
126 + add_action( 'wp_footer', array( $this, 'load_js_api' ) );
127 + add_action( 'wp_footer', array( $this, 'load_js_tracker' ) );
128 +
114 129 add_action( 'save_post', array( $this, 'update_metadata_endpoint' ) );
115 - add_action( 'wp_head', array( $this, 'insert_page_header_metadata' ) );
130 + add_action( 'instant_articles_compat_registry_analytics', array( $this, 'insert_parsely_tracking_fbia' ) );
131 + add_action( 'template_redirect', array( $this, 'parsely_add_amp_actions' ) );
132 + add_action( 'wp_enqueue_scripts', [ $this, 'wp_parsely_style_init' ] );
116 133 }
117 134
118 135 /**
119 - * Adds 10 minute cron interval.
136 + * Adds 10 minute cron interval
120 137 *
121 138 * @param array $schedules WP schedules array.
122 - * @return array
123 139 */
124 - public function wpparsely_add_cron_interval( array $schedules ): array {
140 + public function wpparsely_add_cron_interval( $schedules ) {
125 141 $schedules['everytenminutes'] = array(
126 142 'interval' => 600, // time in seconds.
127 143 'display' => __( 'Every 10 Minutes', 'wp-parsely' ),
128 144 );
@@ -129,161 +145,690 @@
129 145 return $schedules;
130 146 }
131 147
132 148 /**
133 - * Get the full URL of the JavaScript tracker file for the site. If an API key is not set, return an empty string.
149 + * Initialize parsely WordPress style
150 + */
151 + public function wp_parsely_style_init() {
152 + wp_register_style( 'wp-parsely-style', PARSELY_PLUGIN_URL . 'wp-parsely.css', array(), Parsely::VERSION );
153 + }
154 +
155 + /**
156 + * Include the parsely admin header
134 157 *
135 - * @since 3.2.0
158 + * @category Function
159 + * @package Parsely
160 + */
161 + public function add_admin_header() {
162 + echo '
163 +<style>
164 +#wp-parsely_version { color: #777; font-size: 12px; margin-left: 1em; }
165 +.help-text { width: 75%; }
166 +</style>
167 +';
168 +
169 + $admin_script_asset = require PARSELY_PLUGIN_DIR . 'build/admin-page.asset.php';
170 + wp_enqueue_script(
171 + 'wp-parsely-admin',
172 + PARSELY_PLUGIN_URL . 'build/admin-page.js',
173 + $admin_script_asset[ 'dependencies' ],
174 + self::get_asset_cache_buster(),
175 + true
176 + );
177 + }
178 +
179 + /**
180 + * Parsely settings page in WordPress settings menu.
136 181 *
137 - * @return string
182 + * @category Function
183 + * @package Parsely
138 184 */
139 - public function get_tracker_url(): string {
140 - if ( $this->api_key_is_set() ) {
141 - $tracker_url = 'https://cdn.parsely.com/keys/' . $this->get_api_key() . '/p.js';
142 - return esc_url( $tracker_url );
185 + public function add_settings_sub_menu() {
186 + add_options_page(
187 + __( 'Parse.ly Settings', 'wp-parsely' ),
188 + __( 'Parse.ly', 'wp-parsely' ),
189 + self::CAPABILITY,
190 + self::MENU_SLUG,
191 + array( $this, 'display_settings' )
192 + );
193 + }
194 +
195 + /**
196 + * Parse.ly settings screen ( options-general.php?page=[MENU_SLUG] )
197 + *
198 + * @category Function
199 + * @package Parsely
200 + */
201 + public function display_settings() {
202 + if ( ! current_user_can( self::CAPABILITY ) ) {
203 + wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'wp-parsely' ) );
143 204 }
144 - return '';
205 +
206 + include PARSELY_PLUGIN_DIR . 'src/parsely-settings.php';
145 207 }
146 208
147 209 /**
148 - * Insert the code for the <meta name='parsely-page'> parameter within the <head></head> tag.
210 + * Initialize the settings for Parsely
149 211 *
150 - * @since 3.2.0
212 + * @category Function
213 + * @package Parsely
214 + */
215 + public function initialize_settings() {
216 + // All our options are actually stored in one single array to reduce
217 + // DB queries.
218 + register_setting(
219 + self::OPTIONS_KEY,
220 + self::OPTIONS_KEY,
221 + array( $this, 'validate_options' )
222 + );
223 +
224 + // These are the Required Settings.
225 + add_settings_section(
226 + 'required_settings',
227 + __( 'Required Settings', 'wp-parsely' ),
228 + array( $this, 'print_required_settings' ),
229 + self::MENU_SLUG
230 + );
231 +
232 + // Get the API Key.
233 + $h = __( 'Your Site ID is your own site domain ( e.g. `mydomain.com` )', 'wp-parsely' );
234 +
235 + $field_args = array(
236 + 'option_key' => 'apikey',
237 + 'help_text' => $h,
238 + );
239 + add_settings_field(
240 + 'apikey',
241 + __( 'Parse.ly Site ID', 'wp-parsely' ),
242 + array( $this, 'print_text_tag' ),
243 + self::MENU_SLUG,
244 + 'required_settings',
245 + $field_args
246 + );
247 +
248 + // These are the Optional Settings.
249 + add_settings_section(
250 + 'optional_settings',
251 + __( 'Optional Settings', 'wp-parsely' ),
252 + array( $this, 'print_optional_settings' ),
253 + self::MENU_SLUG
254 + );
255 +
256 + /* translators: 1: Opening anchor tag markup, 2: Documentation URL, 3: Opening anchor tag markup continued, 4: Closing anchor tag */
257 + $h = __( 'Your API secret is your secret code to %1$s%2$s%3$saccess our API.%4$s It can be found at dash.parsely.com/yoursitedomain/settings/api ( replace yoursitedomain with your domain name, e.g. `mydomain.com` ) If you haven\'t purchased access to the API, and would like to do so, email your account manager or support@parsely.com!', 'wp-parsely' );
258 + $h_link = 'https://www.parse.ly/help/api/analytics/';
259 +
260 + $field_args = array(
261 + 'option_key' => 'api_secret',
262 + 'help_text' => $h,
263 + 'help_link' => $h_link,
264 + );
265 + add_settings_field(
266 + 'api_secret',
267 + __( 'Parse.ly API Secret', 'wp-parsely' ),
268 + array( $this, 'print_text_tag' ),
269 + self::MENU_SLUG,
270 + 'optional_settings',
271 + $field_args
272 + );
273 +
274 + $h = __( 'Your metadata secret is given to you by Parse.ly support. DO NOT enter anything here unless given to you by Parse.ly support!', 'wp-parsely' );
275 + $h_link = 'https://www.parse.ly/help/api/analytics/';
276 +
277 + $field_args = array(
278 + 'option_key' => 'metadata_secret',
279 + 'help_text' => $h,
280 + 'help_link' => $h_link,
281 + );
282 + add_settings_field(
283 + 'metadata_secret',
284 + __( 'Parse.ly Metadata Secret', 'wp-parsely' ),
285 + array( $this, 'print_text_tag' ),
286 + self::MENU_SLUG,
287 + 'optional_settings',
288 + $field_args
289 + );
290 +
291 + // Clear metadata.
292 + $h = __( 'Check this radio button and hit "Save Changes" to clear all metadata information for Parse.ly posts and re-send all metadata to Parse.ly. WARNING: do not do this unless explicitly instructed by Parse.ly Staff!', 'wp-parsely' );
293 + add_settings_field(
294 + 'parsely_wipe_metadata_cache',
295 + __( 'Wipe Parse.ly Metadata Info', 'wp-parsely' ),
296 + array( $this, 'print_checkbox_tag' ),
297 + self::MENU_SLUG,
298 + 'optional_settings',
299 + array(
300 + 'option_key' => 'parsely_wipe_metadata_cache',
301 + 'help_text' => $h,
302 + 'requires_recrawl' => false,
303 + )
304 + );
305 +
306 + /* translators: 1: Opening anchor tag markup, 2: Documentation URL, 3: Opening anchor tag markup continued, 4: Closing anchor tag */
307 + $h = __( 'Choose the metadata format for our crawlers to access. Most publishers are fine with JSON-LD ( %1$s%2$s%3$shttps://www.parse.ly/help/integration/jsonld/%4$s ), but if you prefer to use our proprietary metadata format then you can do so here.', 'wp-parsely' );
308 + $h_link = 'https://www.parse.ly/help/integration/jsonld/';
309 +
310 + add_settings_field(
311 + 'meta_type',
312 + __( 'Metadata Format', 'wp-parsely' ),
313 + array( $this, 'print_select_tag' ),
314 + self::MENU_SLUG,
315 + 'optional_settings',
316 + array(
317 + 'option_key' => 'meta_type',
318 + 'help_text' => $h,
319 + 'help_link' => $h_link,
320 + // filter WordPress taxonomies under the hood that should not appear in dropdown.
321 + 'select_options' => array(
322 + 'json_ld' => 'json_ld',
323 + 'repeated_metas' => 'repeated_metas',
324 + ),
325 + 'requires_recrawl' => true,
326 + 'multiple' => false,
327 + )
328 + );
329 +
330 + $h = __( 'If you want to specify the url for your logo, you can do so here.', 'wp-parsely' );
331 +
332 + $option_defaults['logo'] = $this->get_logo_default();
333 +
334 + $field_args = array(
335 + 'option_key' => 'logo',
336 + 'help_text' => $h,
337 + );
338 +
339 + add_settings_field(
340 + 'logo',
341 + __( 'Logo', 'wp-parsely' ),
342 + array( $this, 'print_text_tag' ),
343 + self::MENU_SLUG,
344 + 'optional_settings',
345 + $field_args
346 + );
347 +
348 + // Content ID Prefix.
349 + $h = __( 'If you use more than one content management system (e.g. WordPress and Drupal), you may end up with duplicate content IDs. Adding a Content ID Prefix will ensure the content IDs from WordPress will not conflict with other content management systems. We recommend using "WP-" for your prefix.', 'wp-parsely' );
350 +
351 + $field_args = array(
352 + 'option_key' => 'content_id_prefix',
353 + 'optional_args' => array(
354 + 'placeholder' => 'WP-',
355 + ),
356 + 'help_text' => $h,
357 + 'requires_recrawl' => true,
358 + );
359 + add_settings_field(
360 + 'content_id_prefix',
361 + __( 'Content ID Prefix', 'wp-parsely' ),
362 + array( $this, 'print_text_tag' ),
363 + self::MENU_SLUG,
364 + 'optional_settings',
365 + $field_args
366 + );
367 +
368 + // Disable JavaScript.
369 + $h = __( 'If you use a separate system for JavaScript tracking ( Tealium / Segment / Google Tag Manager / other tag manager solution ) you may want to use that instead of having the plugin load the tracker. WARNING: disabling this option will also disable the "Personalize Results" section of the recommended widget! We highly recommend leaving this option set to "No"!', 'wp-parsely' );
370 + add_settings_field(
371 + 'disable_javascript',
372 + __( 'Disable JavaScript', 'wp-parsely' ),
373 + array( $this, 'print_binary_radio_tag' ),
374 + self::MENU_SLUG,
375 + 'optional_settings',
376 + array(
377 + 'title' => __( 'Disable JavaScript', 'wp-parsely' ), // Passed for legend element.
378 + 'option_key' => 'disable_javascript',
379 + 'help_text' => $h,
380 + 'requires_recrawl' => false,
381 + )
382 + );
383 +
384 + // Disable amp tracking.
385 + $h = __( 'If you use a separate system for JavaScript tracking on AMP pages ( Tealium / Segment / Google Tag Manager / other tag manager solution ) you may want to use that instead of having the plugin load the tracker.', 'wp-parsely' );
386 + add_settings_field(
387 + 'disable_amp',
388 + __( 'Disable AMP Tracking', 'wp-parsely' ),
389 + array( $this, 'print_binary_radio_tag' ),
390 + self::MENU_SLUG,
391 + 'optional_settings',
392 + array(
393 + 'title' => __( 'Disable AMP Tracking', 'wp-parsely' ), // Passed for legend element.
394 + 'option_key' => 'disable_amp',
395 + 'help_text' => $h,
396 + 'requires_recrawl' => false,
397 + )
398 + );
399 +
400 + // Use top-level categories.
401 + $h = __( 'The plugin will use the first category assigned to a post. With this option selected, if you post a story to News > National > Florida, the plugin will use the "News" for the section name in your dashboard instead of "Florida".', 'wp-parsely' );
402 + add_settings_field(
403 + 'use_top_level_cats',
404 + __( 'Use Top-Level Categories for Section', 'wp-parsely' ),
405 + array( $this, 'print_binary_radio_tag' ),
406 + self::MENU_SLUG,
407 + 'optional_settings',
408 + array(
409 + 'title' => __( 'Use Top-Level Categories for Section', 'wp-parsely' ), // Passed for legend element.
410 + 'option_key' => 'use_top_level_cats',
411 + 'help_text' => $h,
412 + 'requires_recrawl' => true,
413 + )
414 + );
415 +
416 + // Allow use of custom taxonomy to populate articleSection in parselyPage; defaults to category.
417 + $h = __( 'By default, the section value in your Parse.ly dashboard maps to a post\'s category. You can optionally choose a custom taxonomy, if you\'ve created one, to populate the section value instead.', 'wp-parsely' );
418 + add_settings_field(
419 + 'custom_taxonomy_section',
420 + __( 'Use Custom Taxonomy for Section', 'wp-parsely' ),
421 + array( $this, 'print_select_tag' ),
422 + self::MENU_SLUG,
423 + 'optional_settings',
424 + array(
425 + 'option_key' => 'custom_taxonomy_section',
426 + 'help_text' => $h,
427 + // filter WordPress taxonomies under the hood that should not appear in dropdown.
428 + 'select_options' => array_diff( get_taxonomies(), array( 'post_tag', 'nav_menu', 'author', 'link_category', 'post_format' ) ),
429 + 'requires_recrawl' => true,
430 + )
431 + );
432 +
433 + // Use categories and custom taxonomies as tags.
434 + $h = __( 'You can use this option to add all assigned categories and taxonomies to your tags. For example, if you had a post assigned to the categories: "Business/Tech", "Business/Social", your tags would include "Business/Tech" and "Business/Social" in addition to your other tags.', 'wp-parsely' );
435 + add_settings_field(
436 + 'cats_as_tags',
437 + __( 'Add Categories to Tags', 'wp-parsely' ),
438 + array( $this, 'print_binary_radio_tag' ),
439 + self::MENU_SLUG,
440 + 'optional_settings',
441 + array(
442 + 'title' => __( 'Add Categories to Tags', 'wp-parsely' ), // Passed for legend element.
443 + 'option_key' => 'cats_as_tags',
444 + 'help_text' => $h,
445 + 'requires_recrawl' => true,
446 + )
447 + );
448 +
449 + // Track logged-in users.
450 + $h = __( 'By default, the plugin will track the activity of users that are logged into this site. You can change this setting to only track the activity of anonymous visitors. Note: You will no longer see the Parse.ly tracking code on your site if you browse while logged in.', 'wp-parsely' );
451 + add_settings_field(
452 + 'track_authenticated_users',
453 + __( 'Track Logged-in Users', 'wp-parsely' ),
454 + array( $this, 'print_binary_radio_tag' ),
455 + self::MENU_SLUG,
456 + 'optional_settings',
457 + array(
458 + 'title' => __( 'Track Logged-in Users', 'wp-parsely' ), // Passed for legend element.
459 + 'option_key' => 'track_authenticated_users',
460 + 'help_text' => $h,
461 + 'requires_recrawl' => false,
462 + )
463 + );
464 +
465 + // Lowercase all tags.
466 + $h = __( 'By default, the plugin will use lowercase versions of your tags to correct for potential misspellings. You can change this setting to ensure that tag names are used verbatim.', 'wp-parsely' );
467 + add_settings_field(
468 + 'lowercase_tags',
469 + __( 'Lowercase All Tags', 'wp-parsely' ),
470 + array( $this, 'print_binary_radio_tag' ),
471 + self::MENU_SLUG,
472 + 'optional_settings',
473 + array(
474 + 'title' => __( 'Lowercase All Tags', 'wp-parsely' ), // Passed for legend element.
475 + 'option_key' => 'lowercase_tags',
476 + 'help_text' => $h,
477 + 'requires_recrawl' => true,
478 + )
479 + );
480 +
481 + $h = __( 'The plugin uses http canonical URLs by default. If this needs to be forced to use https, set this option to true. Note: the default is fine for almost all publishers, it\'s unlikely you\'ll have to change this unless directed to do so by a Parse.ly support rep.', 'wp-parsely' );
482 + add_settings_field(
483 + 'force_https_canonicals',
484 + __( 'Force HTTPS canonicals', 'wp-parsely' ),
485 + array( $this, 'print_binary_radio_tag' ),
486 + self::MENU_SLUG,
487 + 'optional_settings',
488 + array(
489 + 'title' => __( 'Force HTTPS canonicals', 'wp-parsely' ), // Passed for legend element.
490 + 'option_key' => 'force_https_canonicals',
491 + 'help_text' => $h,
492 + 'requires_recrawl' => true,
493 + )
494 + );
495 +
496 + // Allow use of custom taxonomy to populate articleSection in parselyPage; defaults to category.
497 + $h = __( 'By default, Parse.ly only tracks the default post type as a post page. If you want to track custom post types, select them here!', 'wp-parsely' );
498 + add_settings_field(
499 + 'track_post_types',
500 + __( 'Post Types To Track', 'wp-parsely' ),
501 + array( $this, 'print_select_tag' ),
502 + self::MENU_SLUG,
503 + 'optional_settings',
504 + array(
505 + 'option_key' => 'track_post_types',
506 + 'help_text' => $h,
507 + // filter WordPress taxonomies under the hood that should not appear in dropdown.
508 + 'select_options' => get_post_types(),
509 + 'requires_recrawl' => true,
510 + 'multiple' => true,
511 + )
512 + );
513 +
514 + // Allow use of custom taxonomy to populate articleSection in parselyPage; defaults to category.
515 + $h = __( 'By default, Parse.ly only tracks the default page type as a non-post page. If you want to track custom post types as non-post pages, select them here!', 'wp-parsely' );
516 + add_settings_field(
517 + 'track_page_types',
518 + __( 'Page Types To Track', 'wp-parsely' ),
519 + array( $this, 'print_select_tag' ),
520 + self::MENU_SLUG,
521 + 'optional_settings',
522 + array(
523 + 'option_key' => 'track_page_types',
524 + 'help_text' => $h,
525 + // filter WordPress taxonomies under the hood that should not appear in dropdown.
526 + 'select_options' => get_post_types(),
527 + 'requires_recrawl' => true,
528 + 'multiple' => true,
529 + )
530 + );
531 +
532 + // Dynamic tracking note.
533 + add_settings_field(
534 + 'dynamic_tracking_note',
535 + __( 'Note: ', 'wp-parsely' ),
536 + array( $this, 'print_dynamic_tracking_note' ),
537 + self::MENU_SLUG,
538 + 'optional_settings'
539 + );
540 + }
541 +
542 + /**
543 + * Validate options from an array
151 544 *
152 - * @param string $meta_type `json_ld` or `repeated_metas`.
153 - * @return void
545 + * @category Function
546 + * @package Parsely
547 + * @param array $array Array of options to be sanitized.
548 + * @param string $name Unused?.
154 549 */
155 - public function render_metadata( string $meta_type ): void {
156 - /**
157 - * Filter whether the Parse.ly meta tags should be inserted in the page.
158 - *
159 - * By default, the tags are inserted.
160 - *
161 - * @since 3.0.0
162 - *
163 - * @param bool $insert_metadata True to insert the metadata, false otherwise.
164 - */
165 - if ( ! apply_filters( 'wp_parsely_should_insert_metadata', true ) ) {
166 - return;
550 + public function validate_option_array( $array, $name ) {
551 + $new_array = $array;
552 + foreach ( $array as $key => $val ) {
553 + $new_array[ $key ] = sanitize_text_field( $val );
167 554 }
555 + return $new_array;
556 + }
168 557
169 - $parsely_options = $this->get_options();
558 + /**
559 + * Validate the options provided by the user
560 + *
561 + * @category Function
562 + * @package Parsely
563 + * @param array $input Options from the settings page.
564 + * @return array $input list of validated input settings.
565 + */
566 + public function validate_options( $input ) {
567 + if ( empty( $input['apikey'] ) ) {
568 + add_settings_error(
569 + self::OPTIONS_KEY,
570 + 'apikey',
571 + __( 'Please specify the Site ID', 'wp-parsely' )
572 + );
573 + } else {
574 + $input['apikey'] = strtolower( $input['apikey'] );
575 + $input['apikey'] = sanitize_text_field( $input['apikey'] );
576 + if ( strpos( $input['apikey'], '.' ) === false || strpos( $input['apikey'], ' ' ) !== false ) {
577 + add_settings_error(
578 + self::OPTIONS_KEY,
579 + 'apikey',
580 + __( 'Your Parse.ly Site ID looks incorrect, it should look like "example.com".', 'wp-parsely' )
581 + );
582 + }
583 + }
584 + // these can't be null, if somebody accidentally deselected them just reset to default.
585 + if ( ! isset( $input['track_post_types'] ) ) {
586 + $input['track_post_types'] = array( 'post' );
170 587
171 - if (
172 - $this->api_key_is_missing() ||
588 + }
589 + if ( ! isset( $input['track_page_types'] ) ) {
590 + $input['track_page_types'] = array( 'page' );
591 + }
173 592
174 - // Chosen not to track logged-in users.
175 - ( ! $parsely_options['track_authenticated_users'] && $this->parsely_is_user_logged_in() ) ||
593 + if ( empty( $input['logo'] ) ) {
594 + $input['logo'] = $this->get_logo_default();
595 + }
176 596
177 - // 404 pages are not tracked.
178 - is_404() ||
597 + $input['track_post_types'] = $this->validate_option_array( $input['track_post_types'], 'track_post_types' );
598 + $input['track_page_types'] = $this->validate_option_array( $input['track_page_types'], 'track_page_types' );
179 599
180 - // Search pages are not tracked.
181 - is_search()
182 - ) {
183 - return;
600 + $input['api_secret'] = sanitize_text_field( $input['api_secret'] );
601 + // Content ID prefix.
602 + $input['content_id_prefix'] = sanitize_text_field( $input['content_id_prefix'] );
603 + $input['custom_taxonomy_section'] = sanitize_text_field( $input['custom_taxonomy_section'] );
604 +
605 + // Custom taxonomy as section.
606 + // Top-level categories.
607 + if ( 'true' !== $input['use_top_level_cats'] && 'false' !== $input['use_top_level_cats'] ) {
608 + add_settings_error(
609 + self::OPTIONS_KEY,
610 + 'use_top_level_cats',
611 + __( 'Value passed for use_top_level_cats must be either "true" or "false".', 'wp-parsely' )
612 + );
613 + } else {
614 + $input['use_top_level_cats'] = 'true' === $input['use_top_level_cats'];
184 615 }
185 616
186 - global $post;
617 + // Child categories as tags.
618 + if ( 'true' !== $input['cats_as_tags'] && 'false' !== $input['cats_as_tags'] ) {
619 + add_settings_error(
620 + self::OPTIONS_KEY,
621 + 'cats_as_tags',
622 + __( 'Value passed for cats_as_tags must be either "true" or "false".', 'wp-parsely' )
623 + );
624 + } else {
625 + $input['cats_as_tags'] = 'true' === $input['cats_as_tags'];
626 + }
187 627
188 - // We can't construct the metadata without a valid post object.
189 - $parsed_post = get_post( $post );
190 - if ( ! $parsed_post instanceof WP_Post ) {
191 - return;
628 + // Track authenticated users.
629 + if ( 'true' !== $input['track_authenticated_users'] && 'false' !== $input['track_authenticated_users'] ) {
630 + add_settings_error(
631 + self::OPTIONS_KEY,
632 + 'track_authenticated_users',
633 + __( 'Value passed for track_authenticated_users must be either "true" or "false".', 'wp-parsely' )
634 + );
635 + } else {
636 + $input['track_authenticated_users'] = 'true' === $input['track_authenticated_users'];
192 637 }
193 638
194 - // Assign default values for LD+JSON
195 - // TODO: Mapping of an install's post types to Parse.ly post types (namely page/post).
196 - $parsely_page = $this->construct_parsely_metadata( $parsely_options, $parsed_post );
639 + // Lowercase tags.
640 + if ( 'true' !== $input['lowercase_tags'] && 'false' !== $input['lowercase_tags'] ) {
641 + add_settings_error(
642 + self::OPTIONS_KEY,
643 + 'lowercase_tags',
644 + __( 'Value passed for lowercase_tags must be either "true" or "false".', 'wp-parsely' )
645 + );
646 + } else {
647 + $input['lowercase_tags'] = 'true' === $input['lowercase_tags'];
648 + }
197 649
198 - // Something went wrong - abort.
199 - if ( 0 === count( $parsely_page ) || ! isset( $parsely_page['headline'] ) ) {
200 - return;
650 + if ( 'true' !== $input['force_https_canonicals'] && 'false' !== $input['force_https_canonicals'] ) {
651 + add_settings_error(
652 + self::OPTIONS_KEY,
653 + 'force_https_canonicals',
654 + __( 'Value passed for force_https_canonicals must be either "true" or "false".', 'wp-parsely' )
655 + );
656 + } else {
657 + $input['force_https_canonicals'] = 'true' === $input['force_https_canonicals'];
201 658 }
202 659
203 - // Insert JSON-LD or repeated metas.
204 - if ( 'json_ld' === $meta_type ) {
205 - include plugin_dir_path( PARSELY_FILE ) . 'views/json-ld.php';
660 + if ( 'true' !== $input['disable_javascript'] && 'false' !== $input['disable_javascript'] ) {
661 + add_settings_error(
662 + self::OPTIONS_KEY,
663 + 'disable_javascript',
664 + __( 'Value passed for disable_javascript must be either "true" or "false".', 'wp-parsely' )
665 + );
206 666 } else {
207 - // Assume `meta_type` is `repeated_metas`.
208 - $parsely_post_type = $this->convert_jsonld_to_parsely_type( $parsely_page['@type'] );
209 - if ( isset( $parsely_page['keywords'] ) && is_array( $parsely_page['keywords'] ) ) {
210 - $parsely_page['keywords'] = implode( ',', $parsely_page['keywords'] );
211 - }
667 + $input['disable_javascript'] = 'true' === $input['disable_javascript'];
668 + }
212 669
213 - $parsely_metas = array(
214 - 'title' => $parsely_page['headline'] ?? null,
215 - 'link' => $parsely_page['url'] ?? null,
216 - 'type' => $parsely_post_type,
217 - 'image-url' => $parsely_page['thumbnailUrl'] ?? null,
218 - 'pub-date' => $parsely_page['datePublished'] ?? null,
219 - 'section' => $parsely_page['articleSection'] ?? null,
220 - 'tags' => $parsely_page['keywords'] ?? null,
221 - 'author' => isset( $parsely_page['author'] ),
670 + if ( 'true' !== $input['disable_amp'] && 'false' !== $input['disable_amp'] ) {
671 + add_settings_error(
672 + self::OPTIONS_KEY,
673 + 'disable_amp',
674 + __( 'Value passed for disable_amp must be either "true" or "false".', 'wp-parsely' )
222 675 );
223 - $parsely_metas = array_filter( $parsely_metas, array( $this, 'filter_empty_and_not_string_from_array' ) );
676 + } else {
677 + $input['disable_amp'] = 'true' === $input['disable_amp'];
678 + }
224 679
225 - if ( isset( $parsely_page['author'] ) ) {
226 - $parsely_page_authors = wp_list_pluck( $parsely_page['author'], 'name' );
227 - $parsely_page_authors = array_filter( $parsely_page_authors, array( $this, 'filter_empty_and_not_string_from_array' ) );
680 + if ( ! empty( $input['metadata_secret'] ) ) {
681 + if ( strlen( $input['metadata_secret'] ) !== 10 ) {
682 + add_settings_error(
683 + self::OPTIONS_KEY,
684 + 'metadata_secret',
685 + __( 'Metadata secret is incorrect. Please contact Parse.ly support!', 'wp-parsely' )
686 + );
687 + } elseif ( 'true' === $input['parsely_wipe_metadata_cache'] ) {
688 + delete_post_meta_by_key( 'parsely_metadata_last_updated' );
689 +
690 + wp_schedule_event( time() + 100, 'everytenminutes', 'parsely_bulk_metas_update' );
691 + $input['parsely_wipe_metadata_cache'] = false;
228 692 }
229 -
230 - include plugin_dir_path( PARSELY_FILE ) . 'views/repeated-metas.php';
231 693 }
232 694
233 - // Add any custom metadata.
234 - if ( isset( $parsely_page['custom_metadata'] ) ) {
235 - include plugin_dir_path( PARSELY_FILE ) . 'views/custom-metadata.php';
236 - }
695 + return $input;
237 696 }
238 697
239 698 /**
240 - * Insert the code for the <meta name='parsely-page'> parameter within the <head></head> tag.
699 + * Not doing anything here
241 700 *
242 - * @since 3.0.0
701 + * @category Function
702 + * @package Parsely
703 + */
704 + public function print_required_settings() {
705 + // We can optionally print some text here in the future, but we don't
706 + // need to now.
707 + }
708 +
709 + /**
710 + * Not doing anything here
243 711 *
244 - * @return void
712 + * @category Function
713 + * @package Parsely
245 714 */
246 - public function insert_page_header_metadata(): void {
247 - $parsely_options = $this->get_options();
248 - $this->render_metadata( $parsely_options['meta_type'] );
715 + public function print_optional_settings() {
716 + // We can optionally print some text here in the future, but we don't
717 + // need to now.
249 718 }
250 719
251 720 /**
252 - * Deprecated. Echo the metadata into the page, and return the inserted values.
721 + * Adds a 'Settings' link to the Plugins screen in WP admin
253 722 *
254 - * To just echo the metadata, use the `insert_page_header_metadata()` method.
255 - * To get the metadata to be inserted, use the `construct_parsely_metadata()` method.
723 + * @category Function
724 + * @package Parsely
725 + * @param array $links The links to add.
726 + */
727 + public function add_plugin_meta_links( $links ) {
728 + array_unshift( $links, '<a href="' . esc_url( $this->get_settings_url() ) . '">' . __( 'Settings', 'wp-parsely' ) . '</a>' );
729 + return $links;
730 + }
731 +
732 + /**
733 + * Display the admin warning if needed
256 734 *
257 - * @deprecated 3.0.0
258 - * @see construct_parsely_metadata()
259 - *
260 - * @return array<string, mixed>
735 + * @category Function
736 + * @package Parsely
261 737 */
262 - public function insert_parsely_page(): array {
263 - _deprecated_function( __FUNCTION__, '3.0', 'construct_parsely_metadata()' );
264 - $this->insert_page_header_metadata();
738 + public function display_admin_warning() {
739 + $options = $this->get_options();
265 740
266 - global $post;
267 -
268 - $parsed_post = get_post( $post );
269 - if ( ! $parsed_post instanceof WP_Post ) {
270 - return array();
741 + if ( isset( $options['apikey'] ) && ! empty( $options['apikey'] ) ) {
742 + return;
271 743 }
272 744
273 - return $this->construct_parsely_metadata( $this->get_options(), $parsed_post );
745 + $message = sprintf(
746 + /* translators: %s: Plugin settings page URL */
747 + __( '<strong>The Parse.ly plugin is not active.</strong> You need to <a href="%s">provide your Parse.ly Dash Site ID</a> before things get cooking.', 'wp-parsely' ),
748 + esc_url( $this->get_settings_url() )
749 + );
750 + ?>
751 + <div id="message" class="error"><p><?php echo wp_kses_post( $message ); ?></p></div>
752 + <?php
274 753 }
275 754
276 755 /**
277 - * Function to be used in `array_filter` to clean up repeated metas.
756 + * Show our note about dynamic tracking
278 757 *
279 - * @since 2.6.0
758 + * @category Function
759 + * @package Parsely
760 + */
761 + public function print_dynamic_tracking_note() {
762 + printf(
763 + /* translators: 1: Documentation URL 2: Documentation URL */
764 + wp_kses_post( __( 'This plugin does not currently support dynamic tracking ( the tracking of multiple pageviews on a single page). Some common use-cases for dynamic tracking are slideshows or articles loaded via AJAX calls in single-page applications -- situations in which new content is loaded without a full page refresh. Tracking these events requires manually implementing additional JavaScript above <a href="%1$s">the standard Parse.ly include</a> that the plugin injects into your page source. Please consult <a href="%2$s">the Parse.ly documentation on dynamic tracking</a> for instructions on implementing dynamic tracking, or contact Parse.ly support (<a href="%3$s">support@parsely.com</a> ) for additional assistance.', 'wp-parsely' ) ),
765 + esc_url( 'http://www.parsely.com/help/integration/basic/' ),
766 + esc_url( 'https://www.parsely.com/help/integration/dynamic/' ),
767 + esc_url( 'mailto:support@parsely.com' )
768 + );
769 + }
770 +
771 + /**
772 + * End the code coverage ignore
280 773 *
281 - * @param mixed $var Value to filter from the array.
282 - * @return bool True if the variable is not empty, and it's a string.
774 + * @codeCoverageIgnoreEnd
283 775 */
284 - private static function filter_empty_and_not_string_from_array( $var ): bool {
285 - return is_string( $var ) && '' !== $var;
776 +
777 + /**
778 + * Actually inserts the code for the <meta name='parsely-page'> parameter within the <head></head> tag.
779 + */
780 + public function insert_parsely_page() {
781 + $parsely_options = $this->get_options();
782 +
783 + if (
784 + // No API key.
785 + empty( $parsely_options['apikey'] ) ||
786 +
787 + // Chosen not to track logged in users.
788 + ( ! $parsely_options['track_authenticated_users'] && $this->parsely_is_user_logged_in() ) ||
789 +
790 + // 404 pages are not tracked.
791 + is_404() ||
792 +
793 + // Search pages are not tracked.
794 + is_search()
795 + ) {
796 + return '';
797 + }
798 +
799 + global $post;
800 + // Assign default values for LD+JSON
801 + // TODO: Maping of an install's post types to Parse.ly post types (namely page/post).
802 + $parsely_page = $this->construct_parsely_metadata( $parsely_options, $post );
803 +
804 + // Something went wrong - abort.
805 + if ( empty( $parsely_page ) || ! isset( $parsely_page['headline'] ) ) {
806 + return;
807 + }
808 +
809 + echo "\n" . '<!-- BEGIN Parse.ly ' . esc_html( Parsely::VERSION ) . ' -->' . "\n";
810 +
811 + // Insert JSON-LD or repeated metas.
812 + if ( 'json_ld' === $parsely_options['meta_type'] ) {
813 + include PARSELY_PLUGIN_DIR . 'views/json-ld.php';
814 + } else {
815 + $parsely_post_type = $this->convert_jsonld_to_parsely_type( $parsely_page['@type'] );
816 + if ( is_array( $parsely_page['keywords'] ) ) {
817 + $parsely_page['keywords'] = implode( ',', $parsely_page['keywords'] );
818 + }
819 +
820 + include PARSELY_PLUGIN_DIR . 'views/repeated-metas.php';
821 + }
822 +
823 + // Add any custom metadata.
824 + if ( isset( $parsely_page['custom_metadata'] ) ) {
825 + include PARSELY_PLUGIN_DIR . 'views/custom-metadata.php';
826 + }
827 +
828 + echo '<!-- END Parse.ly -->' . "\n\n";
829 +
830 + return $parsely_page;
286 831 }
287 832
288 833 /**
289 834 * Compare the post_status key against an allowed list (by default, only 'publish'ed content includes tracking data).
@@ -292,32 +837,16 @@
292 837 *
293 838 * @param int|WP_Post $post Which post object or ID to check.
294 839 * @return bool Should the post status be tracked for the provided post's post_type. By default, only 'publish' is allowed.
295 840 */
296 - public static function post_has_trackable_status( $post ): bool {
841 + public static function post_has_trackable_status( $post ) {
297 842 static $cache = array();
298 - $post_id = is_int( $post ) ? $post : $post->ID;
843 + $post_id = is_int( $post ) ? $post : $post->ID;
299 844 if ( isset( $cache[ $post_id ] ) ) {
300 845 return $cache[ $post_id ];
301 846 }
302 847
303 848 /**
304 - * Filters whether the post password check should be skipped when getting the post trackable status.
305 - *
306 - * @since 3.0.1
307 - *
308 - * @param bool $skip True if the password check should be skipped.
309 - * @param int|WP_Post $post Which post object or ID is being checked.
310 - *
311 - * @returns bool
312 - */
313 - $skip_password_check = apply_filters( 'wp_parsely_skip_post_password_check', false, $post );
314 - if ( ! $skip_password_check && post_password_required( $post ) ) {
315 - $cache[ $post_id ] = false;
316 - return false;
317 - }
318 -
319 - /**
320 849 * Filters the statuses that are permitted to be tracked.
321 850 *
322 851 * By default, the only status tracked is 'publish'. Use this filter if you have other published content that has a different (custom) status.
323 852 *
@@ -325,9 +854,9 @@
325 854 *
326 855 * @param string[] $trackable_statuses The list of post statuses that are allowed to be tracked.
327 856 * @param int|WP_Post $post Which post object or ID is being checked.
328 857 */
329 - $statuses = apply_filters( 'wp_parsely_trackable_statuses', array( 'publish' ), $post );
858 + $statuses = apply_filters( 'wp_parsely_trackable_statuses', array( 'publish' ), $post );
330 859 $cache[ $post_id ] = in_array( get_post_status( $post ), $statuses, true );
331 860 return $cache[ $post_id ];
332 861 }
333 862
@@ -333,33 +862,27 @@
333 862
334 863 /**
335 864 * Creates parsely metadata object from post metadata.
336 865 *
337 - * @param array<string, mixed> $parsely_options parsely_options array.
338 - * @param WP_Post $post object.
339 - * @return array<string, mixed>
866 + * @param array $parsely_options parsely_options array.
867 + * @param WP_Post $post object.
868 + * @return mixed|void
340 869 */
341 - public function construct_parsely_metadata( array $parsely_options, WP_Post $post ): array {
342 - $parsely_page = array(
870 + public function construct_parsely_metadata( array $parsely_options, $post ) {
871 + $parsely_page = array(
343 872 '@context' => 'http://schema.org',
344 873 '@type' => 'WebPage',
345 874 );
346 - $current_url = $this->get_current_url();
347 - $queried_object_id = get_queried_object_id();
875 + $current_url = $this->get_current_url();
348 876
349 - if ( is_front_page() && ! is_paged() ) {
877 + if ( is_front_page() && ! is_paged() || ( 'page' === get_option( 'show_on_front' ) && ! get_option( 'page_on_front' ) ) ) {
350 878 $parsely_page['headline'] = $this->get_clean_parsely_page_value( get_bloginfo( 'name', 'raw' ) );
351 879 $parsely_page['url'] = home_url();
352 880 } elseif ( is_front_page() && is_paged() ) {
353 881 $parsely_page['headline'] = $this->get_clean_parsely_page_value( get_bloginfo( 'name', 'raw' ) );
354 882 $parsely_page['url'] = $current_url;
355 - } elseif (
356 - is_home() && (
357 - ! ( 'page' === get_option( 'show_on_front' ) && ! get_option( 'page_on_front' ) ) ||
358 - $queried_object_id && (int) get_option( 'page_for_posts' ) === $queried_object_id
359 - )
360 - ) {
361 - $parsely_page['headline'] = get_the_title( get_option( 'page_for_posts', true ) );
883 + } elseif ( is_home() ) {
884 + $parsely_page['headline'] = get_the_title( get_option('page_for_posts', true) );
362 885 $parsely_page['url'] = $current_url;
363 886 } elseif ( is_author() ) {
364 887 // TODO: why can't we have something like a WP_User object for all the other cases? Much nicer to deal with than functions.
365 888 $author = ( get_query_var( 'author_name' ) ) ? get_user_by( 'slug', get_query_var( 'author_name' ) ) : get_userdata( get_query_var( 'author' ) );
@@ -364,10 +887,11 @@
364 887 // TODO: why can't we have something like a WP_User object for all the other cases? Much nicer to deal with than functions.
365 888 $author = ( get_query_var( 'author_name' ) ) ? get_user_by( 'slug', get_query_var( 'author_name' ) ) : get_userdata( get_query_var( 'author' ) );
366 889 $parsely_page['headline'] = $this->get_clean_parsely_page_value( 'Author - ' . $author->data->display_name );
367 890 $parsely_page['url'] = $current_url;
368 - } elseif ( is_category() || is_post_type_archive() || is_tax() ) {
369 - $category = get_queried_object();
891 + } elseif ( is_category() ) {
892 + $category = get_the_category();
893 + $category = $category[0];
370 894 $parsely_page['headline'] = $this->get_clean_parsely_page_value( $category->name );
371 895 $parsely_page['url'] = $current_url;
372 896 } elseif ( is_date() ) {
373 897 if ( is_year() ) {
@@ -394,8 +918,9 @@
394 918 $parsely_page['url'] = $current_url;
395 919 } elseif ( in_array( get_post_type( $post ), $parsely_options['track_post_types'], true ) && self::post_has_trackable_status( $post ) ) {
396 920 $authors = $this->get_author_names( $post );
397 921 $category = $this->get_category_name( $post, $parsely_options );
922 + $post_id = $parsely_options['content_id_prefix'] . get_the_ID();
398 923
399 924 if ( has_post_thumbnail( $post ) ) {
400 925 $image_id = get_post_thumbnail_id( $post );
401 926 $image_url = wp_get_attachment_image_src( $image_id );
@@ -407,9 +932,9 @@
407 932 $tags = $this->get_tags( $post->ID );
408 933 if ( $parsely_options['cats_as_tags'] ) {
409 934 $tags = array_merge( $tags, $this->get_categories( $post->ID ) );
410 935 // add custom taxonomy values.
411 - $tags = array_merge( $tags, $this->get_custom_taxonomy_values( $post ) );
936 + $tags = array_merge( $tags, $this->get_custom_taxonomy_values( $post, $parsely_options ) );
412 937 }
413 938 // the function 'mb_strtolower' is not enabled by default in php, so this check
414 939 // falls back to the native php function 'strtolower' if necessary.
415 940 if ( function_exists( 'mb_strtolower' ) ) {
@@ -437,25 +962,23 @@
437 962 * Filters the JSON-LD @type.
438 963 *
439 964 * @since 2.5.0
440 965 *
441 - * @param array $jsonld_type JSON-LD @type value, default is NewsArticle.
442 - * @param int $id Post ID.
443 - * @param string $post_type The Post type in WordPress.
966 + * @param array $jsonld_type JSON-LD @type value, default is NewsArticle.
967 + * @param integer $id Post ID.
968 + * @param string $post_type Post type in WordPress.
444 969 */
445 - $type = (string) apply_filters( 'wp_parsely_post_type', 'NewsArticle', $post->ID, $post->post_type );
970 + $type = (string) apply_filters( 'wp_parsely_post_type', 'NewsArticle', $post->ID, $post->post_type );
446 971 $supported_types = array_merge( $this->supported_jsonld_post_types, $this->supported_jsonld_non_post_types );
447 972
448 973 // Validate type before passing it further as an invalid type will not be recognized by Parse.ly.
449 - if ( ! in_array( $type, $supported_types, true ) ) {
974 + if ( ! in_array( $type, $supported_types ) ) {
450 975 $error = sprintf(
451 - /* translators: 1: JSON @type like NewsArticle, 2: URL */
452 976 __( '@type %1$s is not supported by Parse.ly. Please use a type mentioned in %2$s', 'wp-parsely' ),
453 977 $type,
454 978 'https://www.parse.ly/help/integration/jsonld#distinguishing-between-posts-and-pages'
455 979 );
456 - // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
457 - trigger_error( esc_html( $error ), E_USER_WARNING );
980 + trigger_error( $error, E_USER_WARNING );
458 981 $type = 'NewsArticle';
459 982 }
460 983
461 984 $parsely_page['@type'] = $type;
@@ -469,19 +992,24 @@
469 992 $parsely_page['image'] = array(
470 993 '@type' => 'ImageObject',
471 994 'url' => $image_url,
472 995 );
473 -
474 - $this->set_metadata_post_times( $parsely_page, $post );
475 -
996 + $parsely_page['dateCreated'] = gmdate( 'Y-m-d\TH:i:s\Z', get_post_time( 'U', true, $post ) );
997 + $parsely_page['datePublished'] = gmdate( 'Y-m-d\TH:i:s\Z', get_post_time( 'U', true, $post ) );
998 + if ( get_the_modified_date( 'U', true ) >= get_post_time( 'U', true, $post ) ) {
999 + $parsely_page['dateModified'] = gmdate( 'Y-m-d\TH:i:s\Z', get_the_modified_date( 'U', true ) );
1000 + } else {
1001 + // Use the post time as the earliest possible modification date.
1002 + $parsely_page['dateModified'] = gmdate( 'Y-m-d\TH:i:s\Z', get_post_time( 'U', true, $post ) );
1003 + }
476 1004 $parsely_page['articleSection'] = $category;
477 1005 $author_objects = array();
478 1006 foreach ( $authors as $author ) {
479 - $author_tag = array(
1007 + $author_tag = array(
480 1008 '@type' => 'Person',
481 1009 'name' => $author,
482 1010 );
483 - $author_objects[] = $author_tag;
1011 + array_push( $author_objects, $author_tag );
484 1012 }
485 1013 $parsely_page['author'] = $author_objects;
486 1014 $parsely_page['creator'] = $authors;
487 1015 $parsely_page['publisher'] = array(
@@ -486,22 +1014,36 @@
486 1014 $parsely_page['creator'] = $authors;
487 1015 $parsely_page['publisher'] = array(
488 1016 '@type' => 'Organization',
489 1017 'name' => get_bloginfo( 'name' ),
490 - 'logo' => $parsely_options['logo'],
1018 + 'logo' => $parsely_options['logo'],
491 1019 );
492 1020 $parsely_page['keywords'] = $tags;
493 1021 } elseif ( in_array( get_post_type(), $parsely_options['track_page_types'], true ) && self::post_has_trackable_status( $post ) ) {
494 1022 $parsely_page['headline'] = $this->get_clean_parsely_page_value( get_the_title( $post ) );
495 1023 $parsely_page['url'] = $this->get_current_url( 'post' );
496 - } elseif ( 'page' === get_option( 'show_on_front' ) && ! get_option( 'page_on_front' ) ) {
497 - $parsely_page['headline'] = $this->get_clean_parsely_page_value( get_bloginfo( 'name', 'raw' ) );
498 - $parsely_page['url'] = home_url();
499 1024 }
500 1025
501 1026 /**
502 1027 * Filters the structured metadata.
503 1028 *
1029 + * @deprecated 2.5.0 Use `wp_parsely_metadata` filter instead.
1030 + * @since 1.10.0
1031 + *
1032 + * @param array $parsely_page Existing structured metadata for a page.
1033 + * @param WP_Post $post Post object.
1034 + * @param array $parsely_options The Parsely options.
1035 + */
1036 + $parsely_page = apply_filters_deprecated(
1037 + 'after_set_parsely_page',
1038 + array( $parsely_page, $post, $parsely_options ),
1039 + '2.5.0',
1040 + 'wp_parsely_metadata'
1041 + );
1042 +
1043 + /**
1044 + * Filters the structured metadata.
1045 + *
504 1046 * @since 2.5.0
505 1047 *
506 1048 * @param array $parsely_page Existing structured metadata for a page.
507 1049 * @param WP_Post $post Post object.
@@ -506,58 +1048,29 @@
506 1048 * @param array $parsely_page Existing structured metadata for a page.
507 1049 * @param WP_Post $post Post object.
508 1050 * @param array $parsely_options The Parsely options.
509 1051 */
510 - $filtered = apply_filters( 'wp_parsely_metadata', $parsely_page, $post, $parsely_options );
511 - if ( is_array( $filtered ) ) {
512 - return $filtered;
513 - }
514 - return array();
1052 + $parsely_page = apply_filters( 'wp_parsely_metadata', $parsely_page, $post, $parsely_options );
1053 +
1054 + return $parsely_page;
515 1055 }
516 1056
517 - /**
518 - * Sets all metadata values related to post time.
519 - *
520 - * @since 3.0.2
521 - *
522 - * @param array $metadata Array containing all metadata. It will be potentially mutated to add keys: dateCreated, dateModified, & datePublished.
523 - * @param WP_Post $post Post object from which to extract time data.
524 - * @return void
525 - */
526 - private function set_metadata_post_times( array &$metadata, WP_Post $post ): void {
527 - $date_format = 'Y-m-d\TH:i:s\Z';
528 - $post_created_gmt = get_post_time( $date_format, true, $post );
529 1057
530 - if ( false === $post_created_gmt ) {
531 - return;
532 - }
533 -
534 - $metadata['dateCreated'] = $post_created_gmt;
535 - $metadata['datePublished'] = $post_created_gmt;
536 - $metadata['dateModified'] = $post_created_gmt;
537 -
538 - $post_modified_gmt = get_post_modified_time( $date_format, true, $post );
539 -
540 - if ( false !== $post_modified_gmt && $post_modified_gmt > $post_created_gmt ) {
541 - $metadata['dateModified'] = $post_modified_gmt;
542 - }
543 - }
544 -
545 1058 /**
546 1059 * Updates the Parsely metadata endpoint with the new metadata of the post.
547 1060 *
548 1061 * @param int $post_id id of the post to update.
549 - * @return void
1062 + * @return string
550 1063 */
551 - public function update_metadata_endpoint( int $post_id ): void {
1064 + public function update_metadata_endpoint( $post_id ) {
552 1065 $parsely_options = $this->get_options();
553 1066
554 - if ( $this->api_key_is_missing() || empty( $parsely_options['metadata_secret'] ) ) {
555 - return;
1067 + if ( empty( $parsely_options['apikey'] ) || empty( $parsely_options['metadata_secret'] ) ) {
1068 + return '';
556 1069 }
557 1070
558 - $post = get_post( $post_id );
559 - $metadata = $this->construct_parsely_metadata( $parsely_options, $post );
1071 + $post = get_post( $post_id );
1072 + $metadata = $this->construct_parsely_metadata( $parsely_options, $post );
560 1073
561 1074 $endpoint_metadata = array(
562 1075 'canonical_url' => $metadata['url'],
563 1076 'page_type' => $this->convert_jsonld_to_parsely_type( $metadata['@type'] ),
@@ -590,21 +1103,18 @@
590 1103 'body' => $body,
591 1104 'data_format' => 'body',
592 1105 )
593 1106 );
1107 + $current_timestamp = time();
1108 + $meta_update = update_post_meta( $post_id, 'parsely_metadata_last_updated', $current_timestamp );
594 1109
595 - if ( ! is_wp_error( $response ) ) {
596 - $current_timestamp = time();
597 - update_post_meta( $post_id, 'parsely_metadata_last_updated', $current_timestamp );
598 - }
599 1110 }
600 1111
1112 +
601 1113 /**
602 1114 * Updates posts with Parsely metadata api in bulk.
603 - *
604 - * @return void
605 1115 */
606 - public function bulk_update_posts(): void {
1116 + public function bulk_update_posts() {
607 1117 global $wpdb;
608 1118 $parsely_options = $this->get_options();
609 1119 $allowed_types = array_merge( $parsely_options['track_post_types'], $parsely_options['track_page_types'] );
610 1120 $allowed_types_string = implode(
@@ -617,10 +1127,9 @@
617 1127 )
618 1128 );
619 1129 $ids = wp_cache_get( 'parsely_post_ids_need_meta_updating' );
620 1130 if ( false === $ids ) {
621 - $ids = array();
622 - // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
1131 + $ids = array();
623 1132 $results = $wpdb->get_results(
624 1133 $wpdb->prepare( "SELECT DISTINCT(id) FROM {$wpdb->posts} WHERE post_type IN (\" . %s . \") AND id NOT IN (SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = 'parsely_metadata_last_updated');", $allowed_types_string ),
625 1134 ARRAY_N
626 1135 );
@@ -639,21 +1148,9 @@
639 1148 $this->update_metadata_endpoint( $post_id );
640 1149 }
641 1150 }
642 1151
643 - /**
644 - * Get the cache buster value for script and styles.
645 - *
646 - * If WP_DEBUG is defined and truthy, and we're not running tests, then use a random number.
647 - * Otherwise, use the plugin version.
648 - *
649 - * @since 2.5.0
650 - * @deprecated 3.2.0
651 - *
652 - * @return string Random number string or plugin version string.
653 - */
654 - public static function get_asset_cache_buster(): string {
655 - _deprecated_function( 'Parsely::get_asset_cache_buster', '3.2.0' );
1152 + public static function get_asset_cache_buster() {
656 1153 static $cache_buster;
657 1154 if ( isset( $cache_buster ) ) {
658 1155 return $cache_buster;
659 1156 }
@@ -666,27 +1163,361 @@
666 1163 * @since 2.5.0
667 1164 *
668 1165 * @param string $cache_buster Plugin version, unless WP_DEBUG is defined and truthy, and tests are not running.
669 1166 */
670 - $cache_buster = apply_filters_deprecated( 'wp_parsely_cache_buster', array( (string) $cache_buster ), '3.2.0' );
1167 + return apply_filters( 'wp_parsely_cache_buster', $cache_buster );
1168 + }
671 1169
672 - return $cache_buster;
1170 + public function register_js() {
1171 + $parsely_options = $this->get_options();
1172 +
1173 + // If we don't have an API key, there's no need to proceed.
1174 + if ( empty( $parsely_options['apikey'] ) ) {
1175 + return '';
1176 + }
1177 +
1178 + wp_register_script(
1179 + 'wp-parsely-tracker',
1180 + 'https://cdn.parsely.com/keys/' . $parsely_options['apikey'] . '/p.js',
1181 + array(),
1182 + self::get_asset_cache_buster(),
1183 + true
1184 + );
1185 +
1186 + $api_script_asset = require PARSELY_PLUGIN_DIR . 'build/init-api.asset.php' ;
1187 + wp_register_script(
1188 + 'wp-parsely-api',
1189 + PARSELY_PLUGIN_URL . 'build/init-api.js',
1190 + $api_script_asset[ 'dependencies' ],
1191 + self::get_asset_cache_buster(),
1192 + true
1193 + );
1194 +
1195 + wp_localize_script(
1196 + 'wp-parsely-api',
1197 + 'wpParsely', // This globally-scoped object holds variables used to interact with the API
1198 + array(
1199 + 'apikey' => $parsely_options['apikey'],
1200 + )
1201 + );
673 1202 }
674 1203
675 1204 /**
1205 + * Enqueues the JavaScript code required to send off beacon requests
1206 + */
1207 + public function load_js_tracker() {
1208 + $parsely_options = $this->get_options();
1209 + // If we don't have an API key, there's no need to proceed.
1210 + if ( empty( $parsely_options['apikey'] ) || $parsely_options['disable_javascript'] ) {
1211 + return;
1212 + }
1213 +
1214 + global $post;
1215 + $display = true;
1216 + if ( in_array( get_post_type(), $parsely_options['track_post_types'], true ) && ! self::post_has_trackable_status( $post ) ) {
1217 + $display = false;
1218 + }
1219 + if ( ! $parsely_options['track_authenticated_users'] && $this->parsely_is_user_logged_in() ) {
1220 + $display = false;
1221 + }
1222 + if ( ! in_array( get_post_type(), $parsely_options['track_post_types'], true ) && ! in_array( get_post_type(), $parsely_options['track_page_types'], true ) ) {
1223 + $display = false;
1224 + }
1225 +
1226 + /**
1227 + * Filters whether to include the Parsely JavaScript file.
1228 + *
1229 + * If true, the JavaScript files are sourced.
1230 + *
1231 + * @since 2.2.0
1232 + * @deprecated 2.5.0 Use `wp_parsely_load_js_tracker` filter instead.
1233 + *
1234 + * @param bool $display True if the JavaScript file should be included. False if not.
1235 + */
1236 + if ( ! apply_filters_deprecated(
1237 + 'parsely_filter_insert_javascript',
1238 + array( $display ),
1239 + '2.5.0',
1240 + 'wp_parsely_load_js_tracker'
1241 + ) ) {
1242 + return;
1243 + }
1244 +
1245 + /**
1246 + * Filters whether to enqueue the Parsely JavaScript tracking script from the CDN.
1247 + *
1248 + * If true, the script is enqueued.
1249 + *
1250 + * @since 2.5.0
1251 + *
1252 + * @param bool $display True if the JavaScript file should be included. False if not.
1253 + */
1254 + if ( ! apply_filters( 'wp_parsely_load_js_tracker', $display ) ) {
1255 + return;
1256 + }
1257 +
1258 + if ( ! has_filter( 'script_loader_tag', array( $this, 'script_loader_tag' ) ) ) {
1259 + add_filter( 'script_loader_tag', array( $this, 'script_loader_tag' ), 10, 3 );
1260 + }
1261 +
1262 + wp_enqueue_script( 'wp-parsely-tracker' );
1263 + }
1264 +
1265 + public function load_js_api() {
1266 + $parsely_options = $this->get_options();
1267 +
1268 + // If we don't have an API secret, there's no need to proceed.
1269 + if ( empty( $parsely_options['api_secret'] ) ) {
1270 + return;
1271 + }
1272 +
1273 + if ( ! has_filter( 'script_loader_tag', array( $this, 'script_loader_tag' ) ) ) {
1274 + add_filter( 'script_loader_tag', array( $this, 'script_loader_tag' ), 10, 3 );
1275 + }
1276 +
1277 + wp_enqueue_script( 'wp-parsely-api' );
1278 + }
1279 +
1280 + public function script_loader_tag( $tag, $handle, $src ) {
1281 + $parsely_options = $this->get_options();
1282 + if ( in_array( $handle, array(
1283 + 'wp-parsely',
1284 + 'wp-parsely-api',
1285 + 'wp-parsely-tracker',
1286 + 'wp-parsely-recommended-widget',
1287 + ) ) ) {
1288 + // Have ClouldFlare Rocket Loader ignore these scripts:
1289 + // https://support.cloudflare.com/hc/en-us/articles/200169436-How-can-I-have-Rocket-Loader-ignore-specific-JavaScripts-
1290 + $tag = preg_replace( '/^<script /', '<script data-cfasync="false" ', $tag );
1291 + }
1292 +
1293 + if ( $handle === 'wp-parsely-tracker' ) {
1294 + $tag = preg_replace( '/ id=(\"|\')wp-parsely-tracker-js\1/', ' id="parsely-cfg"', $tag );
1295 + $tag = preg_replace(
1296 + '/ src=/',
1297 + ' data-parsely-site="' . esc_attr( $parsely_options['apikey'] ) . '" src=',
1298 + $tag
1299 + );
1300 + }
1301 + return $tag;
1302 + }
1303 +
1304 + /**
1305 + * Print out the select tags
1306 + *
1307 + * @param array $args The arguments for the select drop downs.
1308 + */
1309 + public function print_select_tag( $args ) {
1310 + $options = $this->get_options();
1311 + $name = $args['option_key'];
1312 + $select_options = $args['select_options'];
1313 + if ( isset( $args['multiple'] ) ) {
1314 + $multiple = $args['multiple'];
1315 + } else {
1316 + $multiple = false;
1317 + }
1318 + $selected = isset( $options[ $name ] ) ? $options[ $name ] : null;
1319 + $id = esc_attr( $name );
1320 + $name = self::OPTIONS_KEY . "[$id]";
1321 +
1322 + if ( isset( $args['help_text'] ) ) {
1323 + echo '<div class="parsely-form-controls" data-has-help-text="true">';
1324 + }
1325 + if ( isset( $args['requires_recrawl'] ) && true === $args['requires_recrawl'] ) {
1326 + echo '<div class="parsely-form-controls" data-requires-recrawl="true">';
1327 + }
1328 +
1329 + if ( $multiple ) {
1330 + echo sprintf( "<select multiple='multiple' name='%s[]'id='%s'", esc_attr( $name ), esc_attr( $name ) );
1331 + } else {
1332 + echo sprintf( "<select name='%s' id='%s'", esc_attr( $name ), esc_attr( $name ) );
1333 + }
1334 +
1335 + echo '>';
1336 +
1337 + foreach ( $select_options as $key => $val ) {
1338 + echo '<option value="' . esc_attr( $key ) . '" ';
1339 +
1340 + if ( $multiple ) {
1341 + $selected = in_array( $val, $options[ $args['option_key'] ], true );
1342 + echo selected( $selected, true, false ) . '>';
1343 + } else {
1344 + echo selected( $selected, $key, false ) . '>';
1345 + }
1346 + echo esc_html( $val );
1347 + echo '</option>';
1348 + }
1349 + echo '</select>';
1350 +
1351 + if ( isset( $args['help_text'] ) ) {
1352 + if ( isset( $args['help_link'] ) ) {
1353 + echo '<div class="help-text"> <p class="description">' .
1354 + sprintf( esc_html( $args['help_text'] ), '<a href="', esc_url( $args['help_link'] ), '">', '</a>' ) .
1355 + '</p></div>';
1356 + } else {
1357 + echo '<div class="help-text"> <p class="description">' . esc_html( $args['help_text'] ) . '</p></div>';
1358 + }
1359 + }
1360 + echo '</div>';
1361 + }
1362 +
1363 + /**
1364 + * Print out the radio buttons
1365 + *
1366 + * @param array $args The arguments for the radio buttons.
1367 + */
1368 + public function print_binary_radio_tag( $args ) {
1369 + $options = $this->get_options();
1370 + $name = $args['option_key'];
1371 + $value = $options[ $name ];
1372 + $id = esc_attr( $name );
1373 + $name = self::OPTIONS_KEY . "[$id]";
1374 +
1375 + $has_help_text = isset( $args['help_text'] ) ? ' data-has-help-text="true"' : '';
1376 + $requires_recrawl = isset( $args['requires_recrawl'] ) && true === $args['requires_recrawl'] ? ' data-requires-recrawl="true"' : '';
1377 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- static text attribute key-value. ?>
1378 + <fieldset class="parsely-form-controls" <?php echo $has_help_text . $requires_recrawl; ?>>
1379 + <legend class="screen-reader-text"><span><?php echo esc_html( $args['title'] ); ?></span></legend>
1380 + <p>
1381 + <label for="<?php echo esc_attr( "{$id}_true" ); ?>">
1382 + <input type="radio" name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( "{$id}_true" ); ?>" value="true"<?php checked( $value ); ?> />Yes
1383 + </label>
1384 + <br />
1385 + <label for="<?php echo esc_attr( "{$id}_false" ); ?>">
1386 + <input type="radio" name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( "{$id}_false" ); ?>" value="false"<?php checked( $value, false ); ?> />No
1387 + </label>
1388 + </p>
1389 + <?php
1390 + if ( isset( $args['help_text'] ) ) {
1391 + ?><div class="help-text"><p class="description .help-text"><?php echo esc_html( $args['help_text'] ); ?></p></div><?php
1392 + }
1393 + ?>
1394 + </fieldset>
1395 + <?php
1396 + }
1397 +
1398 + /**
1399 + * Prints a checkbox tag in the settings page.
1400 + *
1401 + * @param array $args Arguments to print to checkbox tag.
1402 + */
1403 + public function print_checkbox_tag( $args ) {
1404 + $options = $this->get_options();
1405 + $name = $args['option_key'];
1406 + $value = $options[ $name ];
1407 + $id = esc_attr( $name );
1408 + $name = self::OPTIONS_KEY . "[$id]";
1409 +
1410 + if ( isset( $args['help_text'] ) ) {
1411 + echo '<div class="parsely-form-controls" data-has-help-text="true">';
1412 + }
1413 + if ( isset( $args['requires_recrawl'] ) && true === $args['requires_recrawl'] ) {
1414 + echo '<div class="parsely-form-controls" data-requires-recrawl="true">';
1415 + }
1416 +
1417 + echo sprintf( "<input type='checkbox' name='%s' id='%s_true' value='true' ", esc_attr( $name ), esc_attr( $id ) );
1418 + echo checked( true === $value, true, false );
1419 + echo sprintf( " /> <label for='%s_true'>Yes</label>", esc_attr( $id ) );
1420 +
1421 + if ( isset( $args['help_text'] ) ) {
1422 + echo '<div class="help-text"><p class="description">' . esc_html( $args['help_text'] ) . '</p></div>';
1423 + }
1424 + echo '</div>';
1425 +
1426 + }
1427 +
1428 + /**
1429 + * Print out the radio buttons
1430 + *
1431 + * @param array $args The arguments for text tags.
1432 + */
1433 + public function print_text_tag( $args ) {
1434 + $options = $this->get_options();
1435 + $name = $args['option_key'];
1436 + $value = isset( $options[ $name ] ) ? $options[ $name ] : '';
1437 + $optional_args = isset( $args['optional_args'] ) ? $args['optional_args'] : array();
1438 + $id = esc_attr( $name );
1439 + $name = self::OPTIONS_KEY . "[$id]";
1440 + $value = esc_attr( $value );
1441 + $accepted_args = array( 'placeholder' );
1442 +
1443 + if ( isset( $args['help_text'] ) ) {
1444 + echo '<div class="parsely-form-controls" data-has-help-text="true">';
1445 + }
1446 + if ( isset( $args['requires_recrawl'] ) && true === $args['requires_recrawl'] ) {
1447 + echo '<div class="parsely-form-controls" data-requires-recrawl="true">';
1448 + }
1449 +
1450 + echo sprintf( "<input type='text' name='%s' id='%s' value='%s'", esc_attr( $name ), esc_attr( $id ), esc_attr( $value ) );
1451 + foreach ( $optional_args as $key => $val ) {
1452 + if ( in_array( $key, $accepted_args, true ) ) {
1453 + echo ' ' . esc_attr( $key ) . '="' . esc_attr( $val ) . '"';
1454 + }
1455 + }
1456 + echo ' />';
1457 +
1458 + if ( isset( $args['help_text'] ) ) {
1459 + if ( isset( $args['help_link'] ) ) {
1460 + echo ' <div class="help-text" id="' .
1461 + esc_attr( $args['option_key'] ) .
1462 + '_help_text"><p class="description">' .
1463 + sprintf( esc_html( $args['help_text'] ), '<a href="', esc_url( $args['help_link'] ), '">', '</a>' ) .
1464 + '</p>' .
1465 + '</div>';
1466 + } else {
1467 + echo ' <div class="help-text" id="' .
1468 + esc_attr( $args['option_key'] ) .
1469 + '_help_text"><p class="description">' .
1470 + esc_html( $args['help_text'] ) . '</p>' .
1471 + '</div>';
1472 + }
1473 + }
1474 + }
1475 +
1476 + /**
1477 + * Returns default logo if one can be found
1478 + */
1479 + private function get_logo_default() {
1480 + $custom_logo_id = get_theme_mod( 'custom_logo' );
1481 + if ( $custom_logo_id ) {
1482 + $logo_attrs = wp_get_attachment_image_src( $custom_logo_id, 'full' );
1483 + if ( $logo_attrs ) {
1484 + return $logo_attrs[0];
1485 + }
1486 + }
1487 +
1488 + // get_site_icon_url returns an empty string if one isn't found,
1489 + // which is what we want to use as the default anyway.
1490 + return get_site_icon_url();
1491 + }
1492 +
1493 + /**
1494 + * Extracts a host ( not TLD ) from a URL
1495 + *
1496 + * @param string $url The url of the host.
1497 + * @return string $url The host of the url…
1498 + */
1499 + private function get_host_from_url( $url ) {
1500 + if ( preg_match( '/^https?:\/\/( [^\/]+ )\/.*$/', $url, $matches ) ) {
1501 + return $matches[1];
1502 + }
1503 +
1504 + return $url;
1505 + }
1506 +
1507 + /**
676 1508 * Returns the tags associated with this page or post
677 1509 *
678 - * @param int $post_id The id of the post you're trying to get tags for.
679 - * @return array The tags of the post represented by the post id.
1510 + * @param string $post_id The id of the post you're trying to get tags for.
1511 + * @return array $tags The tags of the post represented by the post id.
680 1512 */
681 - private function get_tags( int $post_id ): array {
682 - $tags = array();
683 - $post_tags = wp_get_post_tags( $post_id );
684 - if ( ! is_wp_error( $post_tags ) ) {
685 - foreach ( $post_tags as $wp_tag ) {
686 - $tags[] = $wp_tag->name;
687 - }
1513 + private function get_tags( $post_id ) {
1514 + $tags = array();
1515 + $wp_tags = wp_get_post_tags( $post_id );
1516 + foreach ( $wp_tags as $wp_tag ) {
1517 + array_push( $tags, $wp_tag->name );
688 1518 }
1519 +
689 1520 return $tags;
690 1521 }
691 1522
692 1523 /**
@@ -691,47 +1522,41 @@
691 1522
692 1523 /**
693 1524 * Returns an array of all the child categories for the current post
694 1525 *
695 - * @param int $post_id The id of the post you're trying to get categories for.
1526 + * @param string $post_id The id of the post you're trying to get categories for.
696 1527 * @param string $delimiter What character will delimit the categories.
697 - * @return array<string> All the child categories of the current post.
1528 + * @return array $tags all the child categories of the current post.
698 1529 */
699 - private function get_categories( int $post_id, string $delimiter = '/' ): array {
700 - $tags = array();
701 - foreach ( get_the_category( $post_id ) as $category ) {
702 - $hierarchy = get_category_parents( $category->term_id, false, $delimiter );
703 - if ( ! is_wp_error( $hierarchy ) ) {
704 - $tags[] = rtrim( $hierarchy, '/' );
705 - }
1530 + private function get_categories( $post_id, $delimiter = '/' ) {
1531 + $tags = array();
1532 + $categories = get_the_category( $post_id );
1533 + foreach ( $categories as $category ) {
1534 + $hierarchy = get_category_parents( $category, false, $delimiter );
1535 + $hierarchy = rtrim( $hierarchy, '/' );
1536 + array_push( $tags, $hierarchy );
706 1537 }
707 1538 // take last element in the hierarchy, a string representing the full parent->child tree,
708 1539 // and split it into individual category names.
709 - $last_tag = end( $tags );
710 - if ( false !== $last_tag ) {
711 - $tags = explode( '/', $last_tag );
712 - }
713 -
714 - // Remove default category name from tags if needed.
715 - $default_category_name = get_cat_name( get_option( 'default_category' ) );
716 - return array_diff( $tags, array( $default_category_name ) );
1540 + $tags = explode( '/', end( $tags ) );
1541 + // remove uncategorized value from tags.
1542 + $tags = array_diff( $tags, array( 'Uncategorized' ) );
1543 + return $tags;
717 1544 }
718 1545
719 1546 /**
720 1547 * Safely returns options for the plugin by assigning defaults contained in optionDefaults. As soon as actual
721 - * options are saved, they override the defaults. This prevents us from having to do a lot of isset() checking
1548 + * options are saved, they override the defaults. This prevents us from having to do a lot of isset() checking
722 1549 * on variables.
723 - *
724 - * @return array
725 1550 */
726 - public function get_options(): array {
727 - $options = get_option( self::OPTIONS_KEY, $this->option_defaults );
728 -
729 - if ( ! is_array( $options ) ) {
730 - return $this->option_defaults;
1551 + private function get_options() {
1552 + $options = get_option( self::OPTIONS_KEY );
1553 + if ( false === $options ) {
1554 + $options = $this->option_defaults;
1555 + } else {
1556 + $options = array_merge( $this->option_defaults, $options );
731 1557 }
732 -
733 - return array_merge( $this->option_defaults, $options );
1558 + return $options;
734 1559 }
735 1560
736 1561 /**
737 1562 * Returns a properly cleaned category/taxonomy value and will optionally use the top-level category/taxonomy value
@@ -738,17 +1563,17 @@
738 1563 * if so instructed via the `use_top_level_cats` option.
739 1564 *
740 1565 * @param WP_Post $post_obj The object for the post.
741 1566 * @param array $parsely_options The parsely options.
742 - * @return string Cleaned category name for the post in question.
1567 + * @return string $category Cleaned category name for for post in question.
743 1568 */
744 - private function get_category_name( WP_Post $post_obj, array $parsely_options ): string {
1569 + private function get_category_name( $post_obj, $parsely_options ) {
745 1570 $taxonomy_dropdown_choice = get_the_terms( $post_obj->ID, $parsely_options['custom_taxonomy_section'] );
746 1571 // Get top-level taxonomy name for chosen taxonomy and assign to $parent_name; it will be used
747 1572 // as the category value if 'use_top_level_cats' option is checked.
748 - // Assign as the default category name if no value is checked for the chosen taxonomy.
749 - $category_name = get_cat_name( get_option( 'default_category' ) );
750 - if ( ! empty( $taxonomy_dropdown_choice ) && ! is_wp_error( $taxonomy_dropdown_choice ) ) {
1573 + // Assign as "Uncategorized" if no value is checked for the chosen taxonomy.
1574 + $category = 'Uncategorized';
1575 + if ( ! empty( $taxonomy_dropdown_choice ) ) {
751 1576 if ( $parsely_options['use_top_level_cats'] ) {
752 1577 $first_term = array_shift( $taxonomy_dropdown_choice );
753 1578 $term_name = $this->get_top_level_term( $first_term->term_id, $first_term->taxonomy );
754 1579 } else {
@@ -754,10 +1579,10 @@
754 1579 } else {
755 1580 $term_name = $this->get_bottom_level_term( $post_obj->ID, $parsely_options['custom_taxonomy_section'] );
756 1581 }
757 1582
758 - if ( is_string( $term_name ) && 0 < strlen( $term_name ) ) {
759 - $category_name = $term_name;
1583 + if ( $term_name ) {
1584 + $category = $term_name;
760 1585 }
761 1586 }
762 1587
763 1588 /**
@@ -768,11 +1593,11 @@
768 1593 * @param string $category Category name.
769 1594 * @param WP_Post $post_obj Post object.
770 1595 * @param array $parsely_options The Parsely options.
771 1596 */
772 - $category_name = apply_filters( 'wp_parsely_post_category', $category_name, $post_obj, $parsely_options );
773 -
774 - return $this->get_clean_parsely_page_value( $category_name );
1597 + $category = apply_filters( 'wp_parsely_post_category', $category, $post_obj, $parsely_options );
1598 + $category = $this->get_clean_parsely_page_value( $category );
1599 + return $category;
775 1600 }
776 1601
777 1602 /**
778 1603 * Return the top-most category/taxonomy value in a hierarcy given a taxonomy value's ID
@@ -777,13 +1602,13 @@
777 1602 /**
778 1603 * Return the top-most category/taxonomy value in a hierarcy given a taxonomy value's ID
779 1604 * ( WordPress calls taxonomy values 'terms' ).
780 1605 *
781 - * @param int $term_id The id of the top level term.
1606 + * @param string $term_id The id of the top level term.
782 1607 * @param string $taxonomy_name The name of the taxonomy.
783 - * @return string|false $parent The top level name of the category / taxonomy.
1608 + * @return string $parent The top level name of the category / taxonomy.
784 1609 */
785 - private function get_top_level_term( int $term_id, string $taxonomy_name ) {
1610 + private function get_top_level_term( $term_id, $taxonomy_name ) {
786 1611 $parent = get_term_by( 'id', $term_id, $taxonomy_name );
787 1612 while ( false !== $parent && 0 !== $parent->parent ) {
788 1613 $parent = get_term_by( 'id', $parent->parent, $taxonomy_name );
789 1614 }
@@ -793,22 +1618,17 @@
793 1618 /**
794 1619 * Return the bottom-most category/taxonomy value in a hierarcy given a post ID
795 1620 * ( WordPress calls taxonomy values 'terms' ).
796 1621 *
797 - * @param int $post_id The post id you're interested in.
1622 + * @param string $post_id The post id you're interested in.
798 1623 * @param string $taxonomy_name The name of the taxonomy.
799 - * @return string Name of the custom taxonomy.
1624 + * @return string name of the custom taxonomy.
800 1625 */
801 - private function get_bottom_level_term( int $post_id, string $taxonomy_name ): string {
802 - $terms = get_the_terms( $post_id, $taxonomy_name );
1626 + private function get_bottom_level_term( $post_id, $taxonomy_name ) {
1627 + $terms = get_the_terms( $post_id, $taxonomy_name );
1628 + $term_ids = is_array( $terms ) ? wp_list_pluck( $terms, 'term_id' ) : null;
1629 + $parents = is_array( $terms ) ? array_filter( wp_list_pluck( $terms, 'parent' ) ) : null;
803 1630
804 - if ( ! is_array( $terms ) ) {
805 - return '';
806 - }
807 -
808 - $term_ids = wp_list_pluck( $terms, 'term_id' );
809 - $parents = array_filter( wp_list_pluck( $terms, 'parent' ) );
810 -
811 1631 // Get array of IDs of terms which are not parents.
812 1632 $term_ids_not_parents = array_diff( $term_ids, $parents );
813 1633 // Get corresponding term objects, which are mapped to array index keys.
814 1634 $terms_not_parents = array_intersect_key( $terms, $term_ids_not_parents );
@@ -814,17 +1634,12 @@
814 1634 $terms_not_parents = array_intersect_key( $terms, $term_ids_not_parents );
815 1635 // remove array index keys.
816 1636 $terms_not_parents_cleaned = array();
817 1637 foreach ( $terms_not_parents as $index => $value ) {
818 - $terms_not_parents_cleaned[] = $value;
1638 + array_push( $terms_not_parents_cleaned, $value );
819 1639 }
820 -
821 - if ( ! empty( $terms_not_parents_cleaned ) ) {
822 - // if you assign multiple child terms in a custom taxonomy, will only return the first.
823 - return $terms_not_parents_cleaned[0]->name ?? '';
824 - }
825 -
826 - return '';
1640 + // if you assign multiple child terms in a custom taxonomy, will only return the first.
1641 + return $terms_not_parents_cleaned[0]->name;
827 1642 }
828 1643
829 1644 /**
830 1645 * Get all term values from custom taxonomies.
@@ -829,40 +1644,41 @@
829 1644 /**
830 1645 * Get all term values from custom taxonomies.
831 1646 *
832 1647 * @param WP_Post $post_obj The post object.
833 - * @return array<string>
1648 + * @param array $parsely_options The pparsely options.
834 1649 */
835 - private function get_custom_taxonomy_values( WP_Post $post_obj ): array {
1650 + private function get_custom_taxonomy_values( $post_obj, $parsely_options ) {
836 1651 // filter out default WordPress taxonomies.
837 1652 $all_taxonomies = array_diff( get_taxonomies(), array( 'post_tag', 'nav_menu', 'author', 'link_category', 'post_format' ) );
838 1653 $all_values = array();
839 1654
840 - foreach ( $all_taxonomies as $taxonomy ) {
841 - $custom_taxonomy_objects = get_the_terms( $post_obj->ID, $taxonomy );
842 - if ( is_array( $custom_taxonomy_objects ) ) {
843 - foreach ( $custom_taxonomy_objects as $custom_taxonomy_object ) {
844 - $all_values[] = $custom_taxonomy_object->name;
1655 + if ( is_array( $all_taxonomies ) ) {
1656 + foreach ( $all_taxonomies as $taxonomy ) {
1657 + $custom_taxonomy_objects = get_the_terms( $post_obj->ID, $taxonomy );
1658 + if ( is_array( $custom_taxonomy_objects ) ) {
1659 + foreach ( $custom_taxonomy_objects as $custom_taxonomy_object ) {
1660 + array_push( $all_values, $custom_taxonomy_object->name );
1661 + }
845 1662 }
846 1663 }
847 1664 }
848 -
849 1665 return $all_values;
850 1666 }
851 1667
852 1668 /**
853 - * Returns a list of coauthors for a post assuming the Co-Authors Plus plugin is
1669 + * Returns a list of coauthors for a post assuming the coauthors plugin is
854 1670 * installed. Borrowed from
855 1671 * https://github.com/Automattic/Co-Authors-Plus/blob/master/template-tags.php#L3-35
856 1672 *
857 - * @param int $post_id The id of the post.
858 - * @return array<WP_User>
1673 + * @param string $post_id The id of the post.
859 1674 */
860 - private function get_coauthor_names( int $post_id ): array {
1675 + private function get_coauthor_names( $post_id ) {
861 1676 $coauthors = array();
862 1677 if ( class_exists( 'coauthors_plus' ) ) {
863 - global $post, $post_ID, $coauthors_plus;
1678 + global $post, $post_ID, $coauthors_plus, $wpdb;
864 1679
1680 + $post_id = (int) $post_id;
865 1681 if ( ! $post_id && $post_ID ) {
866 1682 $post_id = $post_ID;
867 1683 }
868 1684
@@ -874,13 +1690,13 @@
874 1690 $coauthor_terms = get_the_terms( $post_id, $coauthors_plus->coauthor_taxonomy );
875 1691
876 1692 if ( is_array( $coauthor_terms ) && ! empty( $coauthor_terms ) ) {
877 1693 foreach ( $coauthor_terms as $coauthor ) {
878 - $coauthor_slug = preg_replace( '#^cap-#', '', $coauthor->slug );
1694 + $coauthor_slug = preg_replace( '#^cap\-#', '', $coauthor->slug );
879 1695 $post_author = $coauthors_plus->get_coauthor_by( 'user_nicename', $coauthor_slug );
880 1696 // In case the user has been deleted while plugin was deactivated.
881 1697 if ( ! empty( $post_author ) ) {
882 - $coauthors[] = new WP_User( $post_author );
1698 + $coauthors[] = $post_author;
883 1699 }
884 1700 }
885 1701 } elseif ( ! $coauthors_plus->force_guest_authors ) {
886 1702 if ( $post && $post_id === $post->ID ) {
@@ -898,19 +1714,18 @@
898 1714 /**
899 1715 * Determine author name from display name, falling back to firstname
900 1716 * lastname, then nickname and finally the nicename.
901 1717 *
902 - * @param ?WP_User $author The author of the post.
903 - * @return string
1718 + * @param WP_User $author The author of the post.
904 1719 */
905 - private function get_author_name( ?WP_User $author ): string {
906 - // Gracefully handle situation where no author is available.
907 - if ( null === $author ) {
1720 + private function get_author_name( $author ) {
1721 + // gracefully handle situation where no author is available.
1722 + if ( empty( $author ) || ! is_object( $author ) ) {
908 1723 return '';
909 1724 }
910 -
911 - if ( ! empty( $author->display_name ) ) {
912 - return $author->display_name;
1725 + $author_name = $author->display_name;
1726 + if ( ! empty( $author_name ) ) {
1727 + return $author_name;
913 1728 }
914 1729
915 1730 $author_name = $author->user_firstname . ' ' . $author->user_lastname;
916 1731 if ( ' ' !== $author_name ) {
@@ -916,17 +1731,14 @@
916 1731 if ( ' ' !== $author_name ) {
917 1732 return $author_name;
918 1733 }
919 1734
920 - if ( ! empty( $author->nickname ) ) {
921 - return $author->nickname;
1735 + $author_name = $author->nickname;
1736 + if ( ! empty( $author_name ) ) {
1737 + return $author_name;
922 1738 }
923 1739
924 - if ( ! empty( $author->user_nicename ) ) {
925 - return $author->user_nicename;
926 - }
927 -
928 - return '';
1740 + return $author->user_nicename;
929 1741 }
930 1742
931 1743 /**
932 1744 * Retrieve all the authors for a post as an array. Can include multiple
@@ -932,17 +1744,14 @@
932 1744 * Retrieve all the authors for a post as an array. Can include multiple
933 1745 * authors if coauthors plugin is in use.
934 1746 *
935 1747 * @param WP_Post $post The post object.
936 - * @return array<string>
1748 + * @return array
937 1749 */
938 - private function get_author_names( WP_Post $post ): array {
1750 + private function get_author_names( $post ) {
939 1751 $authors = $this->get_coauthor_names( $post->ID );
940 - if ( 0 === count( $authors ) ) {
941 - $post_author = get_user_by( 'id', $post->post_author );
942 - if ( false !== $post_author ) {
943 - $authors = array( $post_author );
944 - }
1752 + if ( empty( $authors ) ) {
1753 + $authors = array( get_user_by( 'id', $post->post_author ) );
945 1754 }
946 1755
947 1756 /**
948 1757 * Filters the list of author WP_User objects for a post.
@@ -948,14 +1757,13 @@
948 1757 * Filters the list of author WP_User objects for a post.
949 1758 *
950 1759 * @since 1.14.0
951 1760 *
952 - * @param WP_User[] $authors One or more authors as WP_User objects.
953 - * @param WP_Post $post Post object.
1761 + * @param array $authors One or more authors as WP_User objects (may also be `false`).
1762 + * @param WP_Post $post Post object.
954 1763 */
955 1764 $authors = apply_filters( 'wp_parsely_pre_authors', $authors, $post );
956 1765
957 - // Getting the author name for each author.
958 1766 $authors = array_map( array( $this, 'get_author_name' ), $authors );
959 1767
960 1768 /**
961 1769 * Filters the list of author names for a post.
@@ -965,55 +1773,50 @@
965 1773 * @param string[] $authors One or more author names.
966 1774 * @param WP_Post $post Post object.
967 1775 */
968 1776 $authors = apply_filters( 'wp_parsely_post_authors', $authors, $post );
969 -
970 - return array_map( array( $this, 'get_clean_parsely_page_value' ), $authors );
1777 + $authors = array_map( array( $this, 'get_clean_parsely_page_value' ), $authors );
1778 + return $authors;
971 1779 }
972 1780
973 1781 /**
974 1782 * Sanitize content
975 1783 *
976 - * @since 2.6.0
977 - *
978 - * @param string|null $val The content you'd like sanitized.
1784 + * @param string $val The content you'd like sanitized.
979 1785 * @return string
980 1786 */
981 - public function get_clean_parsely_page_value( ?string $val ): string {
982 - if ( null === $val ) {
983 - return '';
1787 + private function get_clean_parsely_page_value( $val ) {
1788 + if ( is_string( $val ) ) {
1789 + $val = str_replace( "\n", '', $val );
1790 + $val = str_replace( "\r", '', $val );
1791 + $val = wp_strip_all_tags( $val );
1792 + $val = trim( $val );
1793 + return $val;
984 1794 }
985 1795
986 - $val = str_replace( "\n", '', $val );
987 - $val = str_replace( "\r", '', $val );
988 - $val = wp_strip_all_tags( $val );
989 - return trim( $val );
1796 + return $val;
990 1797 }
991 1798
1799 +
992 1800 /**
993 - * Get the URL of the plugin settings page.
994 - *
995 - * @param int $_blog_id The Blog ID for the multisite subsite to use for context (Default null for current).
996 - *
997 - * @return string
1801 + * Get the URL of the plugin settings page
998 1802 */
999 - public static function get_settings_url( int $_blog_id = null ): string {
1000 - return get_admin_url( $_blog_id, 'options-general.php?page=' . self::MENU_SLUG );
1803 + private function get_settings_url() {
1804 + return admin_url( 'options-general.php?page=' . self::MENU_SLUG );
1001 1805 }
1002 1806
1807 +
1003 1808 /**
1004 1809 * Get the URL of the current PHP script.
1005 1810 * A fall-back implementation to determine permalink
1006 1811 *
1007 - * @since 3.0.0 $parsely_type Default parameter changed to `non-post`.
1008 - *
1009 - * @param string $parsely_type Optional. Parse.ly post type you're interested in, either 'post' or 'non-post'. Default is 'non-post'.
1812 + * @param string $parsely_type Optional. Parse.ly post type you're interested in, either 'post' or 'nonpost'. Default is 'nonpost'.
1010 1813 * @param int $post_id Optional. ID of the post you want to get the URL for. Default is 0, which means the global `$post` is used.
1011 - * @return string
1814 + * @return string|void
1012 1815 */
1013 - public function get_current_url( string $parsely_type = 'non-post', int $post_id = 0 ): string {
1816 + public function get_current_url( $parsely_type = 'nonpost', $post_id = 0 ) {
1014 1817 if ( 'post' === $parsely_type ) {
1015 - $permalink = (string) get_permalink( $post_id );
1818 + $permalink = get_permalink( $post_id );
1016 1819
1017 1820 /**
1018 1821 * Filters the permalink for a post.
1019 1822 *
@@ -1020,9 +1823,9 @@
1020 1823 * @since 1.14.0
1021 1824 * @since 2.5.0 Added $post_id.
1022 1825 *
1023 1826 * @param string $permalink The permalink URL or false if post does not exist.
1024 - * @param string $parsely_type Parse.ly type ("post" or "non-post").
1827 + * @param string $parsely_type Parse.ly type ("post" or "nonpost").
1025 1828 * @param int $post_id ID of the post you want to get the URL for. May be 0, so $permalink will be
1026 1829 * for the global $post.
1027 1830 */
1028 1831 $url = apply_filters( 'wp_parsely_permalink', $permalink, $parsely_type, $post_id );
@@ -1044,11 +1847,11 @@
1044 1847 * Get the first image from a post
1045 1848 * https://css-tricks.com/snippets/wordpress/get-the-first-image-from-a-post/
1046 1849 *
1047 1850 * @param WP_Post $post The post object you're interested in.
1048 - * @return string
1851 + * @return mixed|string
1049 1852 */
1050 - public function get_first_image( WP_Post $post ): string {
1853 + public function get_first_image( $post ) {
1051 1854 ob_start();
1052 1855 ob_end_clean();
1053 1856 if ( preg_match_all( '/<img.+src=[\'"]( [^\'"]+ )[\'"].*>/i', $post->post_content, $matches ) ) {
1054 1857 return $matches[1][0];
@@ -1056,74 +1859,146 @@
1056 1859 return '';
1057 1860 }
1058 1861
1059 1862 /**
1060 - * Check to see if parsely user is logged in.
1863 + * Add parsely tracking to facebook instant articles
1061 1864 *
1062 - * @return bool
1865 + * @param type $registry The registry info for fbia.
1866 + * @return string
1063 1867 */
1064 - public function parsely_is_user_logged_in(): bool {
1065 - // can't use $blog_id here because it futzes with the global $blog_id.
1066 - $current_blog_id = get_current_blog_id();
1067 - $current_user_id = get_current_user_id();
1068 - return is_user_member_of_blog( $current_user_id, $current_blog_id );
1868 + public function insert_parsely_tracking_fbia( &$registry ) {
1869 + $options = $this->get_options();
1870 + $display_name = 'Parsely Analytics'; // Do not translate at this time.
1871 + $identifier = 'parsely-analytics-for-wordpress';
1872 +
1873 + $embed_code = '<script>
1874 + PARSELY = {
1875 + autotrack: false,
1876 + onload: function() {
1877 + PARSELY.beacon.trackPageView({
1878 + urlref: \'http://facebook.com/instantarticles\'
1879 + });
1880 + return true;
1881 + }
1882 + }
1883 + </script>
1884 + <script data-cfasync="false" id="parsely-cfg" data-parsely-site="' . esc_attr( $options['apikey'] ) . '" src="https://cdn.parsely.com/keys/' . esc_attr( $options['apikey'] ) . '/p.js"></script>
1885 + <!-- END Parse.ly Include: Standard -->';
1886 +
1887 + $registry[ $identifier ] = array(
1888 + 'name' => $display_name,
1889 + 'payload' => $embed_code,
1890 + );
1891 +
1892 + return $embed_code;
1069 1893 }
1070 1894
1071 1895 /**
1072 - * Convert JSON-LD type to respective Parse.ly page type.
1896 + * Add amp actions.
1897 + */
1898 + public function parsely_add_amp_actions() {
1899 + if ( ! function_exists( 'is_amp_endpoint' ) || ! is_amp_endpoint() ) {
1900 + return '';
1901 + }
1902 +
1903 + $options = $this->get_options();
1904 +
1905 + if ( $options['disable_amp'] ) {
1906 + return '';
1907 + }
1908 +
1909 + add_filter( 'amp_post_template_analytics', array( $this, 'parsely_add_amp_analytics' ) );
1910 + add_filter( 'amp_analytics_entries', array( $this, 'parsely_add_amp_native_analytics' ) );
1911 + }
1912 +
1913 + /**
1914 + * Add amp analytics.
1073 1915 *
1074 - * If the JSON-LD type is one of the types Parse.ly supports as a "post", then "post" will be returned.
1075 - * Otherwise, for "non-posts" and unknown types, "index" is returned.
1076 - *
1077 - * @since 2.5.0
1078 - * @since 3.2.0 Moved to private method.
1079 - *
1080 - * @see https://www.parse.ly/help/integration/metatags#field-description
1081 - *
1082 - * @param string $type JSON-LD type.
1083 - * @return string "post" or "index".
1916 + * @param type $analytics The analytics object you want to add.
1917 + * @return type
1084 1918 */
1085 - private function convert_jsonld_to_parsely_type( string $type ): string {
1086 - return in_array( $type, $this->supported_jsonld_post_types, true ) ? 'post' : 'index';
1919 + public function parsely_add_amp_analytics( $analytics ) {
1920 + $options = $this->get_options();
1921 +
1922 + if ( empty( $options['apikey'] ) ) {
1923 + return $analytics;
1924 + }
1925 +
1926 + $analytics['parsely'] = array(
1927 + 'type' => 'parsely',
1928 + 'attributes' => array(),
1929 + 'config_data' => array(
1930 + 'vars' => array(
1931 + 'apikey' => $options['apikey'],
1932 + ),
1933 + ),
1934 + );
1935 +
1936 + return $analytics;
1087 1937 }
1088 1938
1089 1939 /**
1090 - * Determine if an API key is saved in the options.
1940 + * Add amp native analytics.
1091 1941 *
1092 - * @since 2.6.0
1093 - *
1094 - * @return bool True is API key is set, false if it is missing.
1942 + * @param type $analytics The analytics object you want to add.
1943 + * @return string|type
1095 1944 */
1096 - public function api_key_is_set(): bool {
1945 + public function parsely_add_amp_native_analytics( $analytics ) {
1097 1946 $options = $this->get_options();
1098 1947
1099 - return (
1100 - isset( $options['apikey'] ) &&
1101 - is_string( $options['apikey'] ) &&
1102 - '' !== $options['apikey']
1948 + if ( ! empty( $options['disable_amp'] ) && true === $options['disable_amp'] ) {
1949 + return '';
1950 + }
1951 +
1952 + if ( empty( $options['apikey'] ) ) {
1953 + return $analytics;
1954 + }
1955 +
1956 + $analytics['parsely'] = array(
1957 + 'type' => 'parsely',
1958 + 'attributes' => array(),
1959 + 'config' => wp_json_encode(
1960 + array(
1961 + 'vars' => array(
1962 + 'apikey' => $options['apikey'],
1963 + ),
1964 + )
1965 + ),
1103 1966 );
1967 +
1968 + return $analytics;
1104 1969 }
1105 1970
1106 1971 /**
1107 - * Determine if an API key is not saved in the options.
1108 - *
1109 - * @since 2.6.0
1110 - *
1111 - * @return bool True if API key is missing, false if it is set.
1972 + * Check to see if parsely user is logged in
1112 1973 */
1113 - public function api_key_is_missing(): bool {
1114 - return ! $this->api_key_is_set();
1974 + public function parsely_is_user_logged_in() {
1975 + // can't use $blog_id here because it futzes with the global $blog_id.
1976 + $current_blog_id = get_current_blog_id();
1977 + $current_user_id = get_current_user_id();
1978 + return is_user_member_of_blog( $current_user_id, $current_blog_id );
1115 1979 }
1116 1980
1117 1981 /**
1118 - * Get the API key if set.
1982 + * Why is this here?
1983 + */
1984 + public function return_personalized_json() {
1985 +
1986 + }
1987 +
1988 + /**
1989 + * Convert JSON-LD type to respective Parse.ly page type.
1119 1990 *
1120 - * @since 2.6.0
1991 + * If the JSON-LD type is one of the types Parse.ly supports as a "post", then "post" will be returned.
1992 + * Otherwise, for "non-posts" and unknown types, "index" is returned.
1121 1993 *
1122 - * @return string API key if set, or empty string if not.
1994 + * @since 2.5.0
1995 + *
1996 + * @see https://www.parse.ly/help/integration/metatags#field-description
1997 + *
1998 + * @param $type string JSON-LD type.
1999 + * @return string "post" or "index".
1123 2000 */
1124 - public function get_api_key(): string {
1125 - $options = $this->get_options();
1126 -
1127 - return $this->api_key_is_set() ? $options['apikey'] : '';
2001 + public function convert_jsonld_to_parsely_type( $type ) {
2002 + return in_array( $type, $this->supported_jsonld_post_types ) ? 'post' : 'index';
1128 2003 }
1129 2004 }