@automattic/newspack-blocks 4.5.1 → 4.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## [4.5.2](https://github.com/Automattic/newspack-blocks/compare/v4.5.1...v4.5.2) (2024-12-16)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * remove CAP compatibility mode ([414691d](https://github.com/Automattic/newspack-blocks/commit/414691d048a59a2c72ddcb1689289f07ab2102d8))
7
+ * removed another unused constant ([298cf88](https://github.com/Automattic/newspack-blocks/commit/298cf884228522a6d93e328d10391f5d7cfbac88))
8
+ * show x.com URLs and icons instead of Twitter in Author blocks ([036517b](https://github.com/Automattic/newspack-blocks/commit/036517b5a80342711f4dd571ae5de02c2d588c69))
9
+
1
10
  ## [4.5.1](https://github.com/Automattic/newspack-blocks/compare/v4.5.0...v4.5.1) (2024-12-09)
2
11
 
3
12
 
@@ -20,32 +20,6 @@ class Newspack_Blocks {
20
20
  'tiers-based' => 'newspack-blocks-donate-tiers-based',
21
21
  ];
22
22
 
23
- /**
24
- * Regex pattern we can use to search for and remove custom SQL statements.
25
- * Custom statements added by this class are wrapped by `newspack-blocks` comments.
26
- */
27
- const SQL_PATTERN = '/\/\* newspack-blocks \*\/(.|\n)*\/\* \/newspack-blocks \*\//';
28
-
29
- /**
30
- * Class property to store user IDs and CAP guest author names for building
31
- * custom SQL statements. In order to allow a single WP_Query to filter by
32
- * both WP users and CAP guest authors (a taxonomy), we need to directly
33
- * modify the JOIN and WHERE clauses in the SQL query.
34
- *
35
- * If this property is false, then the custom statements will be stripped
36
- * from all SQL clauses. If it's an array with `authors` and `coauthors`
37
- * keys, the custom statements will be added to the SQL query.
38
- *
39
- * Example array:
40
- * [
41
- * 'authors' => [], // Array of numeric WP user IDs.
42
- * 'coauthors' => [], // Array of CAP guest author name slugs.
43
- * ]
44
- *
45
- * @var boolean|array
46
- */
47
- protected static $filter_clauses = false;
48
-
49
23
  /**
50
24
  * Add hooks and filters.
51
25
  */
@@ -55,8 +29,6 @@ class Newspack_Blocks {
55
29
  add_post_type_support( 'page', 'newspack_blocks' );
56
30
  add_action( 'jetpack_register_gutenberg_extensions', [ __CLASS__, 'disable_jetpack_donate' ], 99 );
57
31
  add_filter( 'the_content', [ __CLASS__, 'hide_post_content_when_iframe_block_is_fullscreen' ] );
58
- add_filter( 'posts_clauses', [ __CLASS__, 'filter_posts_clauses_when_co_authors' ], 999, 2 );
59
- add_filter( 'posts_groupby', [ __CLASS__, 'group_by_post_id_filter' ], 999 );
60
32
 
61
33
  /**
62
34
  * Disable NextGEN's `C_NextGen_Shortcode_Manager`.
@@ -595,9 +567,6 @@ class Newspack_Blocks {
595
567
  * @return array
596
568
  */
597
569
  public static function build_articles_query( $attributes, $block_name ) {
598
- // Reset author/CAP guest author SQL statements by default.
599
- self::$filter_clauses = false;
600
-
601
570
  global $newspack_blocks_post_id;
602
571
  if ( ! $newspack_blocks_post_id ) {
603
572
  $newspack_blocks_post_id = array();
@@ -633,6 +602,7 @@ class Newspack_Blocks {
633
602
  'ignore_sticky_posts' => true,
634
603
  'has_password' => false,
635
604
  'is_newspack_query' => true,
605
+ 'tax_query' => [], // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
636
606
  );
637
607
  if ( $specific_mode && $specific_posts ) {
638
608
  $args['posts_per_page'] = count( $specific_posts );
@@ -698,80 +668,59 @@ class Newspack_Blocks {
698
668
  }
699
669
  }
700
670
 
701
- $is_co_authors_plus_active = class_exists( 'CoAuthors_Plus' );
702
- $co_authors_guest_authors = class_exists( 'CoAuthors_Guest_Authors' ) ? new CoAuthors_Guest_Authors() : null;
703
-
704
671
  if ( $authors && count( $authors ) ) {
705
- $co_authors_names = [];
706
-
707
- if ( $is_co_authors_plus_active ) {
708
- foreach ( $authors as $index => $author_id ) {
709
- // If the given ID is a guest author.
710
- $co_author = $co_authors_guest_authors ? $co_authors_guest_authors->get_guest_author_by( 'id', $author_id ) : null;
711
- if ( $co_author ) {
712
- if ( ! empty( $co_author->linked_account ) ) {
713
- $linked_account = get_user_by( 'login', $co_author->linked_account );
714
- if ( $linked_account ) {
715
- $authors[] = $linked_account->ID;
672
+ global $coauthors_plus;
673
+ $is_co_authors_plus_active = is_object( $coauthors_plus ) && method_exists( $coauthors_plus, 'get_coauthor_by' );
674
+
675
+ if ( ! $is_co_authors_plus_active ) {
676
+ $args['author__in'] = $authors;
677
+ } else {
678
+ /**
679
+ * When CoAuthors Plus is active, we ignore the 'author__in' parameter and search only by the author taxonomy.
680
+ *
681
+ * If CAP has been activated recently, the author taxonomy may not have been populated yet. You'll need to run
682
+ * wp co-authors-plus create-author-terms-for-posts to make sure all posts have the author terms in place.
683
+ */
684
+ $authors_term_ids = [];
685
+ foreach ( $authors as $author_id ) {
686
+ $co_author = $coauthors_plus->get_coauthor_by( 'id', $author_id );
687
+ if ( is_object( $co_author ) ) {
688
+ $term = $coauthors_plus->get_author_term( $co_author );
689
+ if ( $term ) {
690
+ $authors_term_ids[] = $term->term_id;
691
+ }
692
+
693
+ // If it's a guest author, also check the linked author.
694
+ if ( 'guest-author' === $co_author->type && ! empty( $co_author->wp_user ) && $co_author->wp_user instanceof \WP_User ) {
695
+ $term = $coauthors_plus->get_author_term( $co_author->wp_user );
696
+ if ( $term ) {
697
+ $authors_term_ids[] = $term->term_id;
716
698
  }
717
699
  }
718
- $co_authors_names[] = $co_author->user_nicename;
719
- unset( $authors[ $index ] );
720
- } else {
721
- $authors_controller = new WP_REST_Newspack_Authors_Controller();
722
- $author_data = get_userdata( $author_id );
723
- if ( $author_data ) {
724
- $linked_guest_author = $authors_controller->get_linked_guest_author( $author_data->user_login );
725
- // If the given ID is linked to a guest author.
726
- if ( $linked_guest_author ) {
727
- $guest_author_name = sanitize_title( $linked_guest_author->post_title );
728
- if ( ! in_array( $guest_author_name, $co_authors_names, true ) ) {
729
- $co_authors_names[] = $guest_author_name;
730
- $co_authors_names[] = $linked_guest_author->post_name;
731
- unset( $authors[ $index ] );
700
+
701
+ // If it's a regular wp user, check and include any linked guest authors.
702
+ if ( 'wpuser' === $co_author->type ) {
703
+ $authors_controller = new WP_REST_Newspack_Authors_Controller();
704
+ $linked_guest_author_post = $authors_controller->get_linked_guest_author( $co_author->user_login );
705
+ if ( $linked_guest_author_post ) {
706
+ $linked_guest_author_object = $coauthors_plus->get_coauthor_by( 'id', $author_id );
707
+ if ( is_object( $linked_guest_author_object ) ) {
708
+ $term = $coauthors_plus->get_author_term( $linked_guest_author_object );
709
+ if ( $term ) {
710
+ $authors_term_ids[] = $term->term_id;
711
+ }
732
712
  }
733
- } else {
734
- $co_authors_names[] = $author_data->user_login;
735
- $co_authors_names[] = $author_data->user_nicename;
736
- $co_authors_names[] = 'cap-' . $author_data->user_nicename;
737
- $co_authors_names[] = $author_data->user_email;
738
713
  }
739
714
  }
740
715
  }
741
716
  }
742
- }
743
-
744
- // Reset numeric indexes.
745
- $authors = array_values( $authors );
746
-
747
- if ( empty( $authors ) && count( $co_authors_names ) ) {
748
- // We are only looking for Guest Authors posts. So we need to only search by taxonomy.
749
- $args['tax_query'] = [ // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
750
- 'relation' => 'OR',
751
- [
752
- 'field' => 'slug',
753
- 'taxonomy' => 'author',
754
- 'terms' => $co_authors_names,
755
- ],
756
- [
757
- 'field' => 'name',
717
+ if ( count( $authors_term_ids ) ) {
718
+ $args['tax_query'][] = [
758
719
  'taxonomy' => 'author',
759
- 'terms' => $co_authors_names,
760
- ],
761
- ];
762
- } elseif ( empty( $co_authors_names ) && count( $authors ) ) {
763
- // Simple search by author. Co-Authors plus is not active.
764
- $args['author__in'] = $authors;
765
- } else {
766
- // The query contains both WP users and CAP guest authors. We need to filter the SQL query.
767
- // That's because author__in and tax_query would be combined with AND, not OR.
768
- self::$filter_clauses = [
769
- 'authors' => $authors,
770
- 'coauthors' => $co_authors_names,
771
- ];
772
-
773
- // Also, in these cases, never offload the query to Elastic Search.
774
- $args['newspack_no_es_query'] = true;
720
+ 'field' => 'term_id',
721
+ 'terms' => $authors_term_ids,
722
+ ];
723
+ }
775
724
  }
776
725
  }
777
726
  }
@@ -1236,131 +1185,6 @@ class Newspack_Blocks {
1236
1185
  remove_filter( 'excerpt_more', [ __CLASS__, 'more_excerpt' ], 999 );
1237
1186
  }
1238
1187
 
1239
- /**
1240
- * Filter posts by authors and co-authors. If the query is filtering posts
1241
- * by both WP users and CAP guest authors, the SQL clauses must be modified
1242
- * directly so that the filtering can happen with a single SQL query.
1243
- *
1244
- * @param string[] $clauses Associative array of the clauses for the query.
1245
- * @param WP_Query $query The WP_Query instance (passed by reference).
1246
- */
1247
- public static function filter_posts_clauses_when_co_authors( $clauses, $query ) {
1248
- // Remove any lingering custom SQL statements.
1249
- $clauses['join'] = preg_replace( self::SQL_PATTERN, '', $clauses['join'] );
1250
- $clauses['where'] = preg_replace( self::SQL_PATTERN, '', $clauses['where'] );
1251
- $is_newspack_query = isset( $query->query_vars['is_newspack_query'] ) && $query->query_vars['is_newspack_query'];
1252
-
1253
- // If the query isn't coming from this plugin, or $filter_clauses lacks expected data.
1254
- if (
1255
- ! $is_newspack_query ||
1256
- ! self::$filter_clauses ||
1257
- ! isset( self::$filter_clauses['authors'] ) ||
1258
- ! isset( self::$filter_clauses['coauthors'] )
1259
- ) {
1260
- return $clauses;
1261
- }
1262
-
1263
- global $wpdb;
1264
-
1265
- $authors_ids = self::$filter_clauses['authors'];
1266
- $co_authors_names = self::$filter_clauses['coauthors'];
1267
-
1268
- // co-author tax query.
1269
- $tax_query = [
1270
- 'relation' => 'OR',
1271
- [
1272
- 'taxonomy' => 'author',
1273
- 'field' => 'name',
1274
- 'terms' => $co_authors_names,
1275
- ],
1276
- [
1277
- 'taxonomy' => 'author',
1278
- 'field' => 'slug',
1279
- 'terms' => $co_authors_names,
1280
- ],
1281
- ];
1282
-
1283
- // Generate the tax query SQL.
1284
- $tax_query = new WP_Tax_Query( $tax_query );
1285
- $tax_query = $tax_query->get_sql( $wpdb->posts, 'ID' );
1286
-
1287
- // Generate the author query SQL.
1288
- $csv = implode( ',', wp_parse_id_list( (array) $authors_ids ) );
1289
- $author_names = array_reduce(
1290
- $authors_ids,
1291
- function( $acc, $author_id ) {
1292
- $author_data = get_userdata( $author_id );
1293
- if ( $author_data ) {
1294
- $acc[] = $author_data->user_login;
1295
- }
1296
- return $acc;
1297
- },
1298
- []
1299
- );
1300
-
1301
- // If getting only WP users, we don't want to get posts attributed to CAP guest authors not linked to the given WP users.
1302
- $exclude = new WP_Tax_Query(
1303
- [
1304
- 'relation' => 'OR',
1305
- [
1306
- 'taxonomy' => 'author',
1307
- 'operator' => 'NOT EXISTS',
1308
- ],
1309
- [
1310
- 'field' => 'name',
1311
- 'taxonomy' => 'author',
1312
- 'terms' => $author_names,
1313
- ],
1314
- ]
1315
- );
1316
- $exclude = $exclude->get_sql( $wpdb->posts, 'ID' );
1317
- $exclude = $exclude['where'];
1318
- $authors = " ( {$wpdb->posts}.post_author IN ( $csv ) $exclude ) ";
1319
-
1320
- /**
1321
- * Make sure the authors are set, the tax query is valid (doesn't contain 0 = 1).
1322
- *
1323
- * Since we have two clauses (one searching on name, and one on slug), it's ok to have a "0 = 1" clause for
1324
- * one of them, but not for both.
1325
- *
1326
- * The reason we might have invalid queries is because we do a broad search with many possibles term slugs and names.
1327
- * There is not one consistent way terms are created, so the slug/name can have different values. We try to search for all of them, and
1328
- * if none of the options we are searching for exist as a term, it will create an invalid query.
1329
- */
1330
- if ( substr_count( $tax_query['where'], ' 0 = 1' ) <= 1 ) {
1331
- // Append to the current join parts. The JOIN statment only needs to exist in the clause once.
1332
- if ( false === strpos( $clauses['join'], $tax_query['join'] ) ) {
1333
- $clauses['join'] .= '/* newspack-blocks */ ' . $tax_query['join'] . ' /* /newspack-blocks */';
1334
- }
1335
-
1336
- $clauses['where'] .= sprintf(
1337
- // The tax query SQL comes prepended with AND.
1338
- '%s AND ( %s ( 1=1 %s ) ) %s',
1339
- '/* newspack-blocks */',
1340
- empty( $authors_ids ) ? '' : $authors . ' OR',
1341
- $tax_query['where'],
1342
- '/* /newspack-blocks */'
1343
- );
1344
- }
1345
- return $clauses;
1346
- }
1347
-
1348
- /**
1349
- * Group by post ID filter, used when we join taxonomies while getting posts.
1350
- *
1351
- * @param string $groupby The GROUP BY clause of the query.
1352
- * @return string The filtered GROUP BY clause.
1353
- */
1354
- public static function group_by_post_id_filter( $groupby ) {
1355
- global $wpdb;
1356
-
1357
- if ( self::$filter_clauses ) {
1358
- return "{$wpdb->posts}.ID ";
1359
- }
1360
-
1361
- return $groupby;
1362
- }
1363
-
1364
1188
  /**
1365
1189
  * Utility to get the link for the given post ID. If the post has an external URL meta value, use that.
1366
1190
  * Otherwise, use the permalink. But if the post type doesn't have a public singular view, don't link.
@@ -7,7 +7,7 @@
7
7
  * Author URI: https://newspack.com/
8
8
  * Text Domain: newspack-blocks
9
9
  * Domain Path: /languages
10
- * Version: 4.5.1
10
+ * Version: 4.5.2
11
11
  *
12
12
  * @package Newspack_Blocks
13
13
  */
@@ -15,7 +15,7 @@
15
15
  define( 'NEWSPACK_BLOCKS__PLUGIN_FILE', __FILE__ );
16
16
  define( 'NEWSPACK_BLOCKS__BLOCKS_DIRECTORY', 'dist/' );
17
17
  define( 'NEWSPACK_BLOCKS__PLUGIN_DIR', plugin_dir_path( NEWSPACK_BLOCKS__PLUGIN_FILE ) );
18
- define( 'NEWSPACK_BLOCKS__VERSION', '4.5.1' );
18
+ define( 'NEWSPACK_BLOCKS__VERSION', '4.5.2' );
19
19
 
20
20
  require_once NEWSPACK_BLOCKS__PLUGIN_DIR . 'includes/class-newspack-blocks.php';
21
21
  require_once NEWSPACK_BLOCKS__PLUGIN_DIR . 'includes/class-newspack-blocks-api.php';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automattic/newspack-blocks",
3
- "version": "4.5.1",
3
+ "version": "4.5.2",
4
4
  "author": "Automattic",
5
5
  "devDependencies": {
6
6
  "@rushstack/eslint-patch": "^1.10.4",
@@ -435,7 +435,7 @@ class WP_REST_Newspack_Authors_Controller extends WP_REST_Controller {
435
435
  $handle = $is_website ? get_post_meta( $author_id, 'cap-website', true ) : get_the_author_meta( $profile, $author_id );
436
436
 
437
437
  if ( $handle ) {
438
- $url = 'twitter' === $profile ? esc_url( 'https://twitter.com/' . $handle ) : esc_url( $handle );
438
+ $url = 'twitter' === $profile ? esc_url( 'https://x.com/' . $handle ) : esc_url( $handle );
439
439
  $acc[ $profile ] = [ 'url' => $url ];
440
440
 
441
441
  if ( class_exists( 'Newspack_SVG_Icons' ) ) {
@@ -129,7 +129,7 @@ class WP_REST_Newspack_Articles_Controller extends WP_REST_Controller {
129
129
  * @return WP_REST_Response
130
130
  */
131
131
  public function get_items( $request ) {
132
- $page = $request->get_param( 'page' ) ?? 1;
132
+ $page = (int) $request->get_param( 'page' ) ?? 1;
133
133
  $exclude_ids = $request->get_param( 'exclude_ids' ) ?? [];
134
134
  $next_page = $page + 1;
135
135
  $attributes = wp_parse_args(
@@ -22,4 +22,4 @@ if (PHP_VERSION_ID < 50600) {
22
22
 
23
23
  require_once __DIR__ . '/composer/autoload_real.php';
24
24
 
25
- return ComposerAutoloaderInit5d96d4d961eec32f3748ae0fac320267::getLoader();
25
+ return ComposerAutoloaderInitf86e2f467cfa249c74e507313f83d8cc::getLoader();
@@ -2,7 +2,7 @@
2
2
 
3
3
  // autoload_real.php @generated by Composer
4
4
 
5
- class ComposerAutoloaderInit5d96d4d961eec32f3748ae0fac320267
5
+ class ComposerAutoloaderInitf86e2f467cfa249c74e507313f83d8cc
6
6
  {
7
7
  private static $loader;
8
8
 
@@ -22,12 +22,12 @@ class ComposerAutoloaderInit5d96d4d961eec32f3748ae0fac320267
22
22
  return self::$loader;
23
23
  }
24
24
 
25
- spl_autoload_register(array('ComposerAutoloaderInit5d96d4d961eec32f3748ae0fac320267', 'loadClassLoader'), true, true);
25
+ spl_autoload_register(array('ComposerAutoloaderInitf86e2f467cfa249c74e507313f83d8cc', 'loadClassLoader'), true, true);
26
26
  self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
27
- spl_autoload_unregister(array('ComposerAutoloaderInit5d96d4d961eec32f3748ae0fac320267', 'loadClassLoader'));
27
+ spl_autoload_unregister(array('ComposerAutoloaderInitf86e2f467cfa249c74e507313f83d8cc', 'loadClassLoader'));
28
28
 
29
29
  require __DIR__ . '/autoload_static.php';
30
- call_user_func(\Composer\Autoload\ComposerStaticInit5d96d4d961eec32f3748ae0fac320267::getInitializer($loader));
30
+ call_user_func(\Composer\Autoload\ComposerStaticInitf86e2f467cfa249c74e507313f83d8cc::getInitializer($loader));
31
31
 
32
32
  $loader->register(true);
33
33
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  namespace Composer\Autoload;
6
6
 
7
- class ComposerStaticInit5d96d4d961eec32f3748ae0fac320267
7
+ class ComposerStaticInitf86e2f467cfa249c74e507313f83d8cc
8
8
  {
9
9
  public static $classMap = array (
10
10
  'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
@@ -13,7 +13,7 @@ class ComposerStaticInit5d96d4d961eec32f3748ae0fac320267
13
13
  public static function getInitializer(ClassLoader $loader)
14
14
  {
15
15
  return \Closure::bind(function () use ($loader) {
16
- $loader->classMap = ComposerStaticInit5d96d4d961eec32f3748ae0fac320267::$classMap;
16
+ $loader->classMap = ComposerStaticInitf86e2f467cfa249c74e507313f83d8cc::$classMap;
17
17
 
18
18
  }, null, ClassLoader::class);
19
19
  }
@@ -3,7 +3,7 @@
3
3
  'name' => 'automattic/newspack-blocks',
4
4
  'pretty_version' => 'dev-trunk',
5
5
  'version' => 'dev-trunk',
6
- 'reference' => '75d5ad1c651ab1218863b9443f02130d07ca3dae',
6
+ 'reference' => 'ee9d86eb6c81922b9ab7b6ea49ff4cd81b820d25',
7
7
  'type' => 'wordpress-plugin',
8
8
  'install_path' => __DIR__ . '/../../',
9
9
  'aliases' => array(),
@@ -13,7 +13,7 @@
13
13
  'automattic/newspack-blocks' => array(
14
14
  'pretty_version' => 'dev-trunk',
15
15
  'version' => 'dev-trunk',
16
- 'reference' => '75d5ad1c651ab1218863b9443f02130d07ca3dae',
16
+ 'reference' => 'ee9d86eb6c81922b9ab7b6ea49ff4cd81b820d25',
17
17
  'type' => 'wordpress-plugin',
18
18
  'install_path' => __DIR__ . '/../../',
19
19
  'aliases' => array(),