Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.DS_Store
.idea

# Manage wordpress/wp-content/plugins/memberful-wp and ignore everything else
# from the wordpress/ folder.
Expand Down
6 changes: 4 additions & 2 deletions wordpress/wp-content/plugins/memberful-wp/js/src/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,17 @@ jQuery(document).ready(function($){
let editor = tinyMCE.editors[0];
let globalContent=$('#use_global_marketing_checkbox');
let snippetContent=$('#use_global_snippets_checkbox');
let modeRadios=$('input[name="memberful_paywall[mode]"]');

function checkGlobalValidity(e){
let isGlobal=globalContent.is(':checked');
let isSnippets=snippetContent.is(':checked');
let isCustomHtml=modeRadios.filter(':checked').val() === 'custom_html';
let submit=$('button[type="submit"]');
let isContentEmpty=!editor.getContent().trim();

let warning=$('#global_content_required');

if( isGlobal && isContentEmpty ){
if( isGlobal && isCustomHtml && isContentEmpty ){
submit.prop('disabled', true);
warning.show();

Expand All @@ -86,6 +87,7 @@ jQuery(document).ready(function($){

globalContent.change(checkGlobalValidity)
snippetContent.change(checkGlobalValidity)
modeRadios.change(checkGlobalValidity)
editor.on('change', checkGlobalValidity);
}

Expand Down
69 changes: 69 additions & 0 deletions wordpress/wp-content/plugins/memberful-wp/js/src/paywall-banner.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/**
* Memberful paywall banner - measure-based full-bleed.
*
* Pure CSS can't make a banner span the visible viewport when the post column
* is offset by a sidebar (classic themes with non-centered content). This
* script measures the banner's parent against documentElement.clientWidth and
* applies inline margin/width so the banner reaches both viewport edges
* exactly. Runs synchronously from a footer enqueue so first paint is correct
* (no flash of off-center content).
*/
( function () {
'use strict';

function measure( banner ) {
var parent = banner.parentElement;
if ( ! parent ) {
return;
}

// Reset any previous measurement so parent rect reflects natural flow.
banner.style.marginInlineStart = '';
banner.style.marginInlineEnd = '';
banner.style.width = '';

var viewportWidth = document.documentElement.clientWidth;
var parentRect = parent.getBoundingClientRect();

var startMargin = -parentRect.left;
var endMargin = parentRect.right - viewportWidth;

banner.style.marginInlineStart = startMargin + 'px';
banner.style.marginInlineEnd = endMargin + 'px';
banner.style.width = viewportWidth + 'px';
}

function init() {
var banners = document.querySelectorAll( '.memberful-paywall--banner' );
if ( ! banners.length ) {
return;
}

banners.forEach( function ( banner ) {
measure( banner );

var pending = null;
var schedule = function () {
if ( pending !== null ) {
return;
}
pending = window.requestAnimationFrame( function () {
pending = null;
measure( banner );
} );
};

window.addEventListener( 'resize', schedule, { passive: true } );

if ( typeof ResizeObserver !== 'undefined' && banner.parentElement ) {
new ResizeObserver( schedule ).observe( banner.parentElement );
}
} );
}

if ( document.readyState === 'loading' ) {
document.addEventListener( 'DOMContentLoaded', init );
} else {
init();
}
} )();
114 changes: 114 additions & 0 deletions wordpress/wp-content/plugins/memberful-wp/js/src/paywall-builder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
jQuery(function ($) {
const $form = $('.memberful-paywall-builder__panel[data-panel="builder"]');
const $modeInputs = $('input[name="memberful_paywall[mode]"]');
const $panels = $('.memberful-paywall-builder__panel');
const $preview = $('#memberful-paywall-preview');
const $colorInput = $('.memberful-paywall-builder__color');

const preview = window.memberfulPaywallPreview || {};
const DEBOUNCE_MS = 250;

let debounceTimer = null;
let requestSeq = 0;

$colorInput.wpColorPicker({
change: function () {
setTimeout(scheduleRefresh, 0);
},
clear: function () {
setTimeout(scheduleRefresh, 0);
},
});

function applyMode(mode) {
$panels.each(function () {
this.style.display = this.dataset.panel === mode ? '' : 'none';
});
}

$modeInputs.on('change', function () {
if (!this.checked) {
return;
}

applyMode(this.value);

if (this.value === 'builder') {
refreshPreview();
}
});
Comment thread
coderabbitai[bot] marked this conversation as resolved.

applyMode($modeInputs.filter(':checked').val() || 'builder');

function collectConfig() {
return {
mode: $('input[name="memberful_paywall[mode]"]:checked').val() || 'builder',
layout: $('input[name="memberful_paywall[layout]"]:checked').val() || 'card',
heading: $('#memberful-paywall-heading').val() || '',
heading_tag: $('#memberful-paywall-heading-tag').val() || 'h2',
subheading: $('#memberful-paywall-subheading').val() || '',
features: $('#memberful-paywall-features').val() || '',
button_label: $('#memberful-paywall-button-label').val() || '',
subscribe_url: $('#memberful-paywall-subscribe-url').val() || '',
sign_in_url: $('#memberful-paywall-signin-url').val() || '',
brand_color: $colorInput.val() || '',
button_shape: $('#memberful-paywall-button-shape').val() || 'rounded',
};
}

function refreshPreview() {
if (!preview.ajaxUrl || !preview.action || !preview.nonce || !$preview.length) {
return;
}

clearTimeout(debounceTimer);

const seq = ++requestSeq;
const body = new URLSearchParams();
body.set('action', preview.action);
body.set('nonce', preview.nonce);

const config = collectConfig();
Object.keys(config).forEach(function (key) {
body.append('config[' + key + ']', config[key]);
});

fetch(preview.ajaxUrl, {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
body: body.toString(),
})
.then(function (res) {
if (!res.ok) {
throw new Error('Request failed: ' + res.status);
}

return res.json();
})
.then(function (json) {
if (seq !== requestSeq) {
return;
}

if (json && json.success && json.data && json.data.html) {
$preview.attr('srcdoc', json.data.html);
}
})
.catch(function (err) {
console.error('Paywall preview failed', err);
});
}

function scheduleRefresh() {
clearTimeout(debounceTimer);
debounceTimer = setTimeout(refreshPreview, DEBOUNCE_MS);
}

$form.on('input', 'input[type="text"], input[type="url"], textarea', scheduleRefresh);
$form.on('change', 'input[type="radio"], select', refreshPreview);

if (($modeInputs.filter(':checked').val() || 'builder') === 'builder') {
refreshPreview();
}
});
1 change: 1 addition & 0 deletions wordpress/wp-content/plugins/memberful-wp/memberful-wp.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
require_once MEMBERFUL_DIR . '/src/widgets.php';
require_once MEMBERFUL_DIR . '/src/endpoints.php';
require_once MEMBERFUL_DIR . '/src/marketing_content.php';
require_once MEMBERFUL_DIR . '/src/paywall.php';
require_once MEMBERFUL_DIR . '/src/content_filter.php';
require_once MEMBERFUL_DIR . '/src/search_filter.php';
require_once MEMBERFUL_DIR . '/src/entities.php';
Expand Down
50 changes: 44 additions & 6 deletions wordpress/wp-content/plugins/memberful-wp/src/admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,34 @@ function memberful_wp_admin_enqueue_scripts() {
);
}

if (
'memberful_options' === filter_input( INPUT_GET, 'page' )
&& 'global_marketing' === filter_input( INPUT_GET, 'subpage' )
) {
wp_enqueue_style( 'wp-color-picker' );

wp_enqueue_style(
'memberful-paywall',
MEMBERFUL_URL . '/stylesheets/paywall.css',
array(),
MEMBERFUL_VERSION
);

wp_enqueue_script(
'memberful-paywall-builder',
MEMBERFUL_URL . '/js/build/paywall-builder.js',
array( 'jquery', 'wp-color-picker' ),
MEMBERFUL_VERSION,
true
);

wp_localize_script(
'memberful-paywall-builder',
'memberfulPaywallPreview',
Memberful_Paywall_Preview::script_args()
);
}

wp_enqueue_script(
'memberful-menu',
plugins_url( 'js/src/menu.js', dirname( __FILE__ ) ),
Expand Down Expand Up @@ -691,8 +719,17 @@ function memberful_wp_global_marketing() {
if ( isset( $_POST['memberful_use_global_marketing'] ) ) {
update_option( 'memberful_use_global_marketing', true );
update_option( 'memberful_global_marketing_override', filter_input( INPUT_POST, 'memberful_global_marketing_override', FILTER_SANITIZE_NUMBER_INT ) );
update_option( 'memberful_global_marketing_content', memberful_wp_kses_post( filter_input( INPUT_POST, 'memberful_global_marketing_content' ) ) );
update_option( 'memberful_use_global_snippets', (int) isset($_POST['memberful_use_global_snippets']));
update_option( 'memberful_use_global_snippets', (int) isset( $_POST['memberful_use_global_snippets'] ) );

$paywall_input = filter_input( INPUT_POST, 'memberful_paywall', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
if ( is_array( $paywall_input ) && ! empty( $paywall_input ) ) {
Memberful_Paywall_Config::save( $paywall_input );
}

$config_mode = ( is_array( $paywall_input ) && isset( $paywall_input['mode'] ) && in_array( $paywall_input['mode'], Memberful_Paywall_Config::MODES, true ) ) ? $paywall_input['mode'] : 'builder';
if ( 'custom_html' === $config_mode ) {
update_option( 'memberful_global_marketing_content', memberful_wp_kses_post( (string) filter_input( INPUT_POST, 'memberful_global_marketing_content' ) ) );
}
} else {
update_option( 'memberful_use_global_marketing', false );
}
Expand All @@ -706,11 +743,12 @@ function memberful_wp_global_marketing() {
memberful_wp_render(
'global_marketing',
array(
'use_global_marketing' => $use_global_marketing,
'use_global_snippets' => $use_global_snippets,
'global_marketing_content' => $global_marketing_content,
'use_global_marketing' => $use_global_marketing,
'use_global_snippets' => $use_global_snippets,
'global_marketing_content' => $global_marketing_content,
'global_marketing_override' => $global_marketing_override,
'form_target' => memberful_wp_plugin_global_marketing_url()
'paywall_config' => Memberful_Paywall_Config::get(),
'form_target' => memberful_wp_plugin_global_marketing_url(),
)
);
}
Expand Down
27 changes: 21 additions & 6 deletions wordpress/wp-content/plugins/memberful-wp/src/global_marketing.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,33 @@
*/
function memberful_get_global_replacement($marketing_content){
$override = get_option( 'memberful_global_marketing_override' );
$global_marketing_content = get_option( 'memberful_global_marketing_content' );

if($override) {
return $global_marketing_content;
if ( $override ) {
return memberful_wp_resolve_global_marketing_content();
}

if(empty(trim($marketing_content))){
return $global_marketing_content;
if ( empty( trim( $marketing_content ) ) ) {
return memberful_wp_resolve_global_marketing_content();
}

return $marketing_content;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

/**
* Resolve the global marketing HTML from whichever source the paywall config points to.
*
* @return string
*/
function memberful_wp_resolve_global_marketing_content(): string {
$config = Memberful_Paywall_Config::get();

if ( 'builder' === $config['mode'] ) {
return Memberful_Paywall_Renderer::render( $config );
}

return (string) get_option( 'memberful_global_marketing_content' );
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

/**
* Filter the paywall to return a "teaser".
*
Expand Down Expand Up @@ -83,7 +97,8 @@ function memberful_apply_global_snippets_content_filter( $memberful_marketing_co
}
}

$wrapped_teaser = "<div class='memberful-global-teaser-content'>$teaser</div>";
$teaser_class = apply_filters( 'memberful_global_teaser_class', 'memberful-global-teaser-content' );
$wrapped_teaser = "<div class='" . esc_attr( $teaser_class ) . "'>$teaser</div>";

if ( $has_teaser && ! did_filter( 'memberful_teaser_css' ) ) {
$wrapped_teaser .= apply_filters( 'memberful_teaser_css', memberful_get_teaser_css() );
Expand Down
7 changes: 7 additions & 0 deletions wordpress/wp-content/plugins/memberful-wp/src/metabox.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ function memberful_wp_metabox_types() {
return apply_filters( 'memberful_metabox_post_types', $types );
}

function memberful_global_marketing_overrides_post_content() {
return get_option( 'memberful_use_global_marketing' )
&& get_option( 'memberful_global_marketing_override' );
}

function memberful_wp_add_metabox() {
if ( ! get_option('memberful_site', FALSE) )
return;
Expand Down Expand Up @@ -54,6 +59,7 @@ function memberful_wp_metabox( $post ) {
$view_vars['marketing_content'] = reset($marketing_content);
$view_vars['viewable_by_any_registered_users'] = memberful_wp_get_post_available_to_any_registered_users( $post->ID );
$view_vars['viewable_by_anybody_subscribed_to_a_plan'] = memberful_wp_get_post_available_to_anybody_subscribed_to_a_plan( $post->ID );
$view_vars['global_marketing_overrides_post_content'] = memberful_global_marketing_overrides_post_content();

memberful_wp_render( 'metabox', $view_vars );
}
Expand Down Expand Up @@ -154,6 +160,7 @@ function memberful_wp_add_term_metabox( $term ) {
$view_vars['marketing_content'] = reset($marketing_content);
$view_vars['viewable_by_any_registered_users'] = memberful_wp_is_term_available_to_any_registered_users( $term->term_id );
$view_vars['viewable_by_anybody_subscribed_to_a_plan'] = memberful_wp_is_term_available_to_anybody_subscribed_to_a_plan( $term->term_id );
$view_vars['global_marketing_overrides_post_content'] = memberful_global_marketing_overrides_post_content();

memberful_wp_render( 'metabox', $view_vars );
}
Expand Down
Loading