Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
28.57% covered (danger)
28.57%
2 / 7
14.29% covered (danger)
14.29%
1 / 7
20.00% covered (danger)
20.00%
1 / 5
33.33% covered (danger)
33.33%
1 / 3
CRAP
n/a
0 / 0
monokulo_init_gateway_class
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
monokulo_add_gateway_class
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
monokulo_render_reconnect_notice
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2/**
3 * Plugin Name:       Monokulo for WooCommerce
4 * Plugin URI:        https://github.com/monokulo/scanner
5 * Description:       Accept Monero at checkout via Monokulo, the hosted,
6 *                     non-custodial payment gateway built on scanner.
7 *                     No spend key ever touches this server or ours - only a
8 *                     view key, used to watch for incoming payments.
9 * Version:            0.1.0
10 * Requires at least:  6.4
11 * Requires PHP:       8.1
12 * Requires Plugins:   woocommerce
13 * WC requires at least: 8.0
14 * Author:             Monokulo
15 * Author URI:         https://github.com/monokulo
16 * License:            GPL-2.0-or-later
17 * License URI:        https://www.gnu.org/licenses/gpl-2.0.html
18 * Text Domain:         monokulo
19 * Domain Path:         /languages
20 *
21 * @package Monokulo
22 */
23
24// Exit if accessed directly - this file is a WordPress plugin entry point,
25// never meant to be loaded outside a WordPress bootstrap. Every other PHP
26// file in this plugin repeats this same guard for the same reason: WordPress
27// plugin directories are web-servable by default on many hosts, and without
28// this guard a request straight to this file's URL would execute arbitrary
29// plugin bootstrap code (harmless here, but the convention exists precisely
30// because it *isn't* always harmless across the plugin ecosystem).
31if ( ! defined( 'ABSPATH' ) ) {
32    exit;
33}
34
35/**
36 * WBS 1.5.1 scope, deliberately: registration only. This bootstrap file's
37 * entire job is making "Monero (via Monokulo)" appear in WooCommerce's
38 * list of registered payment gateways - nothing here talks to the engine yet
39 * (that's 1.5.2's `process_payment()`), and nothing here makes the gateway
40 * enabled by default (also correct per the WBS's own stated outcome: "disabled
41 * state is fine at this step"). Every actual payment decision still lives in
42 * the Rust engine (`scanner`) per `docs/WOOCOMMERCE_ROADMAP.md` Stage 7's
43 * "PHP is a thin adapter, not a second implementation of anything" framing -
44 * this file, and the gateway class it loads, are deliberately the thinnest
45 * possible WordPress-side shim over that engine, not a growing PHP business
46 * layer.
47 */
48
49/**
50 * Loads the gateway class and registers it with WooCommerce.
51 *
52 * Deferred to the `plugins_loaded` hook rather than run at the top level of
53 * this file for a concrete reason, not just convention: `WC_Gateway_Monokulo`
54 * (in includes/class-wc-gateway-monokulo.php) `extends WC_Payment_Gateway`,
55 * a class WooCommerce itself defines. WordPress loads plugins in an
56 * unspecified order relative to each other, so if this plugin happens to load
57 * before WooCommerce does, `class WC_Payment_Gateway` wouldn't exist yet and
58 * the `extends` would be a fatal error. `plugins_loaded` is the first hook
59 * every active plugin is guaranteed to have already been `require`d by, so by
60 * the time this callback runs, WooCommerce's own classes are available
61 * regardless of which plugin's row in `wp_options` happened to load first.
62 * The `Requires Plugins: woocommerce` header above (a WordPress 6.5+
63 * mechanism) additionally stops this plugin from activating at all if
64 * WooCommerce isn't installed, but that only prevents *activation* - it
65 * doesn't reorder *load* order between two already-active plugins, so this
66 * hook is still the right guard even with that header present.
67 */
68function monokulo_init_gateway_class() {
69    if ( ! class_exists( 'WC_Payment_Gateway' ) ) {
70        // WooCommerce isn't active. Fail silently rather than fatal - the
71        // `Requires Plugins` header (WP 6.5+) already stops a fresh activation
72        // in this state, but an older WordPress core, or WooCommerce being
73        // deactivated *after* this plugin was already active, both reach this
74        // function without that guard having fired. Nothing downstream of this
75        // early return runs, so there's nothing left to register.
76        return;
77    }
78
79    require_once __DIR__ . '/includes/class-wc-gateway-monokulo.php';
80}
81add_action( 'plugins_loaded', 'monokulo_init_gateway_class' );
82
83/**
84 * Adds `WC_Gateway_Monokulo` to WooCommerce's list of available gateway
85 * classes via the standard `woocommerce_payment_gateways` filter - this is
86 * the actual registration mechanism WooCommerce documents for third-party
87 * gateways (WooCommerce itself iterates this filter's return value and
88 * instantiates every class name / object in it), confirmed against
89 * WooCommerce's own `WC_Payment_Gateways::init()` source
90 * (`class-wc-payment-gateways.php`) rather than assumed from memory - see
91 * this plugin's `tests/GatewayRegistrationTest.php` for the reasoning
92 * behind exactly which of WooCommerce's own two gateway-listing methods this
93 * plugin's test asserts against, and why.
94 *
95 * @param string[] $gateways Fully-qualified class names (or gateway instances)
96 *                           WooCommerce will offer at checkout.
97 * @return string[] The same list, with this plugin's gateway appended.
98 */
99function monokulo_add_gateway_class( $gateways ) {
100    $gateways[] = 'WC_Gateway_Monokulo';
101    return $gateways;
102}
103add_filter( 'woocommerce_payment_gateways', 'monokulo_add_gateway_class' );
104
105/**
106 * Tells WooCommerce managers, on every admin screen, when this store was
107 * connected by an older plugin version and must reconnect before it can
108 * take Monero payments again (see `WC_Gateway_Monokulo::CONNECTION_VERSION`).
109 * Hooked here rather than in the gateway's constructor so it shows whether
110 * or not WooCommerce builds its gateways on the current request.
111 */
112function monokulo_render_reconnect_notice() {
113    if ( class_exists( 'WC_Gateway_Monokulo' ) ) {
114        WC_Gateway_Monokulo::render_reconnect_notice();
115    }
116}
117add_action( 'admin_notices', 'monokulo_render_reconnect_notice' );