Skip to content

Commit 3f8c77f

Browse files
authored
Feature: add form migration & campaign compatibility for p2p (#8215)
1 parent 3db058d commit 3f8c77f

12 files changed

Lines changed: 356 additions & 22 deletions

File tree

src/Campaigns/Actions/RedirectLegacyCreateFormToCreateCampaign.php

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
namespace Give\Campaigns\Actions;
44

55
use Give\Campaigns\Models\Campaign;
6-
use Give\Campaigns\ValueObjects\CampaignType;
76
use Give\Framework\Database\DB;
87

98
/**
@@ -91,23 +90,67 @@ private function isCampaignIdInvalidOrMissing(): bool
9190
}
9291

9392
/**
93+
* @unreleased updated logic to search the DB explicitly for P2P campaigns
9494
* @since 4.0.0
9595
*/
9696
private function isP2PCampaignFormIdInvalidOrMissing(): bool
9797
{
98-
$form = DB::table('give_campaigns')
99-
->where('form_id', $_GET['donationFormID'])
100-
->where('campaign_type', CampaignType::CORE, '!=')
98+
if (!isset($_GET['donationFormID'])) {
99+
return true;
100+
}
101+
102+
$formId = absint($_GET['donationFormID']);
103+
104+
// Check give_campaigns.form_id for P2P campaigns
105+
$campaign = DB::table('give_campaigns', 'c')
106+
->select('c.id')
107+
->innerJoin('give_p2p_campaigns', 'c.id', 'p2p.campaign_id', 'p2p')
108+
->where('c.form_id', $formId)
101109
->get();
102110

103-
return ! isset($_GET['donationFormID']) || ! $form;
111+
if ($campaign) {
112+
return false;
113+
}
114+
115+
// Also check give_campaign_forms junction table for P2P campaigns
116+
// (migrated v3 forms are stored in the junction table)
117+
$campaignForm = DB::table('give_campaign_forms')
118+
->where('form_id', $formId)
119+
->get();
120+
121+
if ($campaignForm) {
122+
$p2pCampaign = DB::table('give_p2p_campaigns')
123+
->where('campaign_id', $campaignForm->campaign_id)
124+
->get();
125+
126+
return !$p2pCampaign;
127+
}
128+
129+
return true;
104130
}
105131

106132
/**
133+
* @unreleased Also check give_campaign_forms junction table for non-core campaigns (e.g., migrated P2P forms).
107134
* @since 4.0.0
108135
*/
109136
private function isCampaignFormIdInvalidOrMissing(): bool
110137
{
111-
return ! isset($_GET['donationFormID']) || ! Campaign::findByFormId(absint($_GET['donationFormID']));
138+
if (!isset($_GET['donationFormID'])) {
139+
return true;
140+
}
141+
142+
$formId = absint($_GET['donationFormID']);
143+
144+
// Check core campaigns first
145+
if (Campaign::findByFormId($formId)) {
146+
return false;
147+
}
148+
149+
// Fallback: check give_campaign_forms junction table for non-core campaigns
150+
$campaignForm = DB::table('give_campaign_forms')
151+
->where('form_id', $formId)
152+
->get();
153+
154+
return !$campaignForm;
112155
}
113156
}

src/DonationForms/V2/DonationFormsAdminPage.php

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use Give\Campaigns\Models\Campaign;
77
use Give\DonationForms\V2\ListTable\DonationFormsListTable;
88
use Give\FeatureFlags\OptionBasedFormEditor\OptionBasedFormEditor;
9+
use Give\FormMigration\Actions\GetMigratedFormId;
910
use Give\Helpers\EnqueueScript;
1011
use Give\Helpers\Language;
1112
use Give\Framework\Permissions\Facades\UserPermissions;
@@ -168,6 +169,36 @@ public function loadMigrationScripts()
168169
if ($this->isShowingEditV2FormPage()) {
169170
$formId = (int)$_GET['post'];
170171
$campaign = Campaign::findByFormId($formId);
172+
$isMigrated = _give_is_form_migrated($formId);
173+
174+
$campaignUrl = $campaign
175+
? admin_url('edit.php?post_type=give_forms&page=give-campaigns&id=' . $campaign->id)
176+
: '';
177+
178+
/**
179+
* Filters the campaign URL displayed on the v2 form edit screen.
180+
* Allows add-ons (e.g., P2P) to provide their own campaign URL.
181+
*
182+
* @unreleased
183+
*
184+
* @param string $campaignUrl The campaign admin URL, or empty string if not found.
185+
* @param int $formId The donation form ID being edited.
186+
*/
187+
$campaignUrl = apply_filters('givewp_form_builder_campaign_url', $campaignUrl, $formId);
188+
189+
$migratedFormUrl = '';
190+
if ($isMigrated) {
191+
$v3FormId = (new GetMigratedFormId)($formId);
192+
if ($v3FormId) {
193+
$migratedFormUrl = add_query_arg([
194+
'post_type' => 'give_forms',
195+
'page' => 'givewp-form-builder',
196+
'donationFormID' => $v3FormId,
197+
'showTransfer' => '1',
198+
], admin_url('edit.php'));
199+
}
200+
}
201+
171202
EnqueueScript::make('give-edit-v2form', 'build/assets/dist/js/give-edit-v2form.js')
172203
->loadInFooter()
173204
->registerTranslations()
@@ -176,8 +207,9 @@ public function loadMigrationScripts()
176207
'supportedGateways' => $this->getSupportedGateways(),
177208
'migrationApiRoot' => $this->migrationApiRoot,
178209
'apiNonce' => $this->apiNonce,
179-
'isMigrated' => _give_is_form_migrated($formId),
180-
'campaignUrl' => $campaign ? admin_url('edit.php?post_type=give_forms&page=give-campaigns&id=' . $campaign->id) : '',
210+
'isMigrated' => $isMigrated,
211+
'migratedFormUrl' => $migratedFormUrl,
212+
'campaignUrl' => $campaignUrl,
181213
])
182214
->enqueue();
183215

src/DonationForms/V2/resources/components/DonationFormsListTable.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ declare global {
2929
pluginUrl: string;
3030
showUpgradedTooltip: boolean;
3131
isMigrated: boolean;
32+
migratedFormUrl: string;
3233
supportedAddons: Array<string>;
3334
supportedGateways: Array<string>;
3435
isOptionBasedFormEditorEnabled: boolean;

src/DonationForms/V2/resources/components/Onboarding/Components/EditForm.tsx

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ export default function EditForm() {
1212
upgrading: false
1313
});
1414

15+
const {isMigrated, migratedFormUrl} = window.GiveDonationForms;
16+
1517
return (
1618
<>
1719
<FormBuilderButtonPortal
@@ -21,7 +23,28 @@ export default function EditForm() {
2123
isEditing={true}
2224
/>
2325

24-
{!window.GiveDonationForms.isMigrated && (
26+
{isMigrated && migratedFormUrl ? (
27+
<div className={styles.migrationGuideBox}>
28+
<div className={styles.migrationGuideTitle}>
29+
<CompassIcon />
30+
{__('Upgrade in Progress', 'give')}
31+
</div>
32+
33+
<div className={styles.migrationGuideContent}>
34+
{__('This form has been upgraded to the Visual Form Builder. Complete the transfer to finalize the upgrade.', 'give')}
35+
</div>
36+
37+
<Button
38+
onClick={(e) => {
39+
e.preventDefault();
40+
window.location.href = migratedFormUrl;
41+
}}
42+
style={{width: '100%'}}
43+
>
44+
{__('Continue editing upgraded form', 'give')}
45+
</Button>
46+
</div>
47+
) : !isMigrated && (
2548
<div className={styles.migrationGuideBox}>
2649
<div className={styles.migrationGuideTitle}>
2750
<CompassIcon />

src/DonationForms/V2/resources/components/Onboarding/Dialogs/FeatureNoticeDialog.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,17 +87,14 @@ export default function FeatureNoticeDialog({isUpgrading, isEditing, handleClose
8787
</>
8888
)}
8989

90-
{isUpgrading ? (
90+
{isUpgrading || isEditing ? (
9191
<Button size="large" onClick={handleUpgrade} className={styles.proceedButton}>
92-
{__('Proceed with upgrade', 'give')}
92+
{isUpgrading ? __('Proceed with upgrade', 'give') : __('Proceed with the new form builder', 'give')}
9393
</Button>
9494
) : (
9595
<Button
9696
size="large"
9797
onClick={() => {
98-
if (isEditing) {
99-
sessionStorage.setItem('givewp-show-return-btn', 'true');
100-
}
10198
window.location.href = 'edit.php?post_type=give_forms&page=give-campaigns&new=campaign';
10299
}}
103100
className={styles.proceedButton}

src/FormBuilder/Routes/RegisterFormBuilderPageRoute.php

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,8 @@ public function renderPage()
140140
$migratedFormId = give_get_meta($donationFormId, 'migratedFormId', true);
141141
$transferredFormId = give_get_meta($donationFormId, 'transferredFormId', true);
142142

143+
$showTransferModal = isset($_GET['showTransfer']) && (bool)$migratedFormId && !(bool)$transferredFormId;
144+
143145
wp_localize_script('@givewp/form-builder/script', 'migrationOnboardingData', [
144146
'pluginUrl' => GIVE_PLUGIN_URL,
145147
'formId' => $donationFormId,
@@ -149,11 +151,12 @@ public function renderPage()
149151
'apiNonce' => wp_create_nonce('wp_rest'),
150152
'isMigratedForm' => $migratedFormId,
151153
'isTransferredForm' => $transferredFormId,
152-
'showUpgradeDialog' => (bool)$migratedFormId && !(bool)give_get_meta(
154+
'showUpgradeDialog' => !$showTransferModal && (bool)$migratedFormId && !(bool)give_get_meta(
153155
$donationFormId,
154156
'givewp-form-builder-migration-hide-notice',
155157
true
156158
),
159+
'showTransferModal' => $showTransferModal,
157160
'transferShowNotice' => (bool)$migratedFormId && !(bool)$transferredFormId && !(bool)give_get_meta(
158161
$donationFormId,
159162
'givewp-form-builder-transfer-hide-notice',
@@ -175,11 +178,29 @@ public function renderPage()
175178
]);
176179

177180
/**
181+
* @unreleased updated logic with filter
178182
* @since 4.0.0
179183
*/
184+
$campaignUrl = '';
180185
if ($campaign = Campaign::findByFormId($donationFormId)) {
186+
$campaignUrl = admin_url('edit.php?post_type=give_forms&page=give-campaigns&id=' . $campaign->id);
187+
}
188+
189+
/**
190+
* Filters the campaign URL displayed in the form builder header.
191+
* Allows add-ons (e.g., P2P) to provide their own campaign URL when
192+
* the form belongs to a non-core campaign type.
193+
*
194+
* @unreleased
195+
*
196+
* @param string $campaignUrl - The campaign admin URL, or empty string if not found.
197+
* @param int $donationFormId - The donation form ID being edited.
198+
*/
199+
$campaignUrl = apply_filters('givewp_form_builder_campaign_url', $campaignUrl, $donationFormId);
200+
201+
if ($campaignUrl) {
181202
wp_localize_script('@givewp/form-builder/script', 'headerContainer', [
182-
'campaignUrl' => admin_url('edit.php?post_type=give_forms&page=give-campaigns&id=' . $campaign->id),
203+
'campaignUrl' => $campaignUrl,
183204
]);
184205
}
185206

src/FormBuilder/resources/js/form-builder/src/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ const initialState = {
1919
transfer: {
2020
showNotice: Boolean(window.migrationOnboardingData.transferShowNotice),
2121
showUpgradeModal: Boolean(window.migrationOnboardingData.showUpgradeDialog),
22-
showTransferModal: false,
22+
showTransferModal: Boolean(window.migrationOnboardingData.showTransferModal),
2323
showTooltip: false,
2424
}
2525
};

src/FormBuilder/resources/js/form-builder/src/components/onboarding/Onboarding.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ declare global {
2525
migrationActionUrl: string;
2626
transferActionUrl: string;
2727
showUpgradeDialog: boolean;
28+
showTransferModal: boolean;
2829
transferShowNotice: boolean;
2930
isMigratedForm: boolean;
3031
isTransferredForm: boolean;

src/FormMigration/Controllers/MigrationController.php

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
namespace Give\FormMigration\Controllers;
44

55
use Give\Campaigns\Repositories\CampaignRepository;
6+
use Give\Campaigns\ValueObjects\CampaignType;
67
use Give\DonationForms\V2\Models\DonationForm;
78
use Give\FormMigration\Concerns\Blocks\BlockDifference;
89
use Give\FormMigration\DataTransferObjects\FormMigrationPayload;
910
use Give\FormMigration\Pipeline;
1011
use Give\Framework\Blocks\BlockModel;
12+
use Give\Framework\Database\DB;
1113
use Give\Log\Log;
1214
use WP_REST_Request;
1315
use WP_REST_Response;
@@ -56,19 +58,35 @@ public function __invoke(DonationForm $formV2)
5658
$campaignRepository = give(CampaignRepository::class);
5759
if ($campaign = $campaignRepository->getByFormId($payload->formV2->id)) {
5860
$campaignRepository->addCampaignForm($campaign, $payload->formV3->id);
61+
} else {
62+
// Fallback: Check for non-core campaigns (e.g., P2P) linked via give_campaigns.form_id
63+
$campaignData = DB::table('give_campaigns')
64+
->where('form_id', $payload->formV2->id)
65+
->where('campaign_type', CampaignType::CORE, '!=')
66+
->get();
67+
68+
if ($campaignData) {
69+
DB::table('give_campaign_forms')
70+
->insert([
71+
'form_id' => $payload->formV3->id,
72+
'campaign_id' => $campaignData->id,
73+
]);
74+
}
5975
}
6076

6177
Log::info(esc_html__('Form migrated from v2 to v3.', 'give'), $this->debugContext);
6278
});
6379

80+
$redirectArgs = apply_filters('givewp_form_migration_redirect_args', [
81+
'post_type' => 'give_forms',
82+
'page' => 'givewp-form-builder',
83+
'donationFormID' => $payload->formV3->id,
84+
], $payload->formV2->id, $payload->formV3->id);
85+
6486
return new WP_REST_Response([
6587
'v2FormId' => $payload->formV2->id,
6688
'v3FormId' => $payload->formV3->id,
67-
'redirect' => add_query_arg([
68-
'post_type' => 'give_forms',
69-
'page' => 'givewp-form-builder',
70-
'donationFormID' => $payload->formV3->id,
71-
], admin_url('edit.php')),
89+
'redirect' => add_query_arg($redirectArgs, admin_url('edit.php')),
7290
]);
7391
}
7492
}

src/FormMigration/Controllers/TransferController.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Give\FormMigration\Controllers;
44

55
use Give\Campaigns\Repositories\CampaignRepository;
6+
use Give\Campaigns\ValueObjects\CampaignType;
67
use Give\DonationForms\V2\Models\DonationForm;
78
use Give\FormMigration\Actions\GetMigratedFormId;
89
use Give\FormMigration\Actions\TransferDonations;
@@ -26,6 +27,10 @@ public function __construct(WP_REST_Request $request)
2627
$this->request = $request;
2728
}
2829

30+
/**
31+
* @unreleased updated logic to search for non-core campaigns (e.g., P2P)
32+
* @since 3.0.0
33+
*/
2934
public function __invoke(DonationForm $formV2, TransferOptions $options)
3035
{
3136
DB::transaction(function() use ($formV2, $options) {
@@ -42,6 +47,20 @@ public function __invoke(DonationForm $formV2, TransferOptions $options)
4247
if ($defaultForm->id === $formV2->id) {
4348
$campaignRepository->updateDefaultCampaignForm($campaign, $v3FormId);
4449
}
50+
} else {
51+
// Fallback: Check for non-core campaigns (e.g., P2P) linked via give_campaigns.form_id
52+
$campaignData = DB::table('give_campaigns')
53+
->where('form_id', $formV2->id)
54+
->where('campaign_type', CampaignType::CORE, '!=')
55+
->get();
56+
57+
if ($campaignData) {
58+
DB::table('give_campaigns')
59+
->where('id', $campaignData->id)
60+
->update([
61+
'form_id' => $v3FormId,
62+
]);
63+
}
4564
}
4665

4766
if($options->shouldDelete()) {

0 commit comments

Comments
 (0)