PluginProbe
GiveWP – Donation Plugin and Fundraising Platform / 4.17.0
GiveWP – Donation Plugin and Fundraising Platform v4.17.0
4.17.0 4.16.9 4.16.8.1 4.16.8 4.16.7.2 4.16.7.1 4.16.7 4.16.6.1 4.16.6 4.16.5.1 4.16.5 4.16.4 4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 All 256 releases
← All changes | src/Framework/Routes/Router.php +121 -0 4.16.7.1 → 4.17.0 View file →
@@ -3,15 +3,28 @@
3 3 namespace Give\Framework\Routes;
4 4
5 5 use Give\Framework\Exceptions\Primitives\InvalidArgumentException;
6 6 use Give\Helpers\Language;
7 +use WP;
7 8
8 9 use function is_callable;
9 10 use function str_contains;
10 11
12 +/**
13 + * @since 4.17.0 Add script routes served from a plugin-controlled URL
14 + * @since 3.0.0
15 + */
11 16 class Router
12 17 {
13 18 /**
19 + * Base path segment for pretty script URLs. Fixed on purpose: these URLs are
20 + * pasted into third-party sites, so they must not follow any setting.
21 + *
22 + * @since 4.17.0
23 + */
24 + protected string $scriptBase = 'give';
25 +
26 + /**
14 27 * @since 3.0.0
15 28 * @param string $uri
16 29 * @param string|callable $action
17 30 * @param string $method
@@ -33,8 +46,116 @@
33 46 */
34 47 public function post(string $uri, $action, $method = '__invoke')
35 48 {
36 49 $this->addRoute('POST', $method, $uri, $action);
50 + }
51 +
52 + /**
53 + * Serve a built script from a URL the plugin controls, so the file can move
54 + * without breaking URLs already pasted elsewhere. Matching happens on
55 + * parse_request against the path WordPress already resolved, so no rewrite
56 + * rule is registered and nothing needs flushing. See scriptUrl() for the
57 + * URL shape per permalink setting.
58 + *
59 + * @since 4.17.0
60 + *
61 + * @param string $uri Path below the base, e.g. "embed/donation-form/script.js"
62 + * @param string $file Absolute path to the built script
63 + *
64 + * @return ScriptResponse The response, so callers can chain localize()
65 + */
66 + public function script(string $uri, string $file): ScriptResponse
67 + {
68 + $response = new ScriptResponse($file);
69 +
70 + add_action('parse_request', function (WP $wp) use ($uri, $response) {
71 + $request = $this->scriptRequest($wp, $uri);
72 +
73 + if ($request === null) {
74 + return;
75 + }
76 +
77 + $response->send($request);
78 + });
79 +
80 + return $response;
81 + }
82 +
83 + /**
84 + * Pretty permalinks: /give/{uri}
85 + * Index permalinks: /index.php/give/{uri}
86 + * Plain permalinks: /?givewp-route={uri}
87 + *
88 + * @since 4.17.0
89 + *
90 + * @param array $args Query arguments appended to the URL; the script's localize callable
91 + * receives them at request time.
92 + */
93 + public function scriptUrl(string $uri, array $args = []): string
94 + {
95 + global $wp_rewrite;
96 +
97 + if (!$wp_rewrite->using_permalinks()) {
98 + $url = $this->url($uri);
99 + } else {
100 + $prefix = $wp_rewrite->using_index_permalinks() ? $wp_rewrite->index . '/' : '';
101 + $url = home_url("/{$prefix}{$this->scriptBase}/{$uri}");
102 + }
103 +
104 + if (!$args) {
105 + return $url;
106 + }
107 +
108 + // Appended by hand: add_query_arg() would re-encode the givewp-route value's slashes.
109 + return $url . (strpos($url, '?') === false ? '?' : '&') . http_build_query($args);
110 + }
111 +
112 + /**
113 + * @since 4.17.0
114 + */
115 + public function isScriptRequested(WP $wp, string $uri): bool
116 + {
117 + return $this->scriptRequest($wp, $uri) !== null;
118 + }
119 +
120 + /**
121 + * The request data for a script route when the current request is for it, null otherwise.
122 + * The data is the query string run through give_clean(), minus givewp-route itself, so a
123 + * `?form-id=42` argument arrives as `['form-id' => '42']`. Matching covers the pretty path and
124 + * the givewp-route query var, each with an optional numeric segment before the file name
125 + * (embed/donation-form/42/script.js), which comes back as `id`. The segment exists for caches
126 + * that drop query strings from their key; a query argument is the primary way to pass data
127 + * to a script route.
128 + *
129 + * @since 4.17.0
130 + */
131 + public function scriptRequest(WP $wp, string $uri): ?array
132 + {
133 + $directory = dirname($uri);
134 + $directory = $directory === '.' ? '' : preg_quote($directory, '#') . '/';
135 + $pattern = $directory . '(?:(\d+)/)?' . preg_quote(basename($uri), '#');
136 +
137 + $candidates = [
138 + '#^' . preg_quote($this->scriptBase, '#') . '/' . $pattern . '$#' => (string)$wp->request,
139 + '#^' . $pattern . '$#' => isset($_GET['givewp-route']) ? (string)$_GET['givewp-route'] : '',
140 + ];
141 +
142 + foreach ($candidates as $regex => $subject) {
143 + if ($subject === '' || !preg_match($regex, $subject, $matches)) {
144 + continue;
145 + }
146 +
147 + $request = $this->getDataFromGetRequest();
148 + unset($request['givewp-route']);
149 +
150 + if (!empty($matches[1])) {
151 + $request['id'] = (int)$matches[1];
152 + }
153 +
154 + return $request;
155 + }
156 +
157 + return null;
37 158 }
38 159
39 160 /**
40 161 * @since 3.0.0