PluginProbe
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More / 2.4.1
Better Payment – Instant Payments, Donations, Fundraising with Subscriptions & More v2.4.1
2.4.1 2.4.0 2.3.4 2.3.3 2.3.2 2.3.1 2.3.0 2.2.2 2.2.1 2.2.0 2.1.2 2.1.1 trunk 0.0.1 0.0.2 0.0.3 0.0.4 0.0.5 0.0.6 0.0.7 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 All 68 releases
← All changes | better-payment.php +308 -97 0.0.1 → 2.4.1 View file →
@@ -1,151 +1,362 @@
1 1 <?php
2 +
2 3 /**
3 4 * Plugin Name: Better Payment
4 - * Description: Make instant payment with one click through BetterPayment. It offers seamless integrations with Elementor and allows you to get payment through PayPal and Stripe.
5 - * Plugin URI: https://wpdeveloper.net/
5 + * Description: Better Payment allows you to automate payment transactions to manage donations, make payments, sell products, and more on your Elementor and Gutenberg website.
6 + * Plugin URI: https://wpdeveloper.com/
6 7 * Author: WPDeveloper
7 - * Version: 0.0.1
8 - * Author URI: https://wpdeveloper.net/
8 + * Version: 2.4.1
9 + * Requires at least: 6.0
10 + * Requires PHP: 7.4
11 + * Author URI: https://wpdeveloper.com/
9 12 * Text Domain: better-payment
10 13 * Domain Path: /languages
11 14 */
12 15
13 -if ( !defined( 'ABSPATH' ) ) {
16 +if (!defined('ABSPATH')) {
14 17 exit;
15 18 } // Exit if accessed directly
16 19
17 -class BetterPayment {
20 +require_once __DIR__ . '/vendor/autoload.php';
18 21
19 - private static $instance;
22 +/**
23 + * The plugin main class
24 + *
25 + * @since 0.0.1
26 + */
27 +final class Better_Payment {
20 28
29 + use Better_Payment\Lite\Traits\Helper;
30 +
31 + /**
32 + * Plugin version
33 + *
34 + * @var string
35 + * @since 0.0.1
36 + */
37 + const version = '2.4.1';
38 +
39 + /**
40 + * Class construcotr
41 + *
42 + * @since 0.0.1
43 + */
44 + private function __construct() {
45 + $this->define_constants();
46 +
47 + register_activation_hook(__FILE__, [$this, 'activate']);
48 +
49 + add_action('plugins_loaded', [$this, 'init_plugin']);
50 + }
51 +
52 + /**
53 + * Initialize a singleton instance
54 + *
55 + * @return \Better_Payment
56 + * @since 0.0.1
57 + */
21 58 public static function init() {
22 - if ( !isset( self::$instance ) && !( self::$instance instanceof BetterPayment ) ) {
23 - self::$instance = new self();
59 + static $instance = false;
60 +
61 + if (!$instance) {
62 + $instance = new self();
24 63 }
25 64
26 - return self::$instance;
65 + return $instance;
27 66 }
28 67
29 - public function __construct() {
30 - add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
31 - $this->define_constants();
32 - $this->init_plugin();
33 -
68 + /**
69 + * Define the required plugin constants
70 + *
71 + * @return void
72 + * @since 0.0.1
73 + */
74 + public function define_constants() {
75 + define('BETTER_PAYMENT_VERSION', self::version);
76 + // Bump this whenever the campaign CPT rewrite rules change (slug, etc.) to
77 + // trigger a one-time flush_rewrite_rules() on the next init for existing installs.
78 + define('BETTER_PAYMENT_CAMPAIGN_REWRITE_VERSION', '1');
79 + define('BETTER_PAYMENT_FILE', __FILE__);
80 + define('BETTER_PAYMENT_BASENAME', plugin_basename(__FILE__));
81 + define('BETTER_PAYMENT_PATH', __DIR__);
82 + define('BETTER_PAYMENT_URL', plugins_url('', BETTER_PAYMENT_FILE));
83 + define('BETTER_PAYMENT_ASSETS', BETTER_PAYMENT_URL . '/assets');
84 + define('BETTER_PAYMENT_ASSETS_PATH', BETTER_PAYMENT_PATH . '/assets');
85 + define('BETTER_PAYMENT_DEV_ASSETS', BETTER_PAYMENT_URL . '/bpbuild');
86 + define('BETTER_PAYMENT_DEV_ASSETS_PATH', BETTER_PAYMENT_PATH . '/bpbuild');
87 + define('BETTER_PAYMENT_INCLUDES_PATH', BETTER_PAYMENT_PATH . '/includes');
88 + define('BETTER_PAYMENT_ADMIN_PATH', BETTER_PAYMENT_INCLUDES_PATH . '/Admin');
89 + define('BETTER_PAYMENT_ADMIN_VIEWS_PATH', BETTER_PAYMENT_ADMIN_PATH . '/views');
90 + }
91 +
92 + /**
93 + * Do stuff upon plugin activation
94 + *
95 + * @return void
96 + * @since 0.0.1
97 + */
98 + public function activate() {
99 + $installer = new Better_Payment\Lite\Installer();
100 + $installer->run();
101 +
102 + // Register the campaign CPT and flush rewrite rules so campaign permalinks
103 + // (/bp-campaign/{slug}/) resolve immediately, without needing a manual
104 + // Settings → Permalinks re-save. Mark the rewrite version so the init-time
105 + // self-heal flush (see init_campaign_module) does not run redundantly.
106 + ( new Better_Payment\Lite\Campaign\CPT() )->register();
107 + flush_rewrite_rules();
108 + update_option( 'better_payment_campaign_rewrite_version', BETTER_PAYMENT_CAMPAIGN_REWRITE_VERSION );
109 +
110 + if (get_option('better_payment_plugin_installed_fresh') !== 'yes' && get_option('better_payment_plugin_installed_time_fresh') === false) {
111 + update_option('better_payment_plugin_installed_fresh', 'yes');
112 +
113 + $now = time();
114 + update_option('better_payment_plugin_installed_time_fresh', $now);
115 + update_option('better_payment_progress_bar_dismissed_expiry_date', $now + 7 * DAY_IN_SECONDS);
116 + }
117 + }
118 +
119 + /**
120 + * Initialize the plugin
121 + *
122 + * @return void
123 + * @since 0.0.1
124 + */
125 + public function init_plugin() {
126 + new Better_Payment\Lite\Assets();
127 +
34 128 if (is_admin()) {
35 - if ( defined( 'ELEMENTOR_VERSION' ) ) {
36 - new BetterPayment_Settings();
129 + $adminObj = new Better_Payment\Lite\Admin();
130 + $adminObj->init();
131 +
132 + // Warn when the installed Pro predates what this Lite supports.
133 + Better_Payment\Lite\Classes\ProCompatibility::register();
134 +
135 + if ( !$this->bp_section_dismissed() ) {
136 + add_action('save_post', array($this, 'bp_widget_usage_on_save'), 10, 1);
37 137 }
38 -
39 - require 'admin/includes/class-betterpayment-helper.php';
40 -
41 - if (!did_action('elementor/loaded')) {
42 - $notice = new BetterPayment_Helper();
43 - $notice->elementor_not_loaded();
44 - }
138 + } else {
139 + new Better_Payment\Lite\Frontend();
140 + }
45 141
46 - if (did_action('elementor/loaded')) {
47 - add_filter('plugin_action_links', array($this, 'plugin_actions_links'), 10, 2);
48 - }
142 + /**
143 + * Usage tracking must be registered on CRON requests too, not just admin.
144 + *
145 + * This used to be wired only from Admin::init(), which runs solely under
146 + * is_admin(). But WP-Cron executes wp-cron.php as a NON-admin request, so
147 + * Plugin_Usage_Tracker::init() never ran there and its do_tracking()
148 + * callback was never attached. The daily event was scheduled and fired on
149 + * time — into an empty hook. The tracker therefore never sent anything on
150 + * its own schedule; the only payloads that ever went out were the forced
151 + * ones from the setup wizard's opt-in. Silent, and invisible from the
152 + * cron listing, which shows the event as perfectly healthy.
153 + *
154 + * Not registered on front-end requests: nothing here is needed to render a
155 + * page, and this is a payment plugin whose public pages should carry no
156 + * avoidable work. Admin + cron is the complete set of contexts the tracker
157 + * acts in (notice, action links, AJAX, and the scheduled send).
158 + *
159 + * @since 2.3.2
160 + */
161 + if ( is_admin() || wp_doing_cron() ) {
162 + add_action( 'init', array( $this, 'start_plugin_tracking' ) );
49 163 }
164 +
165 + new Better_Payment\Lite\API();
166 +
167 + // Initialize Gutenberg blocks
168 + Better_Payment\Lite\Blocks\BlockManager::get_instance();
169 + Better_Payment\Lite\Blocks\StyleHandler::init();
170 +
171 + // Initialize Block Actions for payment processing (runs before Elementor Actions)
172 + new Better_Payment\Lite\Blocks\BlockActions();
173 +
174 + // Always register PayPal IPN listener + verification poll. These must run even
175 + // when Elementor is inactive, because PayPal payments also flow through the
176 + // block/campaign path. (Previously registered only inside the Elementor gate
177 + // via Classes\Actions, so non-Elementor sites never confirmed PayPal payments.)
178 + add_action( 'admin_post_better_payment_paypal_ipn', [ 'Better_Payment\Lite\Classes\Handler', 'handle_paypal_ipn' ] );
179 + add_action( 'admin_post_nopriv_better_payment_paypal_ipn', [ 'Better_Payment\Lite\Classes\Handler', 'handle_paypal_ipn' ] );
180 + add_action( 'wp_ajax_better_payment_check_paypal_status', [ 'Better_Payment\Lite\Classes\Handler', 'check_paypal_status' ] );
181 + add_action( 'wp_ajax_nopriv_better_payment_check_paypal_status', [ 'Better_Payment\Lite\Classes\Handler', 'check_paypal_status' ] );
182 +
183 + if (defined('ELEMENTOR_VERSION')) {
184 + new Better_Payment\Lite\Classes\Actions();
185 + $el_integration = new Better_Payment\Lite\Admin\Elementor\EL_Integration();
186 + $el_integration->init();
187 +
188 + Better_Payment\Lite\Admin\Settings::save_default_settings();
189 + }
190 +
191 + // ── Campaign Builder module ────────────────────────────────────
192 + $this->init_campaign_module();
193 +
194 + // ── AI module (AI-native Campaign Builder) ─────────────────────
195 + $this->init_ai_module();
196 +
197 + // ── WooCommerce gateway module (Better Payment as a WC gateway) ─
198 + $this->init_woocommerce_module();
50 199 }
51 200
52 - public function define_constants() {
53 - define( 'WPBP_PLUGIN_VERSION', '0.0.1' );
54 - define( 'WPBP_PLUGIN_FILE', __FILE__ );
55 - define( 'WPBP_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
56 - define( 'WPBP_PLUGIN_PATH', trailingslashit( plugin_dir_path( __FILE__ ) ) );
57 - define( 'WPBP_PLUGIN_URL', trailingslashit( plugins_url( '/', __FILE__ ) ) );
58 - define( 'WPBP_ADMIN_PATH', WPBP_PLUGIN_PATH.'admin/');
59 - define( 'WPBP_ADMIN_INCLUDES_PATH', WPBP_PLUGIN_PATH.'admin/includes/');
60 - define( 'WPBP_ADMIN_VIEW_PATH', WPBP_PLUGIN_PATH.'admin/views/');
61 - define( 'WPBP_ADMIN_URL', WPBP_PLUGIN_URL.'admin/');
62 - define( 'WPBP_ADMIN_INCLUDES_URL', WPBP_PLUGIN_URL.'admin/includes/');
63 - define( 'WPBP_ADMIN_VIEW_URL', WPBP_PLUGIN_URL.'admin/views/');
64 - define( 'WPBP_ADMIN_ASSET_URL', WPBP_PLUGIN_URL.'admin/asset/');
201 + /**
202 + * Initialize the WooCommerce integration module.
203 + *
204 + * Registers the "Better Payment (Stripe)" WooCommerce payment gateway,
205 + * which consumes the existing Better Payment payment engine (Stripe
206 + * checkout creation, transaction persistence, verification, hooks).
207 + * No-op when WooCommerce is not active — none of the module's classes
208 + * load, and core never depends on WooCommerce.
209 + *
210 + * @return void
211 + */
212 + private function init_woocommerce_module() {
213 + if ( ! class_exists( 'WooCommerce' ) ) {
214 + return;
215 + }
65 216
217 + Better_Payment\Lite\WooCommerce\Loader::register();
66 218 }
67 219
68 - public function enqueue_scripts() {
69 - wp_register_script( 'betterpayment-stripe', 'https://js.stripe.com/v3/' );
70 - wp_register_script( 'betterpayment', WPBP_PLUGIN_URL . 'asset/js/betterpayment.min.js', [
71 - 'jquery',
72 - 'betterpayment-stripe'
73 - ], WPBP_PLUGIN_VERSION, true );
74 - wp_register_style( 'betterpayment-el', WPBP_PLUGIN_URL . 'asset/css/betterpayment-el.min.css' );
75 - wp_localize_script( 'betterpayment', 'betterpayment', array(
76 - 'ajax_url' => admin_url( 'admin-ajax.php' ),
77 - 'nonce' => wp_create_nonce( 'betterpayment' ),
78 - ) );
220 + /**
221 + * Initialize the AI module (providers, operations, REST endpoints).
222 + *
223 + * @return void
224 + */
225 + private function init_ai_module() {
226 + // Register providers + resolve settings-driven config.
227 + ( new Better_Payment\Lite\AI\AIManager() )->init();
79 228
80 - wp_enqueue_style( 'toastr-css', WPBP_PLUGIN_URL . 'asset/vendor/toastr/css/toastr.min.css' );
81 - wp_enqueue_script( 'toastr-js', WPBP_PLUGIN_URL . 'asset/vendor/toastr/js/toastr.min.js', array( 'jquery' ), WPBP_PLUGIN_VERSION, true );
82 -
229 + // REST API for AI (chat/generate/analyze/image/conversations/config).
230 + new Better_Payment\Lite\API\AIAPI();
83 231 }
84 232
85 233 /**
86 - * Activate plugin.
234 + * Initialize the Campaign Builder module.
87 235 *
88 236 * @return void
89 - * @since 1.0.0
90 237 */
91 - public function activate_plugin() {
92 - require 'includes/class-betterpayment-installer.php';
93 - BetterPayment_Installer::install();
94 - }
238 + private function init_campaign_module() {
239 + $cpt = new Better_Payment\Lite\Campaign\CPT();
95 240
96 - public function init_plugin() {
97 - if ( defined( 'ELEMENTOR_VERSION' ) ) {
98 - require_once 'includes/class-betterpayment-handler.php';
99 - require_once 'includes/class-betterpayment-actions.php';
100 - require_once 'includes/elementor/class-betterpayment-el-integration.php';
241 + // CPT registration (runs on init)
242 + add_action( 'init', [ $cpt, 'register' ] );
101 243
102 - $better_action = new BetterPayment_Actions();
103 - $el_integration = new BetterPayment_EL_integration();
104 - $el_integration->init();
244 + // Self-heal rewrite rules for installs that updated into this version
245 + // (the activation hook does NOT re-run on plugin update). Runs after the
246 + // CPT is registered (priority 11 > default 10) so the new rule is present
247 + // when we flush, then records the version so it flushes only once.
248 + add_action( 'init', static function () {
249 + if ( get_option( 'better_payment_campaign_rewrite_version' ) !== BETTER_PAYMENT_CAMPAIGN_REWRITE_VERSION ) {
250 + flush_rewrite_rules();
251 + update_option( 'better_payment_campaign_rewrite_version', BETTER_PAYMENT_CAMPAIGN_REWRITE_VERSION );
252 + }
253 + }, 11 );
105 254
106 - require_once 'admin/includes/class-betterpayment-settings.php';
107 - require_once 'admin/includes/class-betterpayment-db.php';
255 + // Admin-only: builder page, submenu, asset enqueue
256 + if ( is_admin() ) {
257 + add_action( 'admin_menu', [ $cpt, 'register_builder_page' ], 20 );
258 + add_action( 'admin_enqueue_scripts', [ $cpt, 'enqueue_builder_assets' ] );
259 + add_action( 'admin_enqueue_scripts', [ $cpt, 'enqueue_list_assets' ] );
260 + add_action( 'load-post-new.php', [ $cpt, 'redirect_new_post' ] );
261 + add_action( 'load-post.php', [ $cpt, 'redirect_edit_post' ] );
262 + add_filter( 'get_edit_post_link', [ $cpt, 'filter_edit_link' ], 10, 3 );
263 + add_action( 'admin_init', [ $cpt, 'redirect_cpt_list' ] );
108 264
109 - BetterPayment_Settings::save_default_settings();
265 + // Save post meta when post is saved via standard WP (rare path)
266 + add_action( 'save_post_bp_campaign', [ new Better_Payment\Lite\Campaign\MetaBox(), 'save' ] );
267 +
268 + // Custom columns on campaign list table
269 + $admin_list = new Better_Payment\Lite\Campaign\CampaignListColumns();
270 + add_filter( 'manage_bp_campaign_posts_columns', [ $admin_list, 'add_columns' ] );
271 + add_action( 'manage_bp_campaign_posts_custom_column', [ $admin_list, 'render_column' ], 10, 2 );
110 272 }
111 - }
112 273
113 - /**
114 - * Add settings page link on plugins page
115 - */
116 - public function plugin_actions_links($links, $file)
117 - {
118 - $betterpayment_plugin = plugin_basename(__FILE__);
274 + // Serve a custom template for bp_campaign single pages so RendererService renders
275 + // the campaign content instead of the theme's empty single.php.
276 + add_filter( 'template_include', static function ( $template ) {
277 + if ( is_singular( 'bp_campaign' ) ) {
278 + $custom = BETTER_PAYMENT_PATH . '/templates/single-bp_campaign.php';
279 + return file_exists( $custom ) ? $custom : $template;
280 + }
281 + return $template;
282 + } );
119 283
120 - if ($file == $betterpayment_plugin && current_user_can('manage_options')) {
121 - $links[] = sprintf('<a href="%s">%s</a>', admin_url("admin.php?page=betterpayment-settings"), __('Settings', 'better-payment'));
122 - }
284 + // Register element types and templates (must run before CPT enqueue_builder_assets).
285 + // Deferred to init so __() calls don't trigger translation loading during plugins_loaded.
286 + add_action( 'init', [ 'Better_Payment\Lite\Campaign\Elements\CampaignElements', 'register_all' ], 5 );
123 287
124 - return $links;
125 - }
288 + // Campaign display block (server-side render)
289 + $block = new Better_Payment\Lite\Campaign\CampaignBlock();
290 + add_action( 'init', [ $block, 'register' ], 20 );
126 291
292 + // Shortcode [bp_campaign id="42"]
293 + $shortcode = new Better_Payment\Lite\Campaign\Shortcode();
294 + $shortcode->register();
295 +
296 + // REST API for campaigns
297 + new Better_Payment\Lite\API\CampaignAPI();
298 +
299 + // Bust campaign stats cache when a payment is confirmed by any gateway.
300 + Better_Payment\Lite\Campaign\CampaignStats::register_hooks();
301 + }
127 302 }
128 303
129 -register_activation_hook( __FILE__, 'wp_better_plugin_activate' );
304 +/**
305 + * Initializes the main plugin
306 + *
307 + * @return \Better_Payment
308 + * @since 0.0.1
309 + */
130 310
131 -function wp_better_plugin_activate() {
132 - require 'includes/class-betterpayment-installer.php';
133 - BetterPayment_Installer::install();
311 +Better_Payment::init();
312 +
313 +/**
314 + * Plugin migrator
315 + *
316 + * @since 0.0.2
317 + */
318 +function better_payment_migrator() {
319 + Better_Payment\Lite\Classes\Migrator::migrator();
134 320 }
135 321
136 -add_action( 'plugins_loaded', function () {
137 - BetterPayment::init();
138 -} );
139 322
140 323 /**
141 - * Plugin migrator
324 + * On wp load
142 325 *
143 - * @since 1.0.0
326 + * @return void
327 + * @since 0.0.1
144 328 */
145 329 add_action('wp_loaded', function () {
146 - // set current version to db
147 - if (get_option('wpbp_version') != WPBP_PLUGIN_VERSION) {
148 - // update plugin version
149 - update_option('wpbp_version', WPBP_PLUGIN_VERSION);
330 + if (get_option('better_payment_version') != BETTER_PAYMENT_VERSION) {
331 + better_payment_migrator();
332 + update_option('better_payment_version', BETTER_PAYMENT_VERSION);
150 333 }
151 -});
334 +
335 + // Once per site, not per version: WooCommerce rows written in site time → UTC.
336 + Better_Payment\Lite\Classes\PaymentDateMigration::maybe_run();
337 +
338 + $setup_wizard = get_option('better_payment_setup_wizard');
339 +
340 + if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
341 + $is_from_better_payment = (isset( $_POST['form_data'] ) && isset( $_POST['form_data'][0] ) && isset( $_POST['form_data'][0]['name'] ) && strpos( $_POST['form_data'][0]['name'], 'better_payment_' ) !== false) || (isset( $_POST['is_tracking'] ) && $_POST['is_tracking'] === 'true') || (isset( $_POST['action'] ) && $_POST['action'] === 'save_setup_wizard_data');
342 +
343 + if ( ! $is_from_better_payment ) {
344 + return;
345 + }
346 + }
347 +
348 + if ($setup_wizard == 'redirect') {
349 + Better_Payment\Lite\Admin\Setup_Wizard::redirect();
350 + }
351 +
352 + if ($setup_wizard == 'init') {
353 + new Better_Payment\Lite\Admin\Setup_Wizard();
354 + }
355 +});
356 +
357 +/**
358 + * Dispatch actions
359 + *
360 + * @since 0.0.1
361 + */
362 +\Better_Payment\Lite\Admin::dispatch_actions();