Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/wp-user-frontend/admin/html/form-settings-payment.php
+++ b/wp-user-frontend/admin/html/form-settings-payment.php
@@ -57,7 +57,7 @@
<th>— — <?php esc_html_e( 'Fallback cost', 'wp-user-frontend' ); ?></th>
<td>
<label>
- <input type="number" name="wpuf_settings[fallback_ppp_cost]" value="<?php echo esc_attr( $fallback_ppp_cost ); ?>" />
+ <input type="number" step="0.01" min="0" name="wpuf_settings[fallback_ppp_cost]" value="<?php echo esc_attr( $fallback_ppp_cost ); ?>" />
</label>
<p class="description"><?php esc_html_e( 'Cost of pay per post after a subscription pack limit is reached.', 'wp-user-frontend' ); ?></p>
</td>
@@ -79,7 +79,7 @@
<th>— — <?php esc_html_e( 'Cost Settings', 'wp-user-frontend' ); ?></th>
<td>
<label>
- <input type="number" name="wpuf_settings[pay_per_post_cost]" value="<?php echo esc_attr( $pay_per_post_cost ); ?>" />
+ <input type="number" step="0.01" min="0" name="wpuf_settings[pay_per_post_cost]" value="<?php echo esc_attr( $pay_per_post_cost ); ?>" />
</label>
<p class="description"><?php esc_html_e( 'Amount to be charged per post', 'wp-user-frontend' ); ?></p>
</td>
--- a/wp-user-frontend/class/render-form.php
+++ b/wp-user-frontend/class/render-form.php
@@ -228,10 +228,11 @@
foreach ( $meta_vars as $key => $value ) {
$value_name = isset( $_POST[$value['name']] ) ? sanitize_text_field( wp_unslash( $_POST[$value['name']] ) ) : '';
if ( isset( $_POST['wpuf_files'][$value['name']] ) ) {
- $wpuf_files = isset( $_POST['wpuf_files'] ) ? sanitize_text_field( wp_unslash( $_POST['wpuf_files'][$value['name']] ) ) : [];
- } else {
- $wpuf_files = [];
- }
+ $raw_files = wp_unslash( $_POST['wpuf_files'][$value['name']] );
+ $wpuf_files = absint( $raw_files );
+ } else {
+ $wpuf_files = [];
+ }
switch ( $value['input_type'] ) {
// put files in a separate array, we'll process it later
--- a/wp-user-frontend/class/subscription.php
+++ b/wp-user-frontend/class/subscription.php
@@ -648,6 +648,11 @@
* @return string
*/
public function post_redirect( $response, $post_id, $form_id, $form_settings ) {
+ // Admin users bypass payment redirect
+ if ( current_user_can( wpuf_admin_role() ) ) {
+ return $response;
+ }
+
$form = new WPUF_Form( $form_id );
$payment_options = $form->is_charging_enabled();
$force_pack = $form->is_enabled_force_pack();
@@ -1053,7 +1058,10 @@
$price_with_tax = wpuf_prices_include_tax();
}
- if ( self::has_user_error( $form_settings ) || ( $payment_enabled && $pay_per_post && ! $force_pack ) ) {
+ if (
+ ( self::has_user_error( $form_settings ) && ! ( $force_pack && $form->is_enabled_fallback_cost() ) )
+ || ( $payment_enabled && $pay_per_post && ! $force_pack )
+ ) {
?>
<div class="wpuf-info">
<?php
@@ -1070,12 +1078,11 @@
?>
</div>
<?php
- } elseif ( self::has_user_error( $form_settings ) || ( $payment_enabled && $force_pack && ! is_wp_error( $current_pack ) && ! $current_user->subscription()->has_post_count( $form_settings['post_type'] ) ) ) {
+ } elseif ( $payment_enabled && $force_pack && $form->is_enabled_fallback_cost() && ! is_wp_error( $current_pack ) && ! $current_user->subscription()->has_post_count( $form_settings['post_type'] ) ) {
?>
<div class="wpuf-info">
<?php
- $form = new WPUF_Form( $form_id );
- $fallback_cost = (int) $form->get_subs_fallback_cost();
+ $fallback_cost = (float) $form->get_subs_fallback_cost();
if ( isset( $price_with_tax ) && $price_with_tax ) {
$fallback_cost = apply_filters( 'wpuf_payment_amount', $fallback_cost );
@@ -1120,9 +1127,20 @@
}
public function force_pack_notice( $text, $id, $form_settings ) {
+ // Admin users don't need subscription notices
+ if ( current_user_can( wpuf_admin_role() ) ) {
+ return $text;
+ }
+
$form = new WPUF_Form( $id );
- $force_pack = $form->is_enabled_force_pack();
+ $force_pack = $form->is_enabled_force_pack();
+ $fallback_enabled = $form->is_enabled_fallback_cost();
+
+ // When fallback pay-per-post is enabled, don't show "purchase a pack" notice
+ if ( $force_pack && $fallback_enabled ) {
+ return $text;
+ }
if ( $force_pack && self::has_user_error( $form_settings ) ) {
$pack_page = get_permalink( wpuf_get_option( 'subscription_page', 'wpuf_payment' ) );
@@ -1144,6 +1162,18 @@
$current_pack = $current_user->subscription()->current_pack();
$has_post_count = isset( $form_settings['post_type'] ) ? $current_user->subscription()->has_post_count( $form_settings['post_type'] ) : false;
+ if ( current_user_can( wpuf_admin_role() ) ) {
+ return 'yes';
+ }
+
+ // When force_pack + fallback pay-per-post is enabled, skip this early return
+ // so the downstream fallback logic can allow the user to post with per-post payment.
+ $skip_limit_block = $force_pack && $fallback_enabled;
+
+ if ( $current_user->subscription()->current_pack_id() && ! $has_post_count && ! $skip_limit_block ) {
+ return 'no';
+ }
+
if ( is_user_logged_in() ) {
if ( wpuf_get_user()->post_locked() ) {
return 'no';
@@ -1158,14 +1188,14 @@
if ( ! is_wp_error( $current_pack ) ) {
// current pack has no error
if ( ! $fallback_enabled ) {
- //fallback cost enabled
+ // fallback cost disabled
if ( ! $current_user->subscription()->current_pack_id() ) {
return 'no';
} elseif ( $current_user->subscription()->has_post_count( $form_settings['post_type'] ) ) {
return 'yes';
}
} elseif ( $fallback_enabled ) {
- //fallback cost disabled
+ // fallback cost enabled
if ( ! $current_user->subscription()->current_pack_id() ) {
return 'no';
} elseif ( $has_post_count ) {
@@ -1216,7 +1246,7 @@
// _deprecated_function( __FUNCTION__, '2.6.0', 'wpuf_get_user()->subscription()->has_error( $form_settings = null );' );
- wpuf_get_user()->subscription()->has_error( $form_settings );
+ return wpuf_get_user()->subscription()->has_error( $form_settings );
}
/**
--- a/wp-user-frontend/includes/Admin.php
+++ b/wp-user-frontend/includes/Admin.php
@@ -267,10 +267,7 @@
$localize_data
);
- // Debug: Output form type as HTML comment for verification
- add_action( 'admin_footer', function() use ( $form_type ) {
- echo "n<!-- WPUF AI Form Builder Debug: formType = " . esc_html( $form_type ) . " -->n";
- } );
+
}
/**
--- a/wp-user-frontend/includes/Admin/Admin_Installer.php
+++ b/wp-user-frontend/includes/Admin/Admin_Installer.php
@@ -21,33 +21,72 @@
*/
public function admin_notice() {
$page_created = get_option( '_wpuf_page_created' );
- if ( $page_created != '1' && 'off' == wpuf_get_option( 'install_wpuf_pages', 'wpuf_general', 'on' ) ) {
+ if ( '1' !== $page_created && 'off' === wpuf_get_option( 'install_wpuf_pages', 'wpuf_general', 'on' ) ) {
?>
<div class="updated error">
<p>
- <?php esc_html_e( 'If you have not created <strong>WP User Frontend</strong> pages yet, you can do this by one click.',
- 'wp-user-frontend' ); ?>
+ <?php
+ esc_html_e(
+ 'If you have not created <strong>WP User Frontend</strong> pages yet, you can do this by one click.',
+ 'wp-user-frontend'
+ );
+ ?>
</p>
<p class="submit">
<a class="button button-primary"
- href="<?php echo esc_url( add_query_arg( [ 'install_wpuf_pages' => true ],
- admin_url( 'admin.php?page=wpuf-settings' ) ) ); ?>"><?php esc_html_e( 'Install WPUF Pages',
- 'wp-user-frontend' ); ?></a>
+ href="
+ <?php
+ echo esc_url(
+ wp_nonce_url(
+ add_query_arg(
+ [ 'install_wpuf_pages' => '1' ],
+ admin_url( 'admin.php?page=wpuf-settings' )
+ ),
+ 'wpuf_install_pages'
+ )
+ );
+ ?>
+ ">
+ <?php
+ esc_html_e(
+ 'Install WPUF Pages',
+ 'wp-user-frontend'
+ );
+ ?>
+ </a>
<?php esc_html_e( 'or', 'wp-user-frontend' ); ?>
<a class="button"
- href="<?php echo esc_url( add_query_arg( [ 'wpuf_hide_page_nag' => true ] ) ); ?>"><?php esc_html_e( 'Skip Setup',
- 'wp-user-frontend' ); ?></a>
+ href="<?php echo esc_url( wp_nonce_url( add_query_arg( [ 'wpuf_hide_page_nag' => '1' ] ), 'wpuf_install_pages' ) ); ?>">
+ <?php
+ esc_html_e(
+ 'Skip Setup',
+ 'wp-user-frontend'
+ );
+ ?>
+ </a>
</p>
</div>
<?php
}
- if ( isset( $_GET['wpuf_page_installed'] ) && $_GET['wpuf_page_installed'] == '1' ) {
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
+ if ( isset( $_GET['wpuf_page_installed'] ) && '1' === $_GET['wpuf_page_installed'] ) {
?>
<div class="updated">
<p>
- <strong><?php esc_html_e( 'Congratulations!',
- 'wp-user-frontend' ); ?></strong> <?php echo wp_kses_post( 'Pages for <strong>WP User Frontend</strong> has been successfully installed and saved!',
- 'wp-user-frontend' ); ?>
+ <strong>
+ <?php
+ esc_html_e(
+ 'Congratulations!',
+ 'wp-user-frontend'
+ );
+ ?>
+ </strong>
+ <?php
+ echo wp_kses_post(
+ 'Pages for <strong>WP User Frontend</strong> has been successfully installed and saved!',
+ 'wp-user-frontend'
+ );
+ ?>
</p>
</div>
<?php
@@ -60,16 +99,24 @@
* @return void
*/
public function handle_request() {
- $nonce = isset( $_REQUEST['wpuf_steup'] ) ? sanitize_key( wp_unslash( $_REQUEST['wpuf_steup'] ) ) : '';
- if ( isset( $_POST['_wpnonce'] ) && wp_verify_nonce( 'wpuf_steup' ) ) {
+ if ( ! isset( $_GET['install_wpuf_pages'] ) && ! isset( $_GET['wpuf_hide_page_nag'] ) ) {
+ return;
+ }
+
+ if ( ! current_user_can( 'manage_options' ) ) {
+ return;
}
- if ( isset( $_GET['install_wpuf_pages'] ) && $_GET['install_wpuf_pages'] == '1' ) {
+
+ $nonce = isset( $_GET['_wpnonce'] ) ? sanitize_key( wp_unslash( $_GET['_wpnonce'] ) ) : '';
+ if ( ! wp_verify_nonce( $nonce, 'wpuf_install_pages' ) ) {
+ return;
+ }
+
+ if ( isset( $_GET['install_wpuf_pages'] ) && '1' === $_GET['install_wpuf_pages'] ) {
$this->init_pages();
}
- // if ( isset( $_POST['install_wpuf_pages'] ) && $_POST['install_wpuf_pages'] == '1' ) {
- // $this->init_pages();
- // }
- if ( isset( $_GET['wpuf_hide_page_nag'] ) && $_GET['wpuf_hide_page_nag'] == '1' ) {
+
+ if ( isset( $_GET['wpuf_hide_page_nag'] ) && '1' === $_GET['wpuf_hide_page_nag'] ) {
update_option( '_wpuf_page_created', '1' );
}
}
@@ -88,26 +135,40 @@
$edit_page = $this->create_page( __( 'Edit', 'wp-user-frontend' ), '[wpuf_edit]' );
// login page
$login_page = $this->create_page( __( 'Login', 'wp-user-frontend' ), '[wpuf-login]' );
- $post_form = $this->create_form();
- if ( 'on' == wpuf_get_option( 'enable_payment', 'wpuf_payment', 'on' ) ) {
+ $post_form = $this->create_form();
+ if ( 'on' === wpuf_get_option( 'enable_payment', 'wpuf_payment', 'on' ) ) {
// payment page
- $subscr_page = $this->create_page( __( 'Subscription', 'wp-user-frontend' ),
- __( '[wpuf_sub_pack]', 'wp-user-frontend' ) );
- $payment_page = $this->create_page( __( 'Payment', 'wp-user-frontend' ),
- __( 'Please select a gateway for payment', 'wp-user-frontend' ) );
- $thank_page = $this->create_page( __( 'Thank You', 'wp-user-frontend' ),
- __( '<h1>Payment is complete</h1><p>Congratulations, your payment has been completed!</p>',
- 'wp-user-frontend' ) );
- $bank_page = $this->create_page( __( 'Order Received', 'wp-user-frontend' ),
- __( 'Hi, we have received your order. We will validate the order and will take necessary steps to move forward.',
- 'wp-user-frontend' ) );
+ $subscr_page = $this->create_page(
+ __( 'Subscription', 'wp-user-frontend' ),
+ __( '[wpuf_sub_pack]', 'wp-user-frontend' )
+ );
+ $payment_page = $this->create_page(
+ __( 'Payment', 'wp-user-frontend' ),
+ __( 'Please select a gateway for payment', 'wp-user-frontend' )
+ );
+ $thank_page = $this->create_page(
+ __( 'Thank You', 'wp-user-frontend' ),
+ __(
+ '<h1>Payment is complete</h1><p>Congratulations, your payment has been completed!</p>',
+ 'wp-user-frontend'
+ )
+ );
+ $bank_page = $this->create_page(
+ __( 'Order Received', 'wp-user-frontend' ),
+ __(
+ 'Hi, we have received your order. We will validate the order and will take necessary steps to move forward.',
+ 'wp-user-frontend'
+ )
+ );
}
// save the settings
if ( $edit_page ) {
- update_option( 'wpuf_frontend_posting', [
- 'edit_page_id' => $edit_page,
- 'default_post_form' => $post_form,
- ] );
+ update_option(
+ 'wpuf_frontend_posting', [
+ 'edit_page_id' => $edit_page,
+ 'default_post_form' => $post_form,
+ ]
+ );
}
// profile pages
$profile_options = [];
@@ -128,23 +189,36 @@
$profile_options['register_link_override'] = 'on';
}
update_option( 'wpuf_profile', $profile_options );
- if ( 'on' == wpuf_get_option( 'enable_payment', 'wpuf_payment', 'on' ) ) {
+ if ( 'on' === wpuf_get_option( 'enable_payment', 'wpuf_payment', 'on' ) ) {
// payment pages
- update_option( 'wpuf_payment', [
- 'subscription_page' => $subscr_page,
- 'payment_page' => $payment_page,
- 'payment_success' => $thank_page,
- 'bank_success' => $bank_page,
- ] );
+ update_option(
+ 'wpuf_payment', [
+ 'subscription_page' => $subscr_page,
+ 'payment_page' => $payment_page,
+ 'payment_success' => $thank_page,
+ 'bank_success' => $bank_page,
+ ]
+ );
}
update_option( '_wpuf_page_created', '1' );
+ // User Directory page (Pro only): created when WPUF_User_Listing is available.
+ if ( class_exists( 'WPUF_User_Listing' ) ) {
+ $this->create_page(
+ __( 'User Directory', 'wp-user-frontend' ),
+ $this->get_user_directory_page_content()
+ );
+ }
+
// Auto-add logout link to the primary menu
$this->auto_add_logout_to_menu();
+ // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
- if ( $page != 'wpuf-setup' ) {
- wp_redirect( admin_url( 'admin.php?page=wpuf-settings&wpuf_page_installed=1' ) );
+
+ if ( 'wpuf-setup' !== $page ) {
+ wp_safe_redirect( admin_url( 'admin.php?page=wpuf-settings&wpuf_page_installed=1' ) );
+
exit;
}
}
@@ -238,11 +312,13 @@
*/
private function add_logout_to_fse_navigation() {
// Get all wp_navigation posts
- $navigations = get_posts( [
- 'post_type' => 'wp_navigation',
- 'posts_per_page' => -1,
- 'post_status' => 'publish',
- ] );
+ $navigations = get_posts(
+ [
+ 'post_type' => 'wp_navigation',
+ 'posts_per_page' => -1,
+ 'post_status' => 'publish',
+ ]
+ );
if ( empty( $navigations ) ) {
return false;
@@ -267,10 +343,12 @@
// Append logout link to the navigation content
$new_content = $navigation->post_content . "n" . $logout_block;
- wp_update_post( [
- 'ID' => $navigation->ID,
- 'post_content' => $new_content,
- ] );
+ wp_update_post(
+ [
+ 'ID' => $navigation->ID,
+ 'post_content' => $new_content,
+ ]
+ );
$updated = true;
}
@@ -279,6 +357,100 @@
}
/**
+ * Get the post content for the User Directory page.
+ *
+ * Returns the wpuf-ud/directory Gutenberg block markup for block themes and
+ * the [wpuf_user_listing] shortcode for classic themes. Wrapped in a filter
+ * so integrations can customize the generated content.
+ *
+ * @since 4.3.2
+ *
+ * @return string
+ */
+ public function get_user_directory_page_content() {
+ $is_block_theme = function_exists( 'wp_is_block_theme' ) && wp_is_block_theme();
+
+ if ( $is_block_theme ) {
+ $content = $this->get_user_directory_block_content();
+ } else {
+ $content = '[wpuf_user_listing]';
+ }
+
+ /**
+ * Filter the User Directory page content generated during page installation.
+ *
+ * @since 4.3.2
+ *
+ * @param string $content Rendered page content (block markup or shortcode).
+ * @param bool $is_block_theme Whether the active theme is a block (FSE) theme.
+ */
+ return apply_filters( 'wpuf_user_directory_page_content', $content, $is_block_theme );
+ }
+
+ /**
+ * Get the default Gutenberg block markup for the User Directory page.
+ *
+ * @since 4.3.2
+ *
+ * @return string
+ */
+ private function get_user_directory_block_content() {
+ return <<<'HTML'
+<!-- wp:wpuf-ud/directory {"directory_layout":"roundGrids","hasSelectedLayout":true,"selectedLayout":"roundGrids"} -->
+<div class="wp-block-wpuf-ud-directory"><!-- wp:wpuf-ud/directory-item -->
+<div class="wp-block-wpuf-ud-directory-item"><!-- wp:group {"className":"is-style-default","style":{"border":{"radius":"8px","color":"#d1d5db","width":"1px"},"spacing":{"margin":{"top":"0","bottom":"0"},"blockGap":"0","padding":{"top":"var:preset|spacing|30","bottom":"var:preset|spacing|30","left":"0","right":"0"}}},"layout":{"type":"flex","orientation":"vertical","justifyContent":"center"}} -->
+<div class="wp-block-group is-style-default has-border-color" style="border-color:#d1d5db;border-width:1px;border-radius:8px;margin-top:0;margin-bottom:0;padding-top:var(--wp--preset--spacing--30);padding-right:0;padding-bottom:var(--wp--preset--spacing--30);padding-left:0"><!-- wp:wpuf-ud/avatar {"avatarSize":"custom","fallbackType":"gravatar","customSize":128,"style":{"spacing":{"padding":{"bottom":"15px"},"margin":{"top":"3px"}}}} /-->
+
+<!-- wp:wpuf-ud/name {"style":{"color":"#0F172A","fontWeight":"bold","typography":{"fontStyle":"normal","fontWeight":"600","fontSize":"20px","lineHeight":"2"},"spacing":{"margin":{"bottom":"2px"}}}} /-->
+
+<!-- wp:wpuf-ud/contact {"showIcons":false,"iconSize":"small","showLabels":false,"className":"wpuf-user-contact-info wpuf-contact-layout-inline","style":{"color":{"text":"#64748B"},"typography":{"lineHeight":"1","textAlign":"center","fontSize":"14px"},"spacing":{"margin":{"bottom":"5px"}}}} /-->
+
+<!-- wp:wpuf-ud/social {"iconSize":"medium","style":{"spacing":{"padding":{"top":"5px","bottom":"5px"},"margin":{"top":"5px","bottom":"5px"}}}} /-->
+
+<!-- wp:wpuf-ud/profile-button {"textColor":"base","style":{"border":{"radius":"6px"},"spacing":{"padding":{"top":"9px","right":"17px","bottom":"9px","left":"17px"},"margin":{"top":"14px","bottom":"8px"}},"marginTop":"16px","typography":{"fontStyle":"normal","fontWeight":"400","fontSize":"14px"},"color":{"background":"#7c3aed"}}} /--></div>
+<!-- /wp:group --></div>
+<!-- /wp:wpuf-ud/directory-item --></div>
+<!-- /wp:wpuf-ud/directory -->
+
+<!-- wp:wpuf-ud/profile {"hasSelectedPattern":true} -->
+<div class="wp-block-wpuf-ud-profile wpuf-user-profile"><!-- wp:columns {"className":"wpuf-flex wpuf-flex-row wpuf-gap-8 wpuf-border wpuf-border-gray-200 wpuf-rounded-lg wpuf-p-8"} -->
+<div class="wp-block-columns wpuf-flex wpuf-flex-row wpuf-gap-8 wpuf-border wpuf-border-gray-200 wpuf-rounded-lg wpuf-p-8"><!-- wp:column {"width":"35%","className":"wpuf-profile-sidebar","style":{"border":{"style":"none","width":"0px"},"spacing":{"padding":{"right":"var:preset|spacing|40","top":"0","bottom":"0","left":"0"}}},"layout":{"type":"constrained","justifyContent":"left","contentSize":"75%"}} -->
+<div class="wp-block-column wpuf-profile-sidebar" style="border-style:none;border-width:0px;padding-top:0;padding-right:var(--wp--preset--spacing--40);padding-bottom:0;padding-left:0;flex-basis:35%"><!-- wp:wpuf-ud/avatar {"avatarSize":"custom","fallbackType":"gravatar","customSize":100,"style":{"spacing":{"margin":{"bottom":"10px"}}}} /-->
+
+<!-- wp:wpuf-ud/name {"nameFormat":"first_last","headingLevel":"h2","fontFamily":"manrope","style":{"typography":{"fontStyle":"normal","fontWeight":"700"}}} /-->
+
+<!-- wp:wpuf-ud/contact {"showFields":["email","website"],"layoutStyle":"vertical","showLabels":false,"iconColor":"#707070","style":{"typography":{"fontSize":"14px","lineHeight":"1.7"},"spacing":{"margin":{"bottom":"20px","top":"var:preset|spacing|20"}}}} /-->
+
+<!-- wp:heading {"level":4,"style":{"spacing":{"margin":{"top":"var:preset|spacing|40","right":"0"}},"color":{"text":"#707070"},"elements":{"link":{"color":{"text":"#707070"}}},"typography":{"fontStyle":"normal","fontWeight":"700"}},"fontSize":"small"} -->
+<h4 class="wp-block-heading has-text-color has-link-color has-small-font-size" style="color:#707070;margin-top:var(--wp--preset--spacing--40);margin-right:0;font-style:normal;font-weight:700">SOCIAL</h4>
+<!-- /wp:heading -->
+
+<!-- wp:wpuf-ud/social {"layoutStyle":"layout-2","style":{"spacing":{"margin":{"right":"0","top":"var:preset|spacing|20"},"padding":{"right":"var:preset|spacing|20","left":"0","top":"0"}}}} /-->
+
+<!-- wp:heading {"level":4,"style":{"spacing":{"margin":{"top":"var:preset|spacing|40"}},"color":{"text":"#707070"},"elements":{"link":{"color":{"text":"#707070"}}},"typography":{"fontStyle":"normal","fontWeight":"700"}},"fontSize":"small"} -->
+<h4 class="wp-block-heading has-text-color has-link-color has-small-font-size" style="color:#707070;margin-top:var(--wp--preset--spacing--40);font-style:normal;font-weight:700">BIO</h4>
+<!-- /wp:heading -->
+
+<!-- wp:wpuf-ud/bio {"characterLimit":100,"style":{"spacing":{"margin":{"top":"var:preset|spacing|20"},"padding":{"right":"0"}},"typography":{"fontSize":"14px"}}} /-->
+
+<!-- wp:wpuf-ud/unmatched-blocks /--></div>
+<!-- /wp:column -->
+
+<!-- wp:column {"width":"65%","className":"wpuf-profile-content","layout":{"type":"default"}} -->
+<div class="wp-block-column wpuf-profile-content" style="flex-basis:65%"><!-- wp:wpuf-ud/tabs {"style":{"spacing":{"margin":{"top":"100px"}}}} -->
+<div class="wpuf-user-tabs" data-about-content="[]"><!-- wp:heading {"level":4,"style":{"spacing":{"margin":{"top":"var:preset|spacing|40"}},"color":{"text":"#707070"},"elements":{"link":{"color":{"text":"#707070"}}},"typography":{"fontStyle":"normal","fontWeight":"700"}},"fontSize":"small"} -->
+<h4 class="wp-block-heading has-text-color has-link-color has-small-font-size" style="color:#707070;margin-top:var(--wp--preset--spacing--40);font-style:normal;font-weight:700">BIO</h4>
+<!-- /wp:heading -->
+
+<!-- wp:wpuf-ud/bio {"characterLimit":100,"style":{"spacing":{"margin":{"top":"var:preset|spacing|20"},"padding":{"right":"0"}},"typography":{"fontSize":"14px"}}} /--></div>
+<!-- /wp:wpuf-ud/tabs --></div>
+<!-- /wp:column --></div>
+<!-- /wp:columns --></div>
+<!-- /wp:wpuf-ud/profile -->
+HTML;
+ }
+
+ /**
* Create a page with title and content
*
* @param string $page_title
@@ -287,13 +459,15 @@
* @return false|int
*/
public function create_page( $page_title, $post_content = '', $post_type = 'page' ) {
- $page_id = wp_insert_post( [
- 'post_title' => $page_title,
- 'post_type' => $post_type,
- 'post_status' => 'publish',
- 'comment_status' => 'closed',
- 'post_content' => $post_content,
- ] );
+ $page_id = wp_insert_post(
+ [
+ 'post_title' => $page_title,
+ 'post_type' => $post_type,
+ 'post_status' => 'publish',
+ 'comment_status' => 'closed',
+ 'post_content' => $post_content,
+ ]
+ );
if ( $page_id && ! is_wp_error( $page_id ) ) {
return $page_id;
}
--- a/wp-user-frontend/includes/Admin/Admin_Tools.php
+++ b/wp-user-frontend/includes/Admin/Admin_Tools.php
@@ -364,7 +364,7 @@
<div class="inside">
<p><?php esc_html_e( 'Clicking this button will create required pages for the plugin. Note: It'll not delete/replace existing pages.', 'wp-user-frontend' ); ?></p>
- <a class="button button-primary" href="<?php echo esc_attr( add_query_arg( [ 'install_wpuf_pages' => true ] ) ); ?>"><?php esc_html_e( 'Install WPUF Pages', 'wp-user-frontend' ); ?></a>
+ <a class="button button-primary" href="<?php echo esc_url( wp_nonce_url( add_query_arg( [ 'install_wpuf_pages' => '1' ] ), 'wpuf_install_pages' ) ); ?>"><?php esc_html_e( 'Install WPUF Pages', 'wp-user-frontend' ); ?></a>
</div>
</div>
--- a/wp-user-frontend/includes/Admin/Forms/Form.php
+++ b/wp-user-frontend/includes/Admin/Forms/Form.php
@@ -106,13 +106,13 @@
/**
* Get pay per cost amount
*
- * @return int
+ * @return float
*/
public function get_pay_per_post_cost() {
$settings = $this->get_settings();
if ( isset( $settings['pay_per_post_cost'] ) && $settings['pay_per_post_cost'] > 0 ) {
- return $settings['pay_per_post_cost'];
+ return (float) $settings['pay_per_post_cost'];
}
return 0;
@@ -136,13 +136,13 @@
/**
* Get the fallback cost amount
*
- * @return int
+ * @return float
*/
public function get_subs_fallback_cost() {
$settings = $this->get_settings();
if ( isset( $settings['fallback_ppp_cost'] ) && $settings['fallback_ppp_cost'] > 0 ) {
- return $settings['fallback_ppp_cost'];
+ return (float) $settings['fallback_ppp_cost'];
}
return 0;
@@ -172,11 +172,21 @@
return [ $user_can_post, $info ];
}
+ // Admin users bypass all subscription and payment restrictions
+ if ( current_user_can( wpuf_admin_role() ) ) {
+ return [ 'yes', '' ];
+ }
+
$post_type = ! empty( $form_settings['post_type'] ) ? $form_settings['post_type'] : 'post';
$has_post_count = $current_user->subscription()->has_post_count( $post_type );
- if ( $current_user->subscription()->current_pack_id() && ! $has_post_count ) {
+ // skip the early return so the payment logic below can handle it
+ $skip_limit_block = $this->is_charging_enabled()
+ && $this->is_enabled_force_pack()
+ && $this->is_enabled_fallback_cost();
+
+ if ( $current_user->subscription()->current_pack_id() && ! $has_post_count && ! $skip_limit_block ) {
$user_can_post = 'no';
$info = __( 'Post Limit Exceeded for your purchased subscription pack.', 'wp-user-frontend' );
--- a/wp-user-frontend/includes/Admin/Forms/Post/Templates/Post_Form_Template_Guest_Post_Recurring.php
+++ b/wp-user-frontend/includes/Admin/Forms/Post/Templates/Post_Form_Template_Guest_Post_Recurring.php
@@ -0,0 +1,212 @@
+<?php
+
+namespace WeDevsWpufAdminFormsPostTemplates;
+
+use WeDevsWpufAdminFormsForm_Template;
+
+/**
+ * Guest post submission form with mandatory recurring subscription
+ *
+ * @since 4.3.2
+ */
+class Post_Form_Template_Guest_Post_Recurring extends Form_Template {
+
+ public function __construct() {
+ parent::__construct();
+
+ $this->enabled = true;
+ $this->title = __( 'Guest Post (Recurring Subscription)', 'wp-user-frontend' );
+ $this->description = __( 'Accept guest post submissions with a mandatory recurring subscription. Collects title, content, excerpt, featured image, category, and tags.', 'wp-user-frontend' );
+ $this->image = WPUF_ASSET_URI . '/images/templates/guest-post-recurring.svg';
+
+ $this->form_fields = [
+ [
+ 'input_type' => 'text',
+ 'template' => 'post_title',
+ 'required' => 'yes',
+ 'label' => __( 'Post Title', 'wp-user-frontend' ),
+ 'name' => 'post_title',
+ 'is_meta' => 'no',
+ 'help' => __( 'Choose a compelling and descriptive title for your guest post.', 'wp-user-frontend' ),
+ 'css' => '',
+ 'placeholder' => __( 'Enter your article title here', 'wp-user-frontend' ),
+ 'default' => '',
+ 'size' => '40',
+ 'wpuf_cond' => $this->conditionals,
+ 'wpuf_visibility' => $this->get_default_visibility_prop(),
+ 'restriction_to' => 'max',
+ 'restriction_type' => 'character',
+ 'width' => 'large',
+ ],
+ [
+ 'input_type' => 'textarea',
+ 'template' => 'post_content',
+ 'required' => 'yes',
+ 'label' => __( 'Post Content', 'wp-user-frontend' ),
+ 'name' => 'post_content',
+ 'is_meta' => 'no',
+ 'help' => __( 'Provide the full content of your guest post. Ensure it's well-written and relevant.', 'wp-user-frontend' ),
+ 'css' => '',
+ 'rows' => '5',
+ 'cols' => '25',
+ 'placeholder' => __( 'Write your article content here', 'wp-user-frontend' ),
+ 'default' => '',
+ 'rich' => 'yes',
+ 'insert_image' => 'yes',
+ 'wpuf_cond' => $this->conditionals,
+ 'wpuf_visibility' => $this->get_default_visibility_prop(),
+ 'restriction_to' => 'max',
+ 'restriction_type' => 'character',
+ 'text_editor_control' => [],
+ 'width' => 'large',
+ ],
+ [
+ 'input_type' => 'textarea',
+ 'template' => 'post_excerpt',
+ 'required' => 'no',
+ 'label' => __( 'Post Excerpt', 'wp-user-frontend' ),
+ 'name' => 'post_excerpt',
+ 'is_meta' => 'no',
+ 'help' => __( 'A short summary of your post, usually displayed on archive pages. Keep it concise.', 'wp-user-frontend' ),
+ 'css' => '',
+ 'rows' => '5',
+ 'cols' => '25',
+ 'placeholder' => __( 'Enter a brief summary here', 'wp-user-frontend' ),
+ 'default' => '',
+ 'rich' => 'no',
+ 'wpuf_cond' => $this->conditionals,
+ 'wpuf_visibility' => $this->get_default_visibility_prop(),
+ 'restriction_to' => 'max',
+ 'restriction_type' => 'character',
+ 'text_editor_control' => [],
+ 'width' => 'large',
+ ],
+ [
+ 'input_type' => 'image_upload',
+ 'template' => 'featured_image',
+ 'count' => '1',
+ 'required' => 'yes',
+ 'label' => __( 'Featured Image', 'wp-user-frontend' ),
+ 'button_label' => __( 'Featured Image', 'wp-user-frontend' ),
+ 'name' => 'featured_image',
+ 'is_meta' => 'no',
+ 'help' => __( 'Select an image that best represents your article. This will be the main image for your post.', 'wp-user-frontend' ),
+ 'css' => '',
+ 'max_size' => '1024',
+ 'wpuf_cond' => $this->conditionals,
+ 'wpuf_visibility' => $this->get_default_visibility_prop(),
+ 'width' => 'large',
+ ],
+ [
+ 'input_type' => 'taxonomy',
+ 'template' => 'taxonomy',
+ 'required' => 'yes',
+ 'label' => __( 'Category', 'wp-user-frontend' ),
+ 'name' => 'category',
+ 'is_meta' => 'no',
+ 'help' => __( 'Choose the most relevant category for your guest post.', 'wp-user-frontend' ),
+ 'first' => __( 'Select a category', 'wp-user-frontend' ),
+ 'css' => '',
+ 'type' => 'select',
+ 'orderby' => 'name',
+ 'order' => 'ASC',
+ 'exclude_type' => 'exclude',
+ 'exclude' => [],
+ 'woo_attr' => 'no',
+ 'woo_attr_vis' => 'no',
+ 'options' => [],
+ 'wpuf_cond' => $this->conditionals,
+ 'wpuf_visibility' => $this->get_default_visibility_prop(),
+ 'width' => 'large',
+ 'show_inline' => false,
+ ],
+ [
+ 'input_type' => 'text',
+ 'template' => 'post_tags',
+ 'required' => 'no',
+ 'label' => __( 'Tags', 'wp-user-frontend' ),
+ 'name' => 'tags',
+ 'is_meta' => 'no',
+ 'help' => __( 'Add relevant keywords or phrases that describe your post.', 'wp-user-frontend' ),
+ 'css' => '',
+ 'placeholder' => __( 'Enter tags (comma-separated)', 'wp-user-frontend' ),
+ 'default' => '',
+ 'size' => '40',
+ 'wpuf_cond' => $this->conditionals,
+ 'wpuf_visibility' => $this->get_default_visibility_prop(),
+ 'width' => 'large',
+ ],
+ ];
+
+ $this->form_settings = [
+ 'post_type' => 'post',
+ 'post_status' => 'draft',
+ 'default_cat' => '-1',
+ 'post_permission' => 'guest_post',
+ 'guest_post' => 'true',
+ 'guest_details' => 'on',
+ 'name_label' => __( 'Name', 'wp-user-frontend' ),
+ 'email_label' => __( 'E-Mail', 'wp-user-frontend' ),
+ 'guest_email_verify' => 'on',
+ 'message_restrict' => __( 'This page is restricted. Please {login} / {register} to view this page.', 'wp-user-frontend' ),
+ 'redirect_to' => 'post',
+ 'comment_status' => 'open',
+ 'show_form_title' => 'true',
+ 'form_description' => __( 'Submit your guest post (this submission is under your active subscription plan). Include your article content, tags, excerpt, and featured image.', 'wp-user-frontend' ),
+ 'submit_text' => __( 'Submit Guest Post', 'wp-user-frontend' ),
+ 'submit_button_cond' => [
+ 'condition_status' => 'no',
+ 'cond_logic' => 'any',
+ 'conditions' => [
+ [
+ 'name' => '',
+ 'operator' => '=',
+ 'option' => '',
+ ],
+ ],
+ ],
+ 'draft_post' => 'true',
+ 'edit_post_status' => 'draft',
+ 'edit_redirect_to' => 'same',
+ 'update_message' => __( 'Post has been updated successfully. <a target="_blank" href="{link}">View post</a>', 'wp-user-frontend' ),
+ 'edit_url' => '',
+ 'update_text' => __( 'Update Post', 'wp-user-frontend' ),
+ 'payment_options' => 'true',
+ 'choose_payment_option' => 'force_pack_purchase',
+ 'force_pack_purchase' => 'true',
+ 'enable_pay_per_post' => 'false',
+ 'fallback_ppp_enable' => 'true',
+ 'use_theme_css' => 'wpuf-style',
+ 'form_layout' => 'layout1',
+ 'form_template' => 'post_form_template_guest_post_recurring',
+ 'notification' => [
+ 'new' => 'on',
+ 'new_to' => get_option( 'admin_email' ),
+ 'new_subject' => 'New guest post submission (subscription)',
+ 'new_body' => 'Hi,
+A new guest post has been submitted to your site {sitename} ({siteurl}).
+
+Here are the details:
+Post Title: CVE-2026-5459: User Frontend: AI Powered Frontend Posting, User Directory, Profile, Membership & User Registration <= 4.3.1 Unauthenticated Insecure Direct Object Reference to Arbitrary User Subscription Overwrite PoC, Patch Analysis & Rule
+Description: Atomic Edge analysis of CVE-2026-5459:
This vulnerability allows unauthenticated attackers to overwrite any user’s active subscription with a free subscription pack via an Insecure Direct Object Reference (IDOR) in the User Frontend plugin. The flaw exists in the payment_page() function within the subscription handling code. The CVSS score is 5.3 (Medium), indicating a moderate severity due to the requirement of a free subscription pack existing on the site.
The root cause is missing authorization validation on the ‘user_id’ parameter in the payment processing flow. The payment_page() function (defined in wp-user-frontend/class/subscription.php) accepts a ‘user_id’ from the user-controlled request but fails to verify that the authenticated user (or unauthenticated visitor) has permission to modify the target user’s subscription. Specifically, the function calls wpuf_get_user($user_id)->subscription()->add_pack() without checking if the requesting user is the same as the target user or has administrative privileges. Additionally, the post_redirect() method (line 648) and other subscription functions lacked admin user checks in the vulnerable version, which have been added in the patch.
Exploitation requires a site that has at least one free subscription pack (with price=0). An attacker sends a POST request to the payment endpoint (typically /wp-admin/admin-ajax.php with action ‘wpuf_payment’ or a direct form submission) including a ‘pack_id’ parameter pointing to a free subscription pack and a ‘user_id’ parameter set to the numeric ID of a target user. The attacker does not need authentication. For example, an attacker can send: POST /wp-admin/admin-ajax.php with action=wpuf_payment, pack_id=, user_id=. The plugin will process the request and overwrite the target user’s existing paid subscription with the free pack, causing the user to lose premium features.
The patch introduces multiple authorization checks. In wp-user-frontend/class/subscription.php: (1) post_redirect() now returns early if the user has admin role (line 651); (2) force_pack_notice() similarly bypasses for admin users (line 1130); (3) a new has_post_count check (line 1170) ensures that falling back to per-post payment only applies when the user has remaining posts in their current pack; (4) the method has_user_error() now returns the result of has_error() instead of calling it without returning (line 1249). The patch also corrects variable types (float vs int) and adds nonce verification to the admin page installer.
The impact is financial loss and service degradation for site users who have paid for premium subscriptions. An attacker can forcibly downgrade any user (including administrators, editors, or paying customers) to a free subscription tier, stripping them of paid features such as unlimited posting, custom fields, or priority support. This undermines the site’s subscription business model and can damage user trust. The vulnerability does not allow data theft or code execution, but it directly subverts the payment and subscription system.
+Short Description: Medium CVE-2026-5459 in Wp User Frontend (CVSS 5.3): User Frontend: AI Powered Frontend Posting, User Directory, Profile, Membership & User Registration. Atomic Edge summarizes impact, exploitability, and patch details, with WAF rule...
+Author: {author}
+Post URL: {permalink}
+Edit URL: {editlink}',
+ 'edit' => 'on',
+ 'edit_to' => get_option( 'admin_email' ),
+ 'edit_subject' => 'Guest post has been updated',
+ 'edit_body' => 'Hi,
+The guest post "CVE-2026-5459: User Frontend: AI Powered Frontend Posting, User Directory, Profile, Membership & User Registration <= 4.3.1 Unauthenticated Insecure Direct Object Reference to Arbitrary User Subscription Overwrite PoC, Patch Analysis & Rule" has been updated.
+
+Here are the details:
+Post Title: CVE-2026-5459: User Frontend: AI Powered Frontend Posting, User Directory, Profile, Membership & User Registration <= 4.3.1 Unauthenticated Insecure Direct Object Reference to Arbitrary User Subscription Overwrite PoC, Patch Analysis & Rule
+Description: Atomic Edge analysis of CVE-2026-5459:
This vulnerability allows unauthenticated attackers to overwrite any user’s active subscription with a free subscription pack via an Insecure Direct Object Reference (IDOR) in the User Frontend plugin. The flaw exists in the payment_page() function within the subscription handling code. The CVSS score is 5.3 (Medium), indicating a moderate severity due to the requirement of a free subscription pack existing on the site.
The root cause is missing authorization validation on the ‘user_id’ parameter in the payment processing flow. The payment_page() function (defined in wp-user-frontend/class/subscription.php) accepts a ‘user_id’ from the user-controlled request but fails to verify that the authenticated user (or unauthenticated visitor) has permission to modify the target user’s subscription. Specifically, the function calls wpuf_get_user($user_id)->subscription()->add_pack() without checking if the requesting user is the same as the target user or has administrative privileges. Additionally, the post_redirect() method (line 648) and other subscription functions lacked admin user checks in the vulnerable version, which have been added in the patch.
Exploitation requires a site that has at least one free subscription pack (with price=0). An attacker sends a POST request to the payment endpoint (typically /wp-admin/admin-ajax.php with action ‘wpuf_payment’ or a direct form submission) including a ‘pack_id’ parameter pointing to a free subscription pack and a ‘user_id’ parameter set to the numeric ID of a target user. The attacker does not need authentication. For example, an attacker can send: POST /wp-admin/admin-ajax.php with action=wpuf_payment, pack_id=, user_id=. The plugin will process the request and overwrite the target user’s existing paid subscription with the free pack, causing the user to lose premium features.
The patch introduces multiple authorization checks. In wp-user-frontend/class/subscription.php: (1) post_redirect() now returns early if the user has admin role (line 651); (2) force_pack_notice() similarly bypasses for admin users (line 1130); (3) a new has_post_count check (line 1170) ensures that falling back to per-post payment only applies when the user has remaining posts in their current pack; (4) the method has_user_error() now returns the result of has_error() instead of calling it without returning (line 1249). The patch also corrects variable types (float vs int) and adds nonce verification to the admin page installer.
The impact is financial loss and service degradation for site users who have paid for premium subscriptions. An attacker can forcibly downgrade any user (including administrators, editors, or paying customers) to a free subscription tier, stripping them of paid features such as unlimited posting, custom fields, or priority support. This undermines the site’s subscription business model and can damage user trust. The vulnerability does not allow data theft or code execution, but it directly subverts the payment and subscription system.
+Short Description: Medium CVE-2026-5459 in Wp User Frontend (CVSS 5.3): User Frontend: AI Powered Frontend Posting, User Directory, Profile, Membership & User Registration. Atomic Edge summarizes impact, exploitability, and patch details, with WAF rule...
+Author: {author}
+Post URL: {permalink}
+Edit URL: {editlink}',
+ ],
+ ];
+ }
+}
--- a/wp-user-frontend/includes/Admin/Forms/Post/Templates/Post_Form_Template_Paid_Guest_Post.php
+++ b/wp-user-frontend/includes/Admin/Forms/Post/Templates/Post_Form_Template_Paid_Guest_Post.php
@@ -0,0 +1,213 @@
+enabled = true;
+ $this->title = __( 'Paid Guest Post', 'wp-user-frontend' );
+ $this->description = __( 'Accept guest post submissions with one-time payment. Collects title, content, excerpt, featured image, category, and tags.', 'wp-user-frontend' );
+ $this->image = WPUF_ASSET_URI . '/images/templates/paid-guest-post.svg';
+
+ $this->form_fields = [
+ [
+ 'input_type' => 'text',
+ 'template' => 'post_title',
+ 'required' => 'yes',
+ 'label' => __( 'Post Title', 'wp-user-frontend' ),
+ 'name' => 'post_title',
+ 'is_meta' => 'no',
+ 'help' => __( 'Choose a compelling and descriptive title for your guest post.', 'wp-user-frontend' ),
+ 'css' => '',
+ 'placeholder' => __( 'Enter your article title here', 'wp-user-frontend' ),
+ 'default' => '',
+ 'size' => '40',
+ 'wpuf_cond' => $this->conditionals,
+ 'wpuf_visibility' => $this->get_default_visibility_prop(),
+ 'restriction_to' => 'max',
+ 'restriction_type' => 'character',
+ 'width' => 'large',
+ ],
+ [
+ 'input_type' => 'textarea',
+ 'template' => 'post_content',
+ 'required' => 'yes',
+ 'label' => __( 'Post Content', 'wp-user-frontend' ),
+ 'name' => 'post_content',
+ 'is_meta' => 'no',
+ 'help' => __( 'Provide the full content of your guest post. Ensure it's well-written and relevant.', 'wp-user-frontend' ),
+ 'css' => '',
+ 'rows' => '5',
+ 'cols' => '25',
+ 'placeholder' => __( 'Write your article content here', 'wp-user-frontend' ),
+ 'default' => '',
+ 'rich' => 'yes',
+ 'insert_image' => 'yes',
+ 'wpuf_cond' => $this->conditionals,
+ 'wpuf_visibility' => $this->get_default_visibility_prop(),
+ 'restriction_to' => 'max',
+ 'restriction_type' => 'character',
+ 'text_editor_control' => [],
+ 'width' => 'large',
+ ],
+ [
+ 'input_type' => 'textarea',
+ 'template' => 'post_excerpt',
+ 'required' => 'no',
+ 'label' => __( 'Post Excerpt', 'wp-user-frontend' ),
+ 'name' => 'post_excerpt',
+ 'is_meta' => 'no',
+ 'help' => __( 'A short summary of your post, usually displayed on archive pages. Keep it concise.', 'wp-user-frontend' ),
+ 'css' => '',
+ 'rows' => '5',
+ 'cols' => '25',
+ 'placeholder' => __( 'Enter a brief summary here', 'wp-user-frontend' ),
+ 'default' => '',
+ 'rich' => 'no',
+ 'wpuf_cond' => $this->conditionals,
+ 'wpuf_visibility' => $this->get_default_visibility_prop(),
+ 'restriction_to' => 'max',
+ 'restriction_type' => 'character',
+ 'text_editor_control' => [],
+ 'width' => 'large',
+ ],
+ [
+ 'input_type' => 'image_upload',
+ 'template' => 'featured_image',
+ 'count' => '1',
+ 'required' => 'yes',
+ 'label' => __( 'Featured Image', 'wp-user-frontend' ),
+ 'button_label' => __( 'Featured Image', 'wp-user-frontend' ),
+ 'name' => 'featured_image',
+ 'is_meta' => 'no',
+ 'help' => __( 'Select an image that best represents your article. This will be the main image for your post.', 'wp-user-frontend' ),
+ 'css' => '',
+ 'max_size' => '1024',
+ 'wpuf_cond' => $this->conditionals,
+ 'wpuf_visibility' => $this->get_default_visibility_prop(),
+ 'width' => 'large',
+ ],
+ [
+ 'input_type' => 'taxonomy',
+ 'template' => 'taxonomy',
+ 'required' => 'yes',
+ 'label' => __( 'Category', 'wp-user-frontend' ),
+ 'name' => 'category',
+ 'is_meta' => 'no',
+ 'help' => __( 'Choose the most relevant category for your guest post.', 'wp-user-frontend' ),
+ 'first' => __( 'Select a category', 'wp-user-frontend' ),
+ 'css' => '',
+ 'type' => 'select',
+ 'orderby' => 'name',
+ 'order' => 'ASC',
+ 'exclude_type' => 'exclude',
+ 'exclude' => [],
+ 'woo_attr' => 'no',
+ 'woo_attr_vis' => 'no',
+ 'options' => [],
+ 'wpuf_cond' => $this->conditionals,
+ 'wpuf_visibility' => $this->get_default_visibility_prop(),
+ 'width' => 'large',
+ 'show_inline' => false,
+ ],
+ [
+ 'input_type' => 'text',
+ 'template' => 'post_tags',
+ 'required' => 'no',
+ 'label' => __( 'Tags', 'wp-user-frontend' ),
+ 'name' => 'tags',
+ 'is_meta' => 'no',
+ 'help' => __( 'Add relevant keywords or phrases that describe your post.', 'wp-user-frontend' ),
+ 'css' => '',
+ 'placeholder' => __( 'Enter tags (comma-separated)', 'wp-user-frontend' ),
+ 'default' => '',
+ 'size' => '40',
+ 'wpuf_cond' => $this->conditionals,
+ 'wpuf_visibility' => $this->get_default_visibility_prop(),
+ 'width' => 'large',
+ ],
+ ];
+
+ $this->form_settings = [
+ 'post_type' => 'post',
+ 'post_status' => 'draft',
+ 'default_cat' => '-1',
+ 'post_permission' => 'guest_post',
+ 'guest_post' => 'true',
+ 'guest_details' => 'on',
+ 'name_label' => __( 'Name', 'wp-user-frontend' ),
+ 'email_label' => __( 'E-Mail', 'wp-user-frontend' ),
+ 'guest_email_verify' => 'on',
+ 'message_restrict' => __( 'This page is restricted. Please {login} / {register} to view this page.', 'wp-user-frontend' ),
+ 'redirect_to' => 'post',
+ 'comment_status' => 'closed',
+ 'show_form_title' => 'true',
+ 'form_description' => __( 'Submit your guest article with a one-time payment. Include your title, content, excerpt, tags, and featured image.', 'wp-user-frontend' ),
+ 'submit_text' => __( 'Submit Guest Post', 'wp-user-frontend' ),
+ 'submit_button_cond' => [
+ 'condition_status' => 'no',
+ 'cond_logic' => 'any',
+ 'conditions' => [
+ [
+ 'name' => '',
+ 'operator' => '=',
+ 'option' => '',
+ ],
+ ],
+ ],
+ 'draft_post' => 'true',
+ 'edit_post_status' => 'draft',
+ 'edit_redirect_to' => 'same',
+ 'update_message' => __( 'Post has been updated successfully. View post', 'wp-user-frontend' ),
+ 'edit_url' => '',
+ 'update_text' => __( 'Update Post', 'wp-user-frontend' ),
+ 'payment_options' => 'true',
+ 'choose_payment_option' => 'enable_pay_per_post',
+ 'force_pack_purchase' => 'false',
+ 'enable_pay_per_post' => 'true',
+ 'pay_per_post_cost' => '5',
+ 'fallback_ppp_enable' => 'false',
+ 'use_theme_css' => 'wpuf-style',
+ 'form_layout' => 'layout1',
+ 'form_template' => 'post_form_template_paid_guest_post',
+ 'notification' => [
+ 'new' => 'on',
+ 'new_to' => get_option( 'admin_email' ),
+ 'new_subject' => 'New guest post submission',
+ 'new_body' => 'Hi,
+A new guest post has been submitted to your site {sitename} ({siteurl}).
+
+Here are the details:
+Post Title: CVE-2026-5459: User Frontend: AI Powered Frontend Posting, User Directory, Profile, Membership & User Registration <= 4.3.1 Unauthenticated Insecure Direct Object Reference to Arbitrary User Subscription Overwrite PoC, Patch Analysis & Rule
+Description: Atomic Edge analysis of CVE-2026-5459:
This vulnerability allows unauthenticated attackers to overwrite any user’s active subscription with a free subscription pack via an Insecure Direct Object Reference (IDOR) in the User Frontend plugin. The flaw exists in the payment_page() function within the subscription handling code. The CVSS score is 5.3 (Medium), indicating a moderate severity due to the requirement of a free subscription pack existing on the site.
The root cause is missing authorization validation on the ‘user_id’ parameter in the payment processing flow. The payment_page() function (defined in wp-user-frontend/class/subscription.php) accepts a ‘user_id’ from the user-controlled request but fails to verify that the authenticated user (or unauthenticated visitor) has permission to modify the target user’s subscription. Specifically, the function calls wpuf_get_user($user_id)->subscription()->add_pack() without checking if the requesting user is the same as the target user or has administrative privileges. Additionally, the post_redirect() method (line 648) and other subscription functions lacked admin user checks in the vulnerable version, which have been added in the patch.
Exploitation requires a site that has at least one free subscription pack (with price=0). An attacker sends a POST request to the payment endpoint (typically /wp-admin/admin-ajax.php with action ‘wpuf_payment’ or a direct form submission) including a ‘pack_id’ parameter pointing to a free subscription pack and a ‘user_id’ parameter set to the numeric ID of a target user. The attacker does not need authentication. For example, an attacker can send: POST /wp-admin/admin-ajax.php with action=wpuf_payment, pack_id=, user_id=. The plugin will process the request and overwrite the target user’s existing paid subscription with the free pack, causing the user to lose premium features.
The patch introduces multiple authorization checks. In wp-user-frontend/class/subscription.php: (1) post_redirect() now returns early if the user has admin role (line 651); (2) force_pack_notice() similarly bypasses for admin users (line 1130); (3) a new has_post_count check (line 1170) ensures that falling back to per-post payment only applies when the user has remaining posts in their current pack; (4) the method has_user_error() now returns the result of has_error() instead of calling it without returning (line 1249). The patch also corrects variable types (float vs int) and adds nonce verification to the admin page installer.
The impact is financial loss and service degradation for site users who have paid for premium subscriptions. An attacker can forcibly downgrade any user (including administrators, editors, or paying customers) to a free subscription tier, stripping them of paid features such as unlimited posting, custom fields, or priority support. This undermines the site’s subscription business model and can damage user trust. The vulnerability does not allow data theft or code execution, but it directly subverts the payment and subscription system.
+Short Description: Medium CVE-2026-5459 in Wp User Frontend (CVSS 5.3): User Frontend: AI Powered Frontend Posting, User Directory, Profile, Membership & User Registration. Atomic Edge summarizes impact, exploitability, and patch details, with WAF rule...
+Author: {author}
+Post URL: {permalink}
+Edit URL: {editlink}',
+ 'edit' => 'on',
+ 'edit_to' => get_option( 'admin_email' ),
+ 'edit_subject' => 'Guest post has been updated',
+ 'edit_body' => 'Hi,
+The guest post "CVE-2026-5459: User Frontend: AI Powered Frontend Posting, User Directory, Profile, Membership & User Registration <= 4.3.1 Unauthenticated Insecure Direct Object Reference to Arbitrary User Subscription Overwrite PoC, Patch Analysis & Rule" has been updated.
+
+Here are the details:
+Post Title: CVE-2026-5459: User Frontend: AI Powered Frontend Posting, User Directory, Profile, Membership & User Registration <= 4.3.1 Unauthenticated Insecure Direct Object Reference to Arbitrary User Subscription Overwrite PoC, Patch Analysis & Rule
+Description: Atomic Edge analysis of CVE-2026-5459:
This vulnerability allows unauthenticated attackers to overwrite any user’s active subscription with a free subscription pack via an Insecure Direct Object Reference (IDOR) in the User Frontend plugin. The flaw exists in the payment_page() function within the subscription handling code. The CVSS score is 5.3 (Medium), indicating a moderate severity due to the requirement of a free subscription pack existing on the site.
The root cause is missing authorization validation on the ‘user_id’ parameter in the payment processing flow. The payment_page() function (defined in wp-user-frontend/class/subscription.php) accepts a ‘user_id’ from the user-controlled request but fails to verify that the authenticated user (or unauthenticated visitor) has permission to modify the target user’s subscription. Specifically, the function calls wpuf_get_user($user_id)->subscription()->add_pack() without checking if the requesting user is the same as the target user or has administrative privileges. Additionally, the post_redirect() method (line 648) and other subscription functions lacked admin user checks in the vulnerable version, which have been added in the patch.
Exploitation requires a site that has at least one free subscription pack (with price=0). An attacker sends a POST request to the payment endpoint (typically /wp-admin/admin-ajax.php with action ‘wpuf_payment’ or a direct form submission) including a ‘pack_id’ parameter pointing to a free subscription pack and a ‘user_id’ parameter set to the numeric ID of a target user. The attacker does not need authentication. For example, an attacker can send: POST /wp-admin/admin-ajax.php with action=wpuf_payment, pack_id=, user_id=. The plugin will process the request and overwrite the target user’s existing paid subscription with the free pack, causing the user to lose premium features.
The patch introduces multiple authorization checks. In wp-user-frontend/class/subscription.php: (1) post_redirect() now returns early if the user has admin role (line 651); (2) force_pack_notice() similarly bypasses for admin users (line 1130); (3) a new has_post_count check (line 1170) ensures that falling back to per-post payment only applies when the user has remaining posts in their current pack; (4) the method has_user_error() now returns the result of has_error() instead of calling it without returning (line 1249). The patch also corrects variable types (float vs int) and adds nonce verification to the admin page installer.
The impact is financial loss and service degradation for site users who have paid for premium subscriptions. An attacker can forcibly downgrade any user (including administrators, editors, or paying customers) to a free subscription tier, stripping them of paid features such as unlimited posting, custom fields, or priority support. This undermines the site’s subscription business model and can damage user trust. The vulnerability does not allow data theft or code execution, but it directly subverts the payment and subscription system.
+Short Description: Medium CVE-2026-5459 in Wp User Frontend (CVSS 5.3): User Frontend: AI Powered Frontend Posting, User Directory, Profile, Membership & User Registration. Atomic Edge summarizes impact, exploitability, and patch details, with WAF rule...
+Author: {author}
+Post URL: {permalink}
+Edit URL: {editlink}',
+ ],
+ ];
+ }
+}
--- a/wp-user-frontend/includes/Admin/Forms/Post/Templates/Pro_Form_Preview_Testimonial.php
+++ b/wp-user-frontend/includes/Admin/Forms/Post/Templates/Pro_Form_Preview_Testimonial.php
@@ -0,0 +1,69 @@
+title = __( 'Testimonial Submission', 'wp-user-frontend' );
+ $this->image = WPUF_ASSET_URI . '/images/templates/testimonial.svg';
+ $this->pro_icon = WPUF_ASSET_URI . '/images/templates/crown.svg';
+ }
+
+ /**
+ * Get the template title
+ *
+ * @since 4.3.2
+ *
+ * @return string
+ */
+ public function get_title() {
+ return $this->title ? $this->title : '';
+ }
+
+ /**
+ * Get the template image
+ *
+ * @since 4.3.2
+ *
+ * @return string
+ */
+ public function get_image() {
+ return $this->image ? $this->image : '';
+ }
+
+ /**
+ * Get the pro icon
+ *
+ * @since 4.3.2
+ *
+ * @return string
+ */
+ public function get_pro_icon() {
+ return $this->pro_icon ? $this->pro_icon : '';
+ }
+}
--- a/wp-user-frontend/includes/Admin/Subscription.php
+++ b/wp-user-frontend/includes/Admin/Subscription.php
@@ -672,6 +672,11 @@
* @return string
*/
public function post_redirect( $response, $post_id, $form_id, $form_settings ) {
+ // Admin users bypass payment redirect
+ if ( current_user_can( wpuf_admin_role() ) ) {
+ return $response;
+ }
+
$form = new Form( $form_id );
$payment_options = $form->is_charging_enabled();
$force_pack = $form->is_enabled_force_pack();
@@ -1092,7 +1097,10 @@
// $price_with_tax = $this->wpuf_prices_include_tax();
- if ( self::has_user_error( $form_settings ) || ( $payment_enabled && $pay_per_post && ! $force_pack ) ) {
+ if (
+ ( self::has_user_error( $form_settings ) && ! ( $force_pack && $form->is_enabled_fallback_cost() ) )
+ || ( $payment_enabled && $pay_per_post && ! $force_pack )
+ ) {
?>
subscription()->has_post_count( $form_settings['post_type'] ) ) ) {
+ } elseif ( $payment_enabled && $force_pack && $form->is_enabled_fallback_cost() && ! is_wp_error( $current_pack ) && ! $current_user->subscription()->has_post_count( $form_settings['post_type'] ) ) {
?>
get_subs_fallback_cost();
+ $fallback_cost = (float) $form->get_subs_fallback_cost();
$fallback_cost = apply_filters( 'wpuf_payment_amount', $fallback_cost );
@@ -1178,9 +1185,20 @@
}
public function force_pack_notice( $text, $id, $form_settings ) {
+ // Admin users don't need subscription notices
+ if ( current_user_can( wpuf_admin_role() ) ) {
+ return $text;
+ }
+
$form = new Form( $id );
- $force_pack = $form->is_enabled_force_pack();
+ $force_pack = $form->is_enabled_force_pack();
+ $fallback_enabled = $form->is_enabled_fallback_cost();
+
+ // When fallback pay-per-post is enabled, don't show "purchase a pack" notice
+ if ( $force_pack && $fallback_enabled ) {
+ return $text;
+ }
if ( $force_pack && self::has_user_error( $form_settings ) ) {
$pack_page = get_permalink( wpuf_get_option( 'subscription_page', 'wpuf_payment' ) );
@@ -1206,7 +1224,11 @@
return 'yes';
}
- if ( $current_user->subscription()->current_pack_id() && ! $has_post_count ) {
+ // When force_pack + fallback pay-per-post is enabled, skip this early return
+ // so the downstream fallback logic can allow the user to post with per-post payment.
+ $skip_limit_block = $force_pack && $fallback_enabled;
+
+ if ( $current_user->subscription()->current_pack_id() && ! $has_post_count && ! $skip_limit_block ) {
return 'no';
}
@@ -1223,14 +1245,14 @@
if ( ! is_wp_error( $current_pack ) ) {
// current pack has no error
if ( ! $fallback_enabled ) {
- //fallback cost enabled
+ // fallback cost disabled
if ( ! $current_user->subscription()->current_pack_id() ) {
return 'no';
} elseif ( $current_user->subscription()->has_post_count( $form_settings['post_type'] ) ) {
return 'yes';
}
} elseif ( $fallback_enabled ) {
- //fallback cost disabled
+ // fallback cost enabled
if ( ! $current_user->subscription()->current_pack_id() ) {
return 'no';
} elseif ( $has_post_count ) {
@@ -1281,7 +1303,7 @@
// _deprecated_function( __FUNCTION__, '2.6.0', 'wpuf_get_user()->subscription()->has_error( $form_settings = null );' );
- wpuf_get_user()->subscription()->has_error( $form_settings );
+ return wpuf_get_user()->subscription()->has_error( $form_settings );
}
/**
--- a/wp-user-frontend/includes/Admin/template-parts/modal-v4.2.php
+++ b/wp-user-frontend/includes/Admin/template-parts/modal-v4.2.php
@@ -38,6 +38,10 @@
if ( strpos( strtolower( $form_type ), 'registration' ) !== false || strpos( strtolower( $form_type ), 'profile' ) !== false ) {
// Profile/Registration form categories
$categories = [
+ 'general' => [
+ 'label' => __( 'General', 'wp-user-frontend' ),
+ 'keywords' => [ 'simple', 'signup', 'blog author' ],
+ ],
'ecommerce' => [
'label' => __( 'E-commerce', 'wp-user-frontend' ),
'keywords' => [ 'vendor', 'marketplace', 'product' ],
@@ -46,10 +