Skip to content

Commit 1207526

Browse files
Alpha release Feb 05 (#4458)
2 parents fdca52b + 55b93e8 commit 1207526

78 files changed

Lines changed: 5242 additions & 1135 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

includes/bylines/class-bylines.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ public static function get_authors_avatars( $byline ) {
251251
* @param string $byline Byline with author shortcodes on it.
252252
*/
253253
public static function extract_author_ids_from_shortcode( $byline ) {
254-
preg_match_all( '/\[Author id=(\d+)\]/', $byline, $matches );
254+
preg_match_all( '/\[Author\s+id\s*=\s*(\d+)\]/i', $byline, $matches );
255255
return array_map( 'intval', $matches[1] );
256256
}
257257

includes/class-blocks.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ final class Blocks {
2121
*/
2222
public static function init() {
2323
require_once NEWSPACK_ABSPATH . 'src/blocks/reader-registration/index.php';
24+
require_once NEWSPACK_ABSPATH . 'src/blocks/my-account-button/class-my-account-button-block.php';
2425
require_once NEWSPACK_ABSPATH . 'src/blocks/content-gate/countdown/class-content-gate-countdown-block.php';
2526
require_once NEWSPACK_ABSPATH . 'src/blocks/content-gate/countdown-box/class-content-gate-countdown-box-block.php';
2627
require_once NEWSPACK_ABSPATH . 'src/blocks/contribution-meter/index.php';

includes/class-newspack-ui-icons.php

Lines changed: 24 additions & 24 deletions
Large diffs are not rendered by default.

includes/class-newspack-ui.php

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -428,7 +428,7 @@ public static function return_demo_content() {
428428
<div class="newspack-ui__dropdown">
429429
<button class="newspack-ui__dropdown__toggle newspack-ui__button newspack-ui__button--icon newspack-ui__button--ghost">
430430
<?php Newspack_UI_Icons::print_svg( 'more' ); ?>
431-
<span class="screen-reader-text">More</span>
431+
<span class="screen-reader-text"><?php esc_html_e( 'More', 'newspack-plugin' ); ?></span>
432432
</button>
433433
<div class="newspack-ui__dropdown__content">
434434
<ul>
@@ -448,7 +448,7 @@ public static function return_demo_content() {
448448
<div class="newspack-ui__dropdown">
449449
<button class="newspack-ui__dropdown__toggle newspack-ui__button newspack-ui__button--icon newspack-ui__button--ghost">
450450
<?php Newspack_UI_Icons::print_svg( 'more' ); ?>
451-
<span class="screen-reader-text">More</span>
451+
<span class="screen-reader-text"><?php esc_html_e( 'More', 'newspack-plugin' ); ?></span>
452452
</button>
453453
<div class="newspack-ui__dropdown__content">
454454
<ul>
@@ -518,15 +518,17 @@ public static function return_demo_content() {
518518
</div>
519519
</div>
520520
<button id="show-snackbar-example" class="newspack-ui__button newspack-ui__button--primary">Show snackbar</button>
521-
<div id="snackbar-example" class="newspack-ui__snackbar newspack-ui__snackbar--top-right newspack-ui__snackbar--success">
522-
This is a snackbar message
521+
<div class="newspack-ui__snackbar newspack-ui__snackbar--top-right">
522+
<div id="snackbar-example" class="newspack-ui__snackbar__item newspack-ui__snackbar__item--success" data-autohide="true">
523+
<div class="newspack-ui__snackbar__content">This is a snackbar message</div>
524+
</div>
523525
</div>
524526
<script>
525527
( function() {
526528
const snackbar = document.getElementById( 'snackbar-example' );
527529
const button = document.getElementById( 'show-snackbar-example' );
528530
button.addEventListener( 'click', function() {
529-
snackbar.classList.add( 'active' );
531+
newspackUI.notices.openNotice( snackbar, false );
530532
} );
531533
} )();
532534
</script>
@@ -761,7 +763,7 @@ public static function return_demo_content() {
761763
<h3>Dropdown buttons</h3>
762764
<div class="newspack-ui__dropdown">
763765
<button class="newspack-ui__button newspack-ui__button--secondary newspack-ui__dropdown__toggle">
764-
<span>More</span>
766+
<span><?php esc_html_e( 'More', 'newspack-plugin' ); ?></span>
765767
<?php Newspack_UI_Icons::print_svg( 'more' ); ?>
766768
</button>
767769
<div class="newspack-ui__dropdown__content">

includes/collections/class-content-inserter.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,13 @@ public static function check_if_post_is_in_collection() {
6464
return;
6565
}
6666

67-
$collections = Query_Helper::get_post_collections( $post );
67+
// Only show indicators for published collections.
68+
$collections = array_filter(
69+
Query_Helper::get_post_collections( $post ),
70+
function ( $collection_id ) {
71+
return 'publish' === get_post_status( $collection_id );
72+
}
73+
);
6874
if ( empty( $collections ) ) {
6975
return;
7076
}

includes/content-gate/class-access-rules.php

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,87 @@ public static function evaluate_rule( $rule_slug, $args = null, $user_id = null
168168
return call_user_func( $rule['callback'], $user_id, $args );
169169
}
170170

171+
/**
172+
* Evaluate access rules with OR logic between groups and AND logic within groups.
173+
*
174+
* Rules structure: [ [ rule1, rule2 ], [ rule3, rule4 ] ]
175+
* - Groups use OR logic: reader must pass at least one group
176+
* - Rules within a group use AND logic: reader must pass all rules in the group
177+
*
178+
* @param array $access_rules The access rules (array of groups, each group is an array of rules).
179+
*
180+
* @return bool True if access is granted, false if restricted.
181+
*/
182+
public static function evaluate_rules( $access_rules ) {
183+
if ( empty( $access_rules ) ) {
184+
return true;
185+
}
186+
187+
// Normalize legacy flat rules structure to grouped format.
188+
$access_rules = self::normalize_rules( $access_rules );
189+
190+
// Evaluate each group with OR logic - if any group passes, grant access.
191+
foreach ( $access_rules as $group ) {
192+
if ( self::evaluate_rules_group( $group ) ) {
193+
return true;
194+
}
195+
}
196+
197+
// No group passed - restrict access.
198+
return false;
199+
}
200+
201+
/**
202+
* Evaluate a single group of access rules with AND logic.
203+
*
204+
* @param array $group Array of rules in the group.
205+
*
206+
* @return bool True if all rules in the group pass, false otherwise.
207+
*/
208+
private static function evaluate_rules_group( $group ) {
209+
if ( empty( $group ) || ! is_array( $group ) ) {
210+
return true;
211+
}
212+
213+
foreach ( $group as $rule ) {
214+
if ( ! isset( $rule['slug'] ) ) {
215+
continue;
216+
}
217+
if ( ! self::evaluate_rule( $rule['slug'], $rule['value'] ?? null ) ) {
218+
return false;
219+
}
220+
}
221+
222+
return true;
223+
}
224+
225+
/**
226+
* Normalize access rules to grouped format.
227+
*
228+
* Converts legacy flat rules [ rule1, rule2 ] to grouped format [ [ rule1, rule2 ] ].
229+
*
230+
* @param array $access_rules The access rules.
231+
*
232+
* @return array Normalized access rules in grouped format.
233+
*/
234+
public static function normalize_rules( $access_rules ) {
235+
if ( empty( $access_rules ) ) {
236+
return [];
237+
}
238+
239+
// Check if already in grouped format (array of arrays with rules).
240+
// A grouped format has arrays as first-level elements.
241+
// A flat format has rule objects (with 'slug' key) as first-level elements.
242+
$first_element = reset( $access_rules );
243+
if ( is_array( $first_element ) && ! isset( $first_element['slug'] ) ) {
244+
// Already in grouped format.
245+
return $access_rules;
246+
}
247+
248+
// Convert flat format to single group.
249+
return [ $access_rules ];
250+
}
251+
171252
/**
172253
* Get subscriptions eligible for access rules.
173254
*
@@ -195,13 +276,50 @@ public static function get_subscription_products_options() {
195276

196277
/**
197278
* Whether the user has an active subscription for one of the given products.
279+
* Also checks if the user is a member of a group subscription with the required products.
198280
*
199281
* @param int $user_id User ID.
200282
* @param array $product_ids Required product IDs.
201283
* @return bool
202284
*/
203285
public static function has_active_subscription( $user_id, $product_ids ) {
204-
return ! empty( WooCommerce_Connection::get_active_subscriptions_for_user( $user_id, $product_ids ) );
286+
$has_subscription = false;
287+
288+
// Check user's own subscriptions.
289+
if ( ! empty( WooCommerce_Connection::get_active_subscriptions_for_user( $user_id, $product_ids ) ) ) {
290+
$has_subscription = true;
291+
}
292+
293+
// Check group subscriptions the user is a member of.
294+
if ( ! $has_subscription && function_exists( 'wcs_get_subscription' ) ) {
295+
$group_subscriptions = Group_Subscription::get_group_subscriptions_for_user( $user_id );
296+
foreach ( $group_subscriptions as $subscription ) {
297+
if ( ! $subscription || ! $subscription->has_status( WooCommerce_Connection::ACTIVE_SUBSCRIPTION_STATUSES ) ) {
298+
continue;
299+
}
300+
// If no product filter, any active group subscription grants access.
301+
if ( empty( $product_ids ) ) {
302+
$has_subscription = true;
303+
break;
304+
}
305+
// Check if the subscription has any of the required products.
306+
foreach ( $product_ids as $product_id ) {
307+
if ( $subscription->has_product( $product_id ) ) {
308+
$has_subscription = true;
309+
break 2;
310+
}
311+
}
312+
}
313+
}
314+
315+
/**
316+
* Filters whether a user has an active subscription for the given products.
317+
*
318+
* @param bool $has_subscription Whether the user has an active subscription.
319+
* @param int $user_id User ID.
320+
* @param array $product_ids Required product IDs.
321+
*/
322+
return apply_filters( 'newspack_access_rules_has_active_subscription', $has_subscription, $user_id, $product_ids );
205323
}
206324

207325
/**

0 commit comments

Comments
 (0)