'United States', 'GB' => 'United Kingdom', 'CA' => 'Canada', 'AU' => 'Australia', 'AT' => 'Austria', 'BE' => 'Belgium', 'BR' => 'Brazil', 'BG' => 'Bulgaria', 'HR' => 'Croatia', 'CY' => 'Cyprus', 'CZ' => 'Czech Republic', 'DK' => 'Denmark', 'EE' => 'Estonia', 'FI' => 'Finland', 'FR' => 'France', 'DE' => 'Germany', 'GR' => 'Greece', 'HK' => 'Hong Kong', 'HU' => 'Hungary', 'IE' => 'Ireland', 'IT' => 'Italy', 'JP' => 'Japan', 'LV' => 'Latvia', 'LT' => 'Lithuania', 'LU' => 'Luxembourg', 'MY' => 'Malaysia', 'MT' => 'Malta', 'MX' => 'Mexico', 'NL' => 'Netherlands', 'NZ' => 'New Zealand', 'NO' => 'Norway', 'PL' => 'Poland', 'PT' => 'Portugal', 'RO' => 'Romania', 'SG' => 'Singapore', 'SK' => 'Slovakia', 'SI' => 'Slovenia', 'ES' => 'Spain', 'SE' => 'Sweden', 'CH' => 'Switzerland', 'TH' => 'Thailand', 'AE' => 'United Arab Emirates', ); } function acta_get_supported_currencies() { return array( 'usd' => 'USD - US Dollar', 'eur' => 'EUR - Euro', 'gbp' => 'GBP - British Pound', 'cad' => 'CAD - Canadian Dollar', 'aud' => 'AUD - Australian Dollar', 'jpy' => 'JPY - Japanese Yen', 'chf' => 'CHF - Swiss Franc', 'nzd' => 'NZD - New Zealand Dollar', 'sek' => 'SEK - Swedish Krona', 'nok' => 'NOK - Norwegian Krone', 'dkk' => 'DKK - Danish Krone', 'sgd' => 'SGD - Singapore Dollar', 'hkd' => 'HKD - Hong Kong Dollar', 'mxn' => 'MXN - Mexican Peso', 'brl' => 'BRL - Brazilian Real', 'pln' => 'PLN - Polish Zloty', 'czk' => 'CZK - Czech Koruna', 'huf' => 'HUF - Hungarian Forint', 'ron' => 'RON - Romanian Leu', 'bgn' => 'BGN - Bulgarian Lev', 'thb' => 'THB - Thai Baht', 'myr' => 'MYR - Malaysian Ringgit', 'aed' => 'AED - UAE Dirham', ); } // ─── Activation: generate a secret key ─────────────────────────────────────── register_activation_hook( __FILE__, 'acta_activate' ); function acta_activate() { if ( ! get_option( ACTA_OPTION_KEY ) ) { update_option( ACTA_OPTION_KEY, bin2hex( random_bytes( 32 ) ) ); } // Initialize connection status if not set if ( ! get_option( ACTA_CONNECTION_STATUS ) ) { update_option( ACTA_CONNECTION_STATUS, 'not_registered' ); } // Redirect to the Acta settings page after activation. update_option( ACTA_ACTIVATION_REDIRECT_OPTION, 1 ); } // Also redirect after plugin update (upload zip) — WordPress shows "Go to Plugin Installer" link otherwise. add_action( 'upgrader_process_complete', 'acta_maybe_set_redirect_after_update', 10, 2 ); function acta_maybe_set_redirect_after_update( $upgrader_object, $options ) { if ( empty( $options['action'] ) || $options['action'] !== 'update' ) { return; } if ( empty( $options['type'] ) || $options['type'] !== 'plugin' ) { return; } $our_plugin = plugin_basename( __FILE__ ); $updated = array(); if ( ! empty( $options['plugins'] ) && is_array( $options['plugins'] ) ) { $updated = $options['plugins']; } elseif ( ! empty( $options['plugin'] ) ) { $updated = array( $options['plugin'] ); } if ( in_array( $our_plugin, $updated, true ) ) { update_option( ACTA_ACTIVATION_REDIRECT_OPTION, 1 ); } } add_action( 'admin_init', 'acta_maybe_redirect_after_activation' ); function acta_maybe_redirect_after_activation() { if ( ! get_option( ACTA_ACTIVATION_REDIRECT_OPTION ) ) { return; } delete_option( ACTA_ACTIVATION_REDIRECT_OPTION ); if ( ! is_admin() || ! current_user_can( 'manage_options' ) || wp_doing_ajax() ) { return; } if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) { return; } if ( isset( $_GET['activate-multi'] ) ) { return; } wp_safe_redirect( admin_url( 'admin.php?page=' . ACTA_ADMIN_PAGE_SLUG ) ); exit; } // ─── Admin settings page ───────────────────────────────────────────────────── add_action( 'admin_menu', 'acta_add_admin_menu' ); add_action( 'admin_enqueue_scripts', 'acta_enqueue_admin_scripts' ); function acta_enqueue_admin_scripts( $hook ) { if ( 'toplevel_page_' . ACTA_ADMIN_PAGE_SLUG !== $hook ) { return; } $asset_url = plugin_dir_url( __FILE__ ) . 'assets/js/admin-copy-price.js'; wp_enqueue_script( 'acta-admin-copy-price', $asset_url, array(), ACTA_PLUGIN_VERSION, true ); } function acta_add_admin_menu() { add_menu_page( 'Acta Settings', 'Acta', 'manage_options', ACTA_ADMIN_PAGE_SLUG, 'acta_settings_page', ACTA_MENU_ICON, 30 ); } add_action( 'admin_init', 'acta_settings_init' ); function acta_settings_init() { register_setting( 'acta_settings', ACTA_OPTION_KEY, array( 'sanitize_callback' => 'sanitize_text_field', ) ); register_setting( 'acta_settings', ACTA_PUBLISHER_ID_KEY, array( 'sanitize_callback' => 'sanitize_text_field', ) ); } // ─── Backend API functions ─────────────────────────────────────────────────── /** * Self-service onboarding: create a new publisher on the Acta backend. * Called when publisher clicks "Get Started with Acta". * * @return array { success: bool, message: string, publisherId?: string, stripeOnboardingUrl?: string } */ function acta_onboard_to_backend( $email, $first_name, $last_name, $country, $currency, $article_price ) { $backend_url = rtrim( ACTA_BACKEND_URL, '/' ) . '/api/v1/public/onboard-wordpress'; $secret = get_option( ACTA_OPTION_KEY, '' ); $endpoint = rest_url( 'acta/v1/content' ); $response = wp_remote_post( $backend_url, array( 'timeout' => 30, 'headers' => array( 'Content-Type' => 'application/json' ), 'body' => wp_json_encode( array( 'email' => $email, 'firstName' => $first_name, 'lastName' => $last_name, 'website' => home_url(), 'name' => get_bloginfo( 'name' ), 'country' => $country, 'currency' => $currency, 'articlePrice' => (float) $article_price, 'pluginEndpoint' => $endpoint, 'pluginSecretKey'=> $secret, ) ), ) ); if ( is_wp_error( $response ) ) { return array( 'success' => false, 'message' => 'Connection failed: ' . $response->get_error_message(), ); } $code = wp_remote_retrieve_response_code( $response ); $body = json_decode( wp_remote_retrieve_body( $response ), true ); if ( $code === 201 && ! empty( $body['success'] ) ) { return array( 'success' => true, 'message' => 'Publisher created successfully.', 'publisherId' => $body['publisherId'] ?? '', 'stripeOnboardingUrl'=> $body['stripeOnboardingUrl'] ?? '', ); } $error_msg = $body['error'] ?? ( 'HTTP ' . $code ); return array( 'success' => false, 'message' => $error_msg, ); } /** * Reconnect the plugin to an existing publisher on the Acta backend. * Used for plugin reinstall or v1 → v2 migration. */ function acta_connect_to_backend( $publisher_id, $plugin_endpoint, $plugin_secret_key ) { $backend_url = rtrim( ACTA_BACKEND_URL, '/' ) . '/api/v1/public/connect-wordpress'; $response = wp_remote_post( $backend_url, array( 'timeout' => 15, 'headers' => array( 'Content-Type' => 'application/json' ), 'body' => wp_json_encode( array( 'publisherId' => $publisher_id, 'siteUrl' => home_url(), 'pluginEndpoint' => $plugin_endpoint, 'pluginSecretKey' => $plugin_secret_key, ) ), ) ); if ( is_wp_error( $response ) ) { return array( 'success' => false, 'message' => 'Connection failed: ' . $response->get_error_message(), ); } $code = wp_remote_retrieve_response_code( $response ); $body = json_decode( wp_remote_retrieve_body( $response ), true ); if ( $code === 200 && ! empty( $body['success'] ) ) { return array( 'success' => true, 'message' => $body['message'] ?? 'Connected successfully.', ); } $error_msg = $body['error'] ?? ( 'HTTP ' . $code ); return array( 'success' => false, 'message' => $error_msg, ); } /** * Fetch publisher info (article price, rate limit) from Acta backend. * * @return array{ articlePrice: float, changesRemaining: int, revShare?: int }|null */ function acta_fetch_publisher_info( $publisher_id, $secret, $site_url ) { if ( empty( $publisher_id ) || empty( $secret ) ) { return null; } $url = rtrim( ACTA_BACKEND_URL, '/' ) . '/api/v1/public/wordpress-publisher-info'; $response = wp_remote_post( $url, array( 'timeout' => 10, 'headers' => array( 'Content-Type' => 'application/json' ), 'body' => wp_json_encode( array( 'publisherId' => $publisher_id, 'key' => $secret, 'siteUrl' => $site_url, ) ), ) ); if ( is_wp_error( $response ) ) { return null; } $code = wp_remote_retrieve_response_code( $response ); if ( $code !== 200 ) { return null; } $body = json_decode( wp_remote_retrieve_body( $response ), true ); if ( ! is_array( $body ) || ! isset( $body['articlePrice'] ) ) { return null; } return array( 'articlePrice' => (float) $body['articlePrice'], 'changesRemaining' => isset( $body['changesRemaining'] ) ? (int) $body['changesRemaining'] : 3, 'revShare' => isset( $body['revShare'] ) ? (int) $body['revShare'] : 15, ); } /** * Update default article price via Acta backend. * * @return array{ success: bool, message: string, articlePrice?: float, changesRemaining?: int } */ function acta_update_default_price( $publisher_id, $secret, $site_url, $article_price ) { $url = rtrim( ACTA_BACKEND_URL, '/' ) . '/api/v1/public/wordpress-update-article-price'; $body = array( 'publisherId' => $publisher_id, 'key' => $secret, 'siteUrl' => $site_url, 'articlePrice' => (float) $article_price, ); $response = wp_remote_post( $url, array( 'timeout' => 15, 'headers' => array( 'Content-Type' => 'application/json' ), 'body' => wp_json_encode( $body ), ) ); if ( is_wp_error( $response ) ) { return array( 'success' => false, 'message' => $response->get_error_message(), ); } $code = wp_remote_retrieve_response_code( $response ); $body = json_decode( wp_remote_retrieve_body( $response ), true ); if ( $code === 200 && ! empty( $body['success'] ) ) { return array( 'success' => true, 'message' => 'Default price updated.', 'articlePrice' => $body['articlePrice'] ?? $article_price, 'changesRemaining' => $body['changesRemaining'] ?? 0, ); } return array( 'success' => false, 'message' => $body['error'] ?? ( 'HTTP ' . $code ), ); } /** * Push the paywall mode (pay-per-article only vs. alongside subscriptions) to * the Acta backend. Stored on the publisher record and delivered to the embed * script at runtime — so the flag never lives in (cacheable) page HTML and a * toggle takes effect on the next page load without a cache purge. */ function acta_update_paywall_mode( $publisher_id, $secret, $site_url, $subscribe_override ) { $url = rtrim( ACTA_BACKEND_URL, '/' ) . '/api/v1/public/wordpress-update-paywall-mode'; $body = array( 'publisherId' => $publisher_id, 'key' => $secret, 'siteUrl' => $site_url, 'subscribeOverride' => (bool) $subscribe_override, ); $response = wp_remote_post( $url, array( 'timeout' => 15, 'headers' => array( 'Content-Type' => 'application/json' ), 'body' => wp_json_encode( $body ), ) ); if ( is_wp_error( $response ) ) { return array( 'success' => false, 'message' => $response->get_error_message(), ); } $code = wp_remote_retrieve_response_code( $response ); $body = json_decode( wp_remote_retrieve_body( $response ), true ); if ( $code === 200 && ! empty( $body['success'] ) ) { return array( 'success' => true ); } return array( 'success' => false, 'message' => $body['error'] ?? ( 'HTTP ' . $code ), ); } // ─── Settings page renderer ───────────────────────────────────────────────── function acta_settings_page() { $secret = get_option( ACTA_OPTION_KEY, '' ); $publisher_id = get_option( ACTA_PUBLISHER_ID_KEY, '' ); $stripe_url = get_option( ACTA_STRIPE_URL_KEY, '' ); $conn_status = get_option( ACTA_CONNECTION_STATUS, 'not_registered' ); $endpoint = rest_url( 'acta/v1/content' ); // ── Handle form actions ────────────────────────────────────────────────── // Handle "Get Started with Acta" (self-service onboarding) if ( isset( $_POST['acta_action'] ) && $_POST['acta_action'] === 'onboard' && check_admin_referer( 'acta_onboard' ) ) { $email = sanitize_email( wp_unslash( $_POST['acta_email'] ?? '' ) ); $first_name = sanitize_text_field( wp_unslash( $_POST['acta_first_name'] ?? '' ) ); $last_name = sanitize_text_field( wp_unslash( $_POST['acta_last_name'] ?? '' ) ); $country = sanitize_text_field( wp_unslash( $_POST['acta_country'] ?? '' ) ); $currency = sanitize_text_field( wp_unslash( $_POST['acta_currency'] ?? '' ) ); $article_price = floatval( wp_unslash( $_POST['acta_article_price'] ?? 0 ) ); if ( empty( $email ) || empty( $first_name ) || empty( $last_name ) || empty( $country ) || empty( $currency ) || $article_price <= 0 ) { echo '

' . esc_html__( 'All fields are required. Please fill in your email, name, country, currency, and a price greater than 0.', 'acta-pay-per-article' ) . '

'; } else { $result = acta_onboard_to_backend( $email, $first_name, $last_name, $country, $currency, $article_price ); if ( $result['success'] ) { update_option( ACTA_PUBLISHER_ID_KEY, $result['publisherId'] ); update_option( ACTA_STRIPE_URL_KEY, $result['stripeOnboardingUrl'] ); update_option( ACTA_CONNECTION_STATUS, 'registered' ); $publisher_id = $result['publisherId']; $stripe_url = $result['stripeOnboardingUrl']; $conn_status = 'registered'; echo '

' . esc_html__( 'Successfully registered! Complete your Stripe setup below to start accepting payments.', 'acta-pay-per-article' ) . '

'; } else { echo '

' . esc_html( $result['message'] ) . '

'; } } } // Handle "I've completed Stripe setup" — check if Stripe is done if ( isset( $_POST['acta_action'] ) && $_POST['acta_action'] === 'check_stripe' && check_admin_referer( 'acta_check_stripe' ) ) { // The Stripe onboarding URL becomes invalid once completed. // We mark as live — the backend's /connect/success endpoint already set account_url to null. update_option( ACTA_CONNECTION_STATUS, 'live' ); update_option( ACTA_STRIPE_URL_KEY, '' ); $conn_status = 'live'; $stripe_url = ''; echo '

' . esc_html__( 'Status updated. If your Stripe setup is complete, you\'re live!', 'acta-pay-per-article' ) . '

'; } // Handle "Update default price" if ( $conn_status === 'live' && isset( $_POST['acta_action'] ) && $_POST['acta_action'] === 'update_default_price' && check_admin_referer( 'acta_update_default_price' ) ) { $new_price = floatval( wp_unslash( $_POST['acta_default_price'] ?? 0 ) ); if ( $new_price > 0 ) { $result = acta_update_default_price( $publisher_id, $secret, home_url(), $new_price ); if ( $result['success'] ) { echo '

' . esc_html__( 'Default price updated to ', 'acta-pay-per-article' ) . esc_html( number_format( $result['articlePrice'], 2 ) ) . '.

'; } else { echo '

' . esc_html( $result['message'] ) . '

'; } } } // Handle "Save paywall mode" (subscription + pay-per-article vs pay-per-article only) if ( $conn_status === 'live' && isset( $_POST['acta_action'] ) && $_POST['acta_action'] === 'save_paywall_mode' && check_admin_referer( 'acta_save_paywall_mode' ) ) { $override = ( '1' === sanitize_text_field( wp_unslash( $_POST['acta_subscribe_override'] ?? '0' ) ) ) ? '1' : '0'; $result = acta_update_paywall_mode( $publisher_id, $secret, home_url(), '1' === $override ); if ( $result['success'] ) { update_option( ACTA_SUBSCRIBE_OVERRIDE_KEY, $override ); echo '

' . ( '1' === $override ? esc_html__( 'Saved. Acta will now replace your subscribe paywall with a pay-per-article button.', 'acta-pay-per-article' ) : esc_html__( 'Saved. Acta will mount alongside your existing subscription paywall.', 'acta-pay-per-article' ) ) . '

'; } else { echo '

' . esc_html( $result['message'] ) . '

'; } } // 4.2.0 briefly offered a "Disconnect Acta" button. The feature was removed // in 4.2.1 because it could not change any settings, which is what people // actually wanted it for. Any site left in the disconnected state is // reconnected here, so it cannot be stranded on a screen that no longer // exists. Harmless on every other install. if ( 'disconnected' === $conn_status ) { if ( ! empty( $publisher_id ) && ! empty( $secret ) ) { acta_connect_to_backend( $publisher_id, $endpoint, $secret ); } update_option( ACTA_CONNECTION_STATUS, 'live' ); $conn_status = 'live'; } // ── Render the settings page ───────────────────────────────────────────── $countries = acta_get_supported_countries(); $currencies = acta_get_supported_currencies(); $subscribe_override = '1' === get_option( ACTA_SUBSCRIBE_OVERRIDE_KEY, '' ); ?>

Acta Settings

Acta is a pay-per-content solution for publishers and creators.

Version

Get started accepting payments on your content

How much readers pay to unlock a single article.

✓ Connected to Acta

Publisher ID:

Complete your Stripe setup

You need to set up your Stripe account to receive payments from readers. This takes about 5 minutes.

Complete Stripe Setup →

✓ You're live with Acta!

✓ Stripe setup complete — readers can now purchase your articles.

Publisher ID:

How Acta works

Acta adds a “Read instantly” button to the paywall you already use, giving readers the option to buy a single article. Your subscription offer stays exactly as it is — Acta finds your paywall and adds the button automatically.

Works with: Jetpack, MemberPress, Paid Memberships Pro, Restrict Content Pro, and more. If something looks off, just contact us and we’ll sort it out.

No paywall yet? Install the free Jetpack plugin and add a Paywall block where the article should lock — Acta integrates right within it.

Your price: Set any price per article (see currency minimums).

Our fee: No setup or monthly fee; % rev share including processor fees.

Questions or need setup help? Reach us at contact@readwithacta.com.

Paywall mode

Change default price

Current default price:

Set a custom price on an article

By default, all articles use your default price. To set a different price on a specific article, add a Custom HTML block in the post editor (before the paywall break) with this snippet:

<div id="acta-price" data-price="ENTER_PRICE_HERE"></div>

Replace ENTER_PRICE_HERE with the price (e.g. 2.99). This overrides the default price for that article only.

Contact us at contact@readwithacta.com or visit readwithacta.com

'GET', 'callback' => 'acta_get_content', 'permission_callback' => 'acta_verify_secret', 'args' => array( 'slug' => array( 'required' => true, 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field', ), 'key' => array( 'required' => true, 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field', ), ), ) ); } /** * Verify the shared secret key sent in the request. * This is our auth layer — only Acta backend (which knows the key) can call this. */ function acta_verify_secret( WP_REST_Request $request ) { $secret = get_option( ACTA_OPTION_KEY, '' ); if ( empty( $secret ) ) { return new WP_Error( 'acta_not_configured', 'Acta plugin not configured.', array( 'status' => 503 ) ); } $provided = $request->get_param( 'key' ); // Constant-time comparison to prevent timing attacks if ( ! hash_equals( $secret, (string) $provided ) ) { return new WP_Error( 'acta_unauthorized', 'Invalid secret key.', array( 'status' => 401 ) ); } return true; } /** * Main content delivery callback. * Gets raw post content from DB, strips all paywall markers, then renders via the_content filter. */ function acta_get_content( WP_REST_Request $request ) { $slug = $request->get_param( 'slug' ); // Try post types in order: post, page, then any custom post type $post = acta_get_post_by_slug( $slug, array( 'post', 'page' ) ); if ( ! $post ) { return new WP_Error( 'acta_not_found', 'Post not found for slug: ' . $slug, array( 'status' => 404 ) ); } // Get the raw content from the database (no filters applied yet) $raw_content = $post->post_content; // Strip all known paywall markers from raw content $clean_content = acta_strip_paywall_markers( $raw_content ); // Apply the_content filters (image sizing, shortcodes, embeds, etc.) // but NOT the paywall filters (they've been stripped above) $clean_content = acta_apply_content_filters( $clean_content, $post->ID ); return new WP_REST_Response( array( 'slug' => $slug, 'id' => $post->ID, 'status' => $post->post_status, 'content' => $clean_content, 'version' => ACTA_PLUGIN_VERSION, ), 200 ); } /** * Find a post by slug across multiple post types. */ function acta_get_post_by_slug( $slug, $post_types = array( 'post', 'page' ) ) { $args = array( 'name' => $slug, 'post_type' => $post_types, 'post_status' => 'publish', 'posts_per_page' => 1, ); $posts = get_posts( $args ); return ! empty( $posts ) ? $posts[0] : null; } /** * Strip all known paywall markers from raw Gutenberg/classic post content. */ function acta_strip_paywall_markers( $content ) { // ── Jetpack / WordPress.com $content = preg_replace( '//', '', $content ); $content = preg_replace( '/[\s\S]*?/', '', $content ); // ── MemberPress $content = preg_replace_callback( '/\[mepr-active[^\]]*\]([\s\S]*?)\[\/mepr-active\]/i', function( $m ) { return $m[1]; }, $content ); $content = preg_replace( '/\[mepr-unauthorized[^\]]*\][\s\S]*?\[\/mepr-unauthorized\]/i', '', $content ); // ── Restrict Content Pro $content = preg_replace_callback( '/\[restrict[^\]]*\]([\s\S]*?)\[\/restrict\]/i', function( $m ) { return $m[1]; }, $content ); // ── Paid Memberships Pro $content = preg_replace_callback( '/\[membership[^\]]*\]([\s\S]*?)\[\/membership\]/i', function( $m ) { return $m[1]; }, $content ); // ── WooCommerce Memberships $content = preg_replace_callback( '/\[wcm_restrict[^\]]*\]([\s\S]*?)\[\/wcm_restrict\]/i', function( $m ) { return $m[1]; }, $content ); // ── Paid Member Subscriptions $content = preg_replace_callback( '/\[pms-content[^\]]*\]([\s\S]*?)\[\/pms-content\]/i', function( $m ) { return $m[1]; }, $content ); // ── Simple Membership $content = preg_replace_callback( '/\[swpm_protected[^\]]*\]([\s\S]*?)\[\/swpm_protected\]/i', function( $m ) { return $m[1]; }, $content ); // ── s2Member $content = preg_replace_callback( '/\[s2If[^\]]*\]([\s\S]*?)\[\/s2If\]/i', function( $m ) { return $m[1]; }, $content ); // ── LeakyPaywall $content = preg_replace( '/\[leaky_paywall_content\][\s\S]*?\[\/leaky_paywall_content\]/i', '', $content ); // ── based paywalls if ( acta_uses_more_tag_as_gate() ) { $content = str_replace( '', '', $content ); $content = str_replace( '', '', $content ); } return $content; } /** * Detect whether any active plugin uses as its paywall gate. */ function acta_uses_more_tag_as_gate() { $more_gate_plugins = array( 'paid-memberships-pro/paid-memberships-pro.php', 'woocommerce-memberships/woocommerce-memberships.php', 'subscriptions-for-woocommerce/subscriptions-for-woocommerce.php', ); foreach ( $more_gate_plugins as $plugin ) { if ( is_plugin_active( $plugin ) ) { return true; } } return false; } /** * Apply WordPress content filters while temporarily suppressing paywall re-gating. */ function acta_apply_content_filters( $content, $post_id ) { $removed_hooks = acta_remove_paywall_hooks(); global $post; $original_post = $post; $post = get_post( $post_id ); setup_postdata( $post ); $rendered = apply_filters( 'the_content', $content ); $post = $original_post; if ( $original_post ) { setup_postdata( $original_post ); } else { wp_reset_postdata(); } acta_restore_paywall_hooks( $removed_hooks ); return $rendered; } /** * Remove known paywall plugin filter hooks from the_content. * Returns the removed hooks so they can be restored. */ function acta_remove_paywall_hooks() { global $wp_filter; $removed = array(); if ( ! isset( $wp_filter['the_content'] ) ) { return $removed; } $method_patterns = array( 'add_paywall', 'jetpack_memberships_protect_content', 'jetpack_subscriptions_protect_content', 'mepr_content_protection', 'meprContentProtection', 'rcp_restrict_content', 'rcp_post_content_filter', 'pmpro_the_content', 'pmpro_protect_content', 'wc_memberships_restrict_content', 'pms_restrict_content', 'swpm_the_content_filter', 's2member_the_content_filter', 'leaky_paywall_content_filter', 'um_restrict_content', 'sumo_restrict_content', ); $class_patterns = array( 'Jetpack\\Extensions\\Subscriptions', 'Jetpack\\Memberships', 'MeprContent', 'RCP_Content', 'PMPro', 'WC_Memberships', ); foreach ( $wp_filter['the_content']->callbacks as $priority => $callbacks ) { foreach ( $callbacks as $key => $callback ) { $func = $callback['function']; $func_name = ''; $class_name = ''; $should_remove = false; if ( is_string( $func ) ) { $func_name = $func; } elseif ( is_array( $func ) && isset( $func[1] ) ) { $func_name = is_string( $func[1] ) ? $func[1] : ''; $class_name = is_object( $func[0] ) ? get_class( $func[0] ) : (string) $func[0]; } foreach ( $method_patterns as $pattern ) { if ( stripos( $func_name, $pattern ) !== false ) { $should_remove = true; break; } } if ( ! $should_remove && $class_name ) { foreach ( $class_patterns as $pattern ) { if ( stripos( $class_name, $pattern ) !== false ) { $should_remove = true; break; } } } if ( $should_remove ) { $removed[] = array( 'priority' => $priority, 'callback' => $func, 'accepted_args' => $callback['accepted_args'], ); remove_filter( 'the_content', $func, $priority ); } } } return $removed; } /** * Restore previously removed paywall filter hooks. */ function acta_restore_paywall_hooks( $removed_hooks ) { foreach ( $removed_hooks as $hook ) { add_filter( 'the_content', $hook['callback'], $hook['priority'], $hook['accepted_args'] ); } }