CrowdyPartner Revenue Sync & Wallet Manager

PHP

Difficulty Level: intermediate

Snippet Description

Automatically creates a Wallet CPT for every user, calculates their total, pending, and completed contributions, and keeps wallet balances synced with JetEngine user meta. Includes cron-based batch processing for existing users and real-time updates when wallet data changes.

<?php
/*
Plugin Name: Auto Create Wallets with JetEngine Meta Sync + Wallet Auto Sync
Description: Creates Wallet CPTs for all users, writes balances to JetEngine user meta, keeps them synced, and auto-syncs contributions from JetEngine CCT.
Version: 2.0
Author: Ezekiel Ozi Momoh
*/

if (!defined('ABSPATH')) exit;

// ---------------------------------------------------
// 1. Create wallet for new users
// ---------------------------------------------------
add_action('user_register', 'jetengine_create_wallet_for_user', 20, 1);
function jetengine_create_wallet_for_user($user_id) {
    create_wallet_if_not_exists($user_id);
}

// ---------------------------------------------------
// 2. Batch-create wallets for existing users (hourly cron)
// ---------------------------------------------------
register_activation_hook(__FILE__, function() {
    if (!wp_next_scheduled('jetengine_create_wallets_cron')) {
        wp_schedule_event(time(), 'hourly', 'jetengine_create_wallets_cron');
    }

    if (!wp_next_scheduled('crowdy_wallet_sync_cron')) {
        wp_schedule_event(time(), 'every_five_minutes', 'crowdy_wallet_sync_cron');
    }
});

// Clear cron on plugin deactivation
register_deactivation_hook(__FILE__, function() {
    wp_clear_scheduled_hook('jetengine_create_wallets_cron');
    wp_clear_scheduled_hook('crowdy_wallet_sync_cron');
});

// Support a 5-minute cron schedule
add_filter('cron_schedules', function($schedules) {
    $schedules['every_five_minutes'] = [
        'interval' => 300,
        'display'  => __('Every 5 Minutes')
    ];
    return $schedules;
});

// Cron hook for batch wallet creation
add_action('jetengine_create_wallets_cron', 'jetengine_create_wallets_for_existing_users_batch');

function jetengine_create_wallets_for_existing_users_batch() {
    $offset = (int) get_transient('jetengine_wallets_batch_offset') ?: 0;
    $batch_size = 50;

    $users = get_users([
        'number' => $batch_size,
        'offset' => $offset,
        'fields' => ['ID'],
    ]);

    if (empty($users)) {
        set_transient('jetengine_wallets_batch_done', 1, 0);
        delete_transient('jetengine_wallets_batch_offset');
        return;
    }

    foreach ($users as $user) {
        create_wallet_if_not_exists($user->ID);
    }

    $offset += $batch_size;
    set_transient('jetengine_wallets_batch_offset', $offset, HOUR_IN_SECONDS);
}

// ---------------------------------------------------
// 3. Helper function to create wallet
// ---------------------------------------------------
function create_wallet_if_not_exists($user_id) {

    $existing = get_posts([
        'post_type'  => 'wallets',
        'meta_key'   => 'user_id',
        'meta_value' => $user_id,
        'post_status'=> 'any',
        'numberposts'=> 1,
    ]);

    if (!empty($existing)) return;

    $user = get_userdata($user_id);
    if (!$user) return;

    $username = $user->display_name ?: $user->user_login;
    $suffix = strtoupper(substr(md5(uniqid('', true)), 0, 4));

    $wallet_id = wp_insert_post([
        'post_type'   => 'wallets',
        'post_status' => 'publish',
        'post_title'  => $username . ' Wallet-' . $suffix,
    ]);

    if (is_wp_error($wallet_id) || !$wallet_id) {
        error_log('Failed to create wallet for user ' . $user_id);
        return;
    }

    $wallet_meta = [
        'user_id'           => $user_id,
        'available_balance' => 0.00,
        'pending_balance'   => 0.00,
        'total_withdrawn'   => 0.00,
        'total_earned'      => 0.00,
        'created_at'        => current_time('mysql'),
        'updated_at'        => current_time('mysql'),
    ];

    foreach ($wallet_meta as $key => $value) {
        update_post_meta($wallet_id, $key, $value);
    }

    update_user_meta($user_id, 'wallet_available_balance', 0);
    update_user_meta($user_id, 'wallet_pending_balance', 0);
    update_user_meta($user_id, 'wallet_total_withdrawn', 0);
    update_user_meta($user_id, 'wallet_total_earned', 0);
}

// ---------------------------------------------------
// 4. Sync Wallet CPT meta to JetEngine user meta
// ---------------------------------------------------
add_action('save_post_wallets', 'sync_wallet_cpt_to_user_meta', 20, 2);

function sync_wallet_cpt_to_user_meta($post_id, $post) {
    if ($post->post_status !== 'publish') return;

    remove_action('save_post_wallets', 'sync_wallet_cpt_to_user_meta', 20, 2);

    $user_id = get_post_meta($post_id, 'user_id', true);
    if (!$user_id) {
        add_action('save_post_wallets', 'sync_wallet_cpt_to_user_meta', 20, 2);
        return;
    }

    $wallet_meta_keys = [
        'available_balance' => 'wallet_available_balance',
        'pending_balance'   => 'wallet_pending_balance',
        'total_withdrawn'   => 'wallet_total_withdrawn',
        'total_earned'      => 'wallet_total_earned',
    ];

    foreach ($wallet_meta_keys as $wallet_key => $user_meta_key) {
        $value = floatval(get_post_meta($post_id, $wallet_key, true));
        update_user_meta($user_id, $user_meta_key, $value);
    }

    add_action('save_post_wallets', 'sync_wallet_cpt_to_user_meta', 20, 2);
}

// ---------------------------------------------------
// 5. SHORTCODE: [wallet_balance type="available"]
// ---------------------------------------------------
add_shortcode('wallet_balance', function($atts){
    $atts = shortcode_atts([
        'type' => 'available_balance',
    ], $atts, 'wallet_balance');

    $user_id = get_current_user_id();
    if (!$user_id) return 'Please log in to view your balance.';

    $meta_map = [
        'available_balance' => 'wallet_available_balance',
        'pending_balance'   => 'wallet_pending_balance',
        'total_withdrawn'   => 'wallet_total_withdrawn',
        'total_earned'      => 'wallet_total_earned',
    ];

    $key = $meta_map[$atts['type']] ?? null;
    if (!$key) return '';

    $value = floatval(get_user_meta($user_id, $key, true));
    return '$' . number_format($value, 2);
});

// ---------------------------------------------------
// 6. MAIN WALLET SYNC ENGINE (CCT → Wallet)
// ---------------------------------------------------
add_action('crowdy_wallet_sync_cron', 'crowdy_sync_all_wallet_balances');

function crowdy_sync_all_wallet_balances() {
    global $wpdb;

    $table = $wpdb->prefix . "jet_cct_contributions";

    // Get all authors who have contributions
    $authors = $wpdb->get_col("
        SELECT DISTINCT campaign_author_id 
        FROM $table
        WHERE campaign_author_id IS NOT NULL
    ");

    if (empty($authors)) return;

    foreach ($authors as $author_id) {

        // Ensure the wallet exists
        create_wallet_if_not_exists($author_id);

        // Get wallet ID
        $wallet = get_posts([
            'post_type'  => 'wallets',
            'meta_key'   => 'user_id',
            'meta_value' => $author_id,
            'post_status'=> 'any',
            'numberposts'=> 1,
        ]);

        if (empty($wallet)) continue;
        $wallet_id = $wallet[0]->ID;

        // Query pending contributions
        $pending = (float) $wpdb->get_var($wpdb->prepare("
            SELECT SUM(contribution_amount)
            FROM $table
            WHERE campaign_author_id = %d
            AND payment_status = 'pending'
        ", $author_id));

        // Query completed contributions
        $completed = (float) $wpdb->get_var($wpdb->prepare("
            SELECT SUM(contribution_amount)
            FROM $table
            WHERE campaign_author_id = %d
            AND payment_status = 'completed'
        ", $author_id));

        $pending   = $pending ?: 0;
        $completed = $completed ?: 0;
        $total     = $pending + $completed;

        // Update Wallet meta
        update_post_meta($wallet_id, 'pending_balance', $pending);
        update_post_meta($wallet_id, 'available_balance', $completed);
        update_post_meta($wallet_id, 'total_earned', $total);

        // Sync to user meta
        update_user_meta($author_id, 'wallet_pending_balance', $pending);
        update_user_meta($author_id, 'wallet_available_balance', $completed);
        update_user_meta($author_id, 'wallet_total_earned', $total);
    }
}

Usage Instructions

Usage Instructions

  1. Paste the full code into WPCode Snippets as a PHP snippet.

  2. Set the snippet to Run Everywhere.

  3. Activate the snippet.

  4. When activated, it will:

    • Automatically generate a Wallet custom post for every user who does not have one.

    • Sync earnings, pending, available balance, and total withdrawn based on JetEngine CCT “contributions”.

    • Keep Wallet CPT meta and JetEngine user meta updated in real time.

  5. Existing users’ wallets will be created in safe batches using a scheduled hourly cron job.

No further configuration is required.

Table of Contents