'Springfield Elementary', // required * 'amount' => '25.00', // required (string) * 'currency' => 'USD', // optional, default USD * 'items' => [ // optional line items * ['name' => 'Lunch x5', 'quantity' => '5', * 'unit_amount' => ['currency_code' => 'USD', 'value' => '5.00']], * ], * 'buyer_email' => 'parent@school.com', // optional — prefills PayPal login * 'page_type' => 'checkout', // checkout | product-detail | cart * 'order_api_url' => '/sm/order-api.php', // URL to order-api.php * 'success_url' => '/payment-success', // redirect after capture * 'cancel_url' => '', // optional — redirect on cancel * ]; * require_once '/path/to/ppp/paypal-checkout-widget.php'; * * After the widget, add your other payment options (card, etc.) — they will appear below the divider. */ if (!isset($ppCheckout) || !is_array($ppCheckout)) { throw new RuntimeException('$ppCheckout array must be set before including paypal-checkout-widget.php'); } // -- Resolve merchant ID ------------------------------------------------------- $_ppConfig = require __DIR__ . '/config.php'; $_ppMerchantId = null; $_ppSchoolReady = true; $_ppMerchantsFile = __DIR__ . '/data/school_merchants.json'; if (file_exists($_ppMerchantsFile)) { $_ppMerchants = json_decode(file_get_contents($_ppMerchantsFile), true) ?: []; $_ppRecord = $_ppMerchants[$ppCheckout['school_name']] ?? null; if ($_ppRecord) { $_ppMerchantId = $_ppRecord['merchant_id'] ?? null; if (isset($_ppRecord['paypal_ready'])) { $_ppSchoolReady = (bool)$_ppRecord['paypal_ready']; } } } // Silently skip rendering if school is not connected or not ready if (!$_ppMerchantId || !$_ppSchoolReady) { return; } // -- FraudNet correlation ID (one per session) --------------------------------- if (session_status() !== PHP_SESSION_ACTIVE) { // Session started by the main app — we just read from it } if (empty($_SESSION['pp_fraudnet_id'])) { $_SESSION['pp_fraudnet_id'] = bin2hex(random_bytes(16)); } $_ppFraudnetId = $_SESSION['pp_fraudnet_id']; // -- Params -------------------------------------------------------------------- $_ppClientId = $_ppConfig['client_id']; $_ppCurrency = strtoupper($ppCheckout['currency'] ?? 'USD'); $_ppPageType = $ppCheckout['page_type'] ?? 'checkout'; // PayPal's SDK only accepts a fixed set of data-page-type values; an unknown // value makes the SDK throw "Invalid page type" and no buttons render. Map // common aliases and fall back to 'checkout' for anything unrecognised. $_ppValidPageTypes = [ 'home', 'category', 'product-listing', 'search-results', 'product-details', 'cart', 'mini-cart', 'checkout', 'order-review', 'order-confirmation', 'account', 'profile', 'blog', 'about', 'contact', 'landing', 'marketing', 'help', 'search', 'unknown', ]; $_ppPageTypeAliases = ['product-detail' => 'product-details', 'product' => 'product-details']; $_ppPageType = $_ppPageTypeAliases[$_ppPageType] ?? $_ppPageType; if (!in_array($_ppPageType, $_ppValidPageTypes, true)) { $_ppPageType = 'checkout'; } $_ppApiUrl = $ppCheckout['order_api_url'] ?? './order-api.php'; $_ppSuccessUrl = $ppCheckout['success_url'] ?? ''; $_ppCancelUrl = $ppCheckout['cancel_url'] ?? ''; $_ppAmount = $ppCheckout['amount']; $_ppItems = json_encode($ppCheckout['items'] ?? [], JSON_UNESCAPED_UNICODE); $_ppSchool = $ppCheckout['school_name']; $_ppEmail = $ppCheckout['buyer_email'] ?? ''; // Optional — forwarded to order-api.php on capture so the payment can be booked // to the buyer's account. Defaults to 0 (e.g. demos) where there's no app user. $_ppUserNum = (int)($ppCheckout['user_num'] ?? 0); $_ppEnv = strtolower($_ppConfig['env'] ?? 'sandbox'); // Pay Later promo messaging — the SDK's messaging component has thrown // unhandled "PAGE_TYPE" exceptions in some environments. Set // 'paylater_messaging' => false in config.php to exclude the component and // its render entirely (buttons/wallets are unaffected). // Defaults to FALSE: the SDK's messaging component throws an unhandled // "Cannot set properties of undefined (setting 'PAGE_TYPE')" that aborts the // SDK onload handler and stops the wallet buttons initialising. Opt in // explicitly with 'paylater_messaging' => true once that SDK bug is resolved — // a config file that predates this key must not silently re-enable the crash. $_ppMessagesOn = (bool)($_ppConfig['paylater_messaging'] ?? false); // -- JS SDK URL ---------------------------------------------------------------- $_ppSdkUrl = 'https://www.paypal.com/sdk/js' . '?client-id=' . urlencode($_ppClientId) . '&merchant-id=' . urlencode($_ppMerchantId) . '¤cy=' . $_ppCurrency . '&intent=capture' . '&commit=true' . '&enable-funding=venmo,paylater' . '&components=buttons' . ($_ppMessagesOn ? ',messages' : '') . ',applepay,googlepay'; // -- Unique widget ID (allows multiple widgets on same page) ------------------- // NOTE: no hyphens — this id is interpolated into the pp_initButtons_ // JavaScript function name, and hyphens would make that an invalid identifier // (JS would read them as minus operators ? SyntaxError). It's also used for DOM // ids / CSS selectors, where an alphanumeric id is perfectly valid. $_ppWidgetId = 'ppwidget' . substr(md5($_ppSchool . $_ppAmount), 0, 8); ?>
We accept PayPal & Venmo
Loading payment options…
or pay another way
definition (ReferenceError, widget stuck on "Loading payment options…"). Emitting the SDK tag last guarantees the handlers exist before onload/onerror can possibly fire. -- */ ?>