arie_cristianD

wcs frontend submit with qouta

Nov 9th, 2026
27
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 5.45 KB | None | 0 0
  1.  
  2. /**
  3.  * Frontend Submit quotas per paid Simple Subscription period.
  4.  * Keys are product slugs; unused articles do not carry into a new paid period.
  5.  */
  6. function jnews_frontend_article_quota( $user_id ) {
  7.     $result = array( 'managed' => false, 'remaining' => 0, 'claim' => null );
  8.     if ( ! $user_id || ! function_exists( 'wcs_get_users_subscriptions' ) ) {
  9.         return $result;
  10.     }
  11.     $limits = array( '4-article-subs' => 4, '8-article' => 8, '16-product' => 16 );
  12.     foreach ( wcs_get_users_subscriptions( $user_id ) as $subscription ) {
  13.         $limit = 0;
  14.         foreach ( $subscription->get_items() as $item ) {
  15.             $product = $item->get_product();
  16.             if ( $product && $product->is_type( 'subscription' ) ) {
  17.                 $key = $product->get_slug();
  18.                 if ( ! isset( $limits[ $key ] ) ) {
  19.                     $key = sanitize_title( $product->get_name() );
  20.                 }
  21.                 if ( isset( $limits[ $key ] ) ) {
  22.                     $limit += $limits[ $key ];
  23.                 }
  24.             }
  25.         }
  26.         if ( ! $limit ) {
  27.             continue;
  28.         }
  29.         $result['managed'] = true;
  30.         $end = $subscription->get_time( 'end' );
  31.         if ( ! $subscription->has_status( array( 'active', 'pending-cancel' ) ) || ( $end && $end <= time() ) ) {
  32.             continue;
  33.         }
  34.  
  35.         // Only a paid parent/renewal order starts a quota period. An unpaid
  36.         // renewal or reactivation of the same subscription cannot reset usage.
  37.         $paid_order = null;
  38.         $paid_time  = 0;
  39.         foreach ( $subscription->get_related_orders( 'all', array( 'parent', 'renewal' ) ) as $order ) {
  40.             $date = $order->get_date_paid();
  41.             if ( $order->is_paid() && $date && $date->getTimestamp() >= $paid_time ) {
  42.                 $paid_order = $order;
  43.                 $paid_time  = $date->getTimestamp();
  44.             }
  45.         }
  46.         if ( ! $paid_order ) {
  47.             continue;
  48.         }
  49.         $key       = '_jnews_article_usage_' . $paid_order->get_id();
  50.         $used      = (array) $subscription->get_meta( $key, true );
  51.         $used      = array_filter( $used );
  52.         $remaining = max( 0, $limit - count( $used ) );
  53.         $result['remaining'] += $remaining;
  54.         if ( $remaining && ! $result['claim'] ) {
  55.             $result['claim'] = array( 'subscription' => $subscription, 'key' => $key, 'used' => $used );
  56.         }
  57.     }
  58.     return $result;
  59. }
  60.  
  61. function jnews_frontend_submit_simple_subscription_access( $allowed ) {
  62.     if ( ! get_theme_mod( 'jnews_frontend_submit_enable_woocommerce', false ) || ! is_user_logged_in() ) {
  63.         return $allowed;
  64.     }
  65.     $quota = jnews_frontend_article_quota( get_current_user_id() );
  66.     return $quota['managed'] ? $quota['remaining'] > 0 : $allowed;
  67. }
  68. add_filter( 'jnews_frontend_submit_user_subscription', 'jnews_frontend_submit_simple_subscription_access' );
  69.  
  70. /**
  71.  * Check before the plugin's wp_loaded handler without modifying that handler.
  72.  * Serialize submissions by user so simultaneous requests cannot overspend.
  73.  */
  74. function jnews_frontend_article_quota_before_submit() {
  75.     if ( ! get_theme_mod( 'jnews_frontend_submit_enable_woocommerce', false ) || ! is_user_logged_in()
  76.         || ! isset( $_REQUEST['jnews-action'], $_REQUEST['jnews-editor-nonce'] )
  77.         || 'create-post' !== $_REQUEST['jnews-action']
  78.         || ! is_string( $_REQUEST['jnews-editor-nonce'] )
  79.         || ! wp_verify_nonce( $_REQUEST['jnews-editor-nonce'], 'jnews-editor' ) ) {
  80.         return;
  81.     }
  82.     $user_id = get_current_user_id();
  83.     $quota   = jnews_frontend_article_quota( $user_id );
  84.     if ( ! $quota['managed'] ) {
  85.         return;
  86.     }
  87.     $lock = 'jnews_article_submit_lock_' . $user_id;
  88.     $held = (int) get_option( $lock, 0 );
  89.     if ( $held && $held < time() - 300 ) {
  90.         delete_option( $lock );
  91.     }
  92.     if ( ! add_option( $lock, time(), '', false ) ) {
  93.         wp_die( esc_html__( 'Another article is being submitted. Please try again shortly.', 'jnews' ), '', array( 'response' => 409 ) );
  94.     }
  95.     register_shutdown_function( function () use ( $lock ) { delete_option( $lock ); } );
  96.     // Re-read after obtaining the lock in case another request just completed.
  97.     $quota = jnews_frontend_article_quota( $user_id );
  98.     if ( ! $quota['claim'] ) {
  99.         wp_die( esc_html__( 'Your subscription has no article quota available. Please renew or activate your subscription.', 'jnews' ), '', array( 'response' => 403 ) );
  100.     }
  101.     $GLOBALS['jnews_frontend_article_claim'] = $quota['claim'];
  102. }
  103. add_action( 'wp_loaded', 'jnews_frontend_article_quota_before_submit', 19 );
  104.  
  105. /**
  106.  * Charge only a successfully inserted new article; editing/deletion never refunds it.
  107.  */
  108. function jnews_frontend_article_quota_after_insert( $post_id, $post, $update ) {
  109.     if ( $update || empty( $GLOBALS['jnews_frontend_article_claim'] ) || 'post' !== $post->post_type
  110.         || (int) $post->post_author !== get_current_user_id() || in_array( $post->post_status, array( 'auto-draft', 'trash' ), true ) ) {
  111.         return;
  112.     }
  113.     $claim = $GLOBALS['jnews_frontend_article_claim'];
  114.     unset( $GLOBALS['jnews_frontend_article_claim'] );
  115.     $claim['used'][] = $post_id;
  116.     $claim['subscription']->update_meta_data( $claim['key'], array_unique( $claim['used'] ) );
  117.     $claim['subscription']->save_meta_data();
  118.     update_post_meta( $post_id, '_jnews_article_quota_subscription', $claim['subscription']->get_id() );
  119.     // Subscription quota replaces the plugin's one-time Post Package deduction.
  120.     update_post_meta( $post_id, 'finish_process', true );
  121. }
  122. add_action( 'wp_after_insert_post', 'jnews_frontend_article_quota_after_insert', 10, 3 );
  123.  
  124. function jnews_frontend_article_quota_remaining_text( $text ) {
  125.     $quota = jnews_frontend_article_quota( get_current_user_id() );
  126.     return $quota['managed'] ? (string) $quota['remaining'] : $text;
  127. }
  128. add_filter( 'jnews_frontend_submit_remaining_quota_text', 'jnews_frontend_article_quota_remaining_text' );
  129.  
Advertisement
Add Comment
Please, Sign In to add comment