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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions includes/class-ypf-ui-addon-category-badge.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
<?php
/**
* Admin: "Checkout Badge" field on the Product Category editor.
*
* Lets the merchant set the eval-type card badge ("Best Value" / "Most Popular")
* per product category, stored in the `_ypf_term_badge` term meta that
* templates/woocommerce/checkout/form-product-selection.php already reads.
*
* Add-on only — standard WordPress taxonomy hooks, no main-plugin change.
*/

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

class YPF_UI_Addon_Category_Badge {

const META_KEY = '_ypf_term_badge';
const TAXONOMY = 'product_cat';

public static function init(): void {
add_action( self::TAXONOMY . '_add_form_fields', [ __CLASS__, 'render_add_field' ] );
add_action( self::TAXONOMY . '_edit_form_fields', [ __CLASS__, 'render_edit_field' ], 10, 1 );
add_action( 'created_' . self::TAXONOMY, [ __CLASS__, 'save' ] );
add_action( 'edited_' . self::TAXONOMY, [ __CLASS__, 'save' ] );
}

/**
* Help text shared by both screens.
*/
private static function description(): string {
return __( 'Optional. Shown as a badge on this category\'s checkout card, e.g. "Best Value" or "Most Popular". Leave empty for no badge.', 'yourpropfirm' );
}

/**
* "Add new category" screen — stacked .form-field layout.
*/
public static function render_add_field(): void {
?>
<div class="form-field term-ypf-badge-wrap">
<label for="ypf_term_badge"><?php esc_html_e( 'Checkout Badge', 'yourpropfirm' ); ?></label>
<input type="text" name="ypf_term_badge" id="ypf_term_badge" value="" placeholder="<?php esc_attr_e( 'e.g. Best Value', 'yourpropfirm' ); ?>" />
<p><?php echo esc_html( self::description() ); ?></p>
</div>
<?php
wp_nonce_field( 'ypf_save_term_badge', 'ypf_term_badge_nonce' );
}

/**
* "Edit category" screen — table-row layout.
*
* @param WP_Term $term The category being edited.
*/
public static function render_edit_field( $term ): void {
$value = get_term_meta( $term->term_id, self::META_KEY, true );
?>
<tr class="form-field term-ypf-badge-wrap">
<th scope="row"><label for="ypf_term_badge"><?php esc_html_e( 'Checkout Badge', 'yourpropfirm' ); ?></label></th>
<td>
<input type="text" name="ypf_term_badge" id="ypf_term_badge" value="<?php echo esc_attr( $value ); ?>" placeholder="<?php esc_attr_e( 'e.g. Best Value', 'yourpropfirm' ); ?>" />
<p class="description"><?php echo esc_html( self::description() ); ?></p>
</td>
</tr>
<?php
wp_nonce_field( 'ypf_save_term_badge', 'ypf_term_badge_nonce' );
}

/**
* Persist on create + edit. No-ops for programmatic term creation
* (e.g. the seed) where our nonce is absent — the seed writes the meta itself.
*
* @param int $term_id The category term ID.
*/
public static function save( $term_id ): void {
if (
! isset( $_POST['ypf_term_badge_nonce'] )
|| ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['ypf_term_badge_nonce'] ) ), 'ypf_save_term_badge' )
) {
return;
}
if ( ! current_user_can( 'manage_product_terms' ) && ! current_user_can( 'manage_categories' ) ) {
return;
}
$badge = isset( $_POST['ypf_term_badge'] ) ? sanitize_text_field( wp_unslash( $_POST['ypf_term_badge'] ) ) : '';
update_term_meta( $term_id, self::META_KEY, $badge );
}
}
142 changes: 142 additions & 0 deletions setup_guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# YourPropFirm UI Addon — Production Setup Guide

This add-on replaces the YourPropFirm checkout with the **FUNDEDBIT 2-step design**
(Challenge → Information). It is a **pure override layer**: it styles and re-arranges
the checkout the main plugin already renders. **It never modifies the main plugin** —
everything below is standard WooCommerce / YourPropFirm configuration plus one small
admin field this add-on adds.

> **Requirement:** the **YourPropFirm Plugin** must be installed and active. If it isn't,
> the add-on shows an admin notice and does nothing.

---

## 1. Install

1. Upload & activate the **YourPropFirm UI Addon** plugin (alongside the main plugin).
2. That's it — the checkout (`/checkout/`) is automatically restyled. No settings page
for the add-on itself.

The compiled stylesheet (`dist/css/checkout.css`) is committed and shipped — you do **not**
need Node/Tailwind in production. (Only rebuild if you change `src/css/checkout.css`; see
[Development](#development).)

---

## 2. Product structure (how Step 1 is built)

Step 1 ("Choose Your Challenge") is driven **entirely by your WooCommerce categories and
products** — nothing is hardcoded. The model is:

| Design element | Comes from | Where you set it |
|---|---|---|
| **Evaluation Type** card (e.g. "1-Step") | a Product **Category** name | Products → Categories |
| Card **subtitle** ("Single Phase Evaluation") | the Category **Description** | Products → Categories → Description |
| Card **badge** ("Best Value" / "Most Popular") | the Category **Checkout Badge** | Products → Categories → **Checkout Badge** (added by this add-on) |
| **Account Balance** pill (e.g. "$100,000") | a **Product's Account Size** | the product → Product data → **Account Size** |
| Balance **currency** ($, €, …) | the **Product's Account Currency** | the product → **Account Currency** |
| **Price** (Base / Total) | the **Product price** | the product → Regular price |
| **Trading Platform** options | the product's **Trading Options** | the product → Trading Options |

**So, to add an evaluation type:** create a product **Category** (name + description + badge),
then add one **Product per account size** inside it (set Account Size, Account Currency,
Trading Options, Program, and price on each).

Everything is live: rename a category, change a description/badge, add a product, change a
price — the checkout reflects it (see the [cache note](#notes--gotchas)).

---

## 3. Checkout settings

**WP Admin → YourPropFirm → Product Setup:**

- **Enable Product Selection** — ✅
- **Product Categories** — select your evaluation-type categories (these become the cards)
- **Display Product as Radio Buttons** — ✅ (renders the account-size **cards**; turn off for a dropdown)
- **Display Account Size** — ✅ (shows the account balance instead of the product name)
- *(Optional)* **Overwrite Product Category Label** → level 0 = `Select Evaluation Type`

**YourPropFirm → General Settings:**

- **Terms of Service Link** and **Privacy Policy Link** — set these; the consent text on
Step 2 links to them.

---

## 4. Badges (the "Checkout Badge" field)

This add-on adds a **Checkout Badge** field to the category editor:

> **Products → Categories → (edit a category) → Checkout Badge**

Type e.g. `Best Value` or `Most Popular` and Update. Leave empty for no badge. It also
appears on the **Add new category** screen.

---

## 5. Payment

The checkout uses **whatever payment gateways you enable in WooCommerce** — nothing is
hardcoded to a specific provider.

- Enable gateways in **WooCommerce → Settings → Payments** (Stripe, bank transfer, Confirmo,
NMI, …).
- Step 2's **Payment method** dropdown is populated **dynamically** from your enabled gateways.
- Selecting a gateway renders **that provider's own fields** (e.g. Stripe's card form).
- **Proceed to Payment** places the order through the selected gateway via WooCommerce's
native checkout — the add-on does no payment processing of its own.

No gateway-specific configuration is needed in the add-on.

---

## 6. Terms & conditions

The design uses **consent text** ("By placing your order, you agree to our Terms / Privacy
Policy") instead of a checkbox. The form submits a hidden, always-accepted `terms` field so
the main plugin's terms validation passes. Just make sure the **TOS / Privacy links** are set
(Section 3).

---

## 7. Currency model (important)

Two **independent** currencies, by design:

- **Account balance** (the pills + the summary's *Account* row) → the **product's Account
Currency** (e.g. a `$100,000` USD account).
- **Price** (*Base Price / Sub Total / Total*, and the order) → the **WooCommerce store
currency** (WooCommerce → Settings → General → Currency).

So a `$100,000` (USD) account can be sold for `€489` (EUR store) — the account size shows `$`,
the price shows `€`. This is intentional and correct.

---

## Notes & gotchas

- **Caching:** the main plugin caches the checkout data for ~5 minutes. After editing
products/categories, changes may take up to 5 minutes (or one extra reload) to appear.
- **Order line-item names** are a snapshot taken at purchase (standard WooCommerce) — renaming
a product later does not change names on existing orders.
- The add-on overrides templates only when a matching file exists under
`templates/woocommerce/`; anything else falls through to the main plugin unchanged.

---

## Development

Only needed if you edit styles/markup in this repo.

- **Rebuild CSS** after editing `src/css/checkout.css`:
```bash
cd build && npm run build # outputs dist/css/checkout.css
```
- **Local test data:** `local-dev/seed-category-demo.php` builds a category-driven demo
(eval categories + account-size products). Run it in your WP-CLI/container:
```bash
wp eval-file wp-content/plugins/yourpropfirm-ui-addon/local-dev/seed-category-demo.php
```
- The add-on is **add-on only** — never edit the main plugin to make a change work; it must
function against the stock main plugin.
2 changes: 2 additions & 0 deletions yourpropfirm-ui-addon.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
define( 'YOURPROPFIRM_UI_ADDON_URL', plugin_dir_url( __FILE__ ) );

require_once YOURPROPFIRM_UI_ADDON_DIR . 'includes/class-ypf-ui-addon-hooks.php';
require_once YOURPROPFIRM_UI_ADDON_DIR . 'includes/class-ypf-ui-addon-category-badge.php';

/**
* Boot the add-on after all plugins are loaded.
Expand All @@ -36,4 +37,5 @@
}

YPF_UI_Addon_Hooks::init();
YPF_UI_Addon_Category_Badge::init();
}, 1000 );