summaryrefslogtreecommitdiffstats
path: root/README.md
blob: be2a9f325bd9f9cad2437b0831c275b03b2cd697 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# CEP Autofill for WooCommerce

Fills the WooCommerce checkout address from the CEP the shopper types. Street,
neighbourhood, city and state, from official Correios data (DNE) via the
[public API at cep.is](https://cep.is).

Works on **both** WooCommerce checkouts — the Cart/Checkout Blocks and the
classic `[woocommerce_checkout]` shortcode — see
[Supported checkouts](#supported-checkouts).

No Composer, no npm, no build step: the PHP client and the JavaScript widget
are bundled in the plugin.

## Install

Download the `.zip` from `dist/` (or run `make build`), then **Plugins → Add
New → Upload Plugin** in WordPress. Activate it; WooCommerce must be active
first.

By default the shopper's browser talks to cep.is directly, so there is nothing
to configure and no key to obtain.

Requires WordPress 6.9 or newer, PHP 8.1 or newer, and WooCommerce.

## Settings

**WooCommerce → Settings → CEP autofill.**

| setting                    | default  | what it does                                                                        |
| -------------------------- | -------- | ----------------------------------------------------------------------------------- |
| **Autofill**               | on       | look the address up while the shopper types                                          |
| **Lookups go through**     | browser  | the browser straight to cep.is, or this site's REST API                              |
| **Fields already filled**  | keep     | keep what the shopper typed / only fill empty fields / always overwrite              |
| **House number**           | on       | move the cursor to the house-number field after a hit (classic checkout)             |
| **API address**            | cep.is   | point at your own instance of the API                                                |

### Lookups go through

**The browser (default).** One cross-origin GET against a Cloudflare edge
cache. No PHP runs, nothing is billed to the store, and the answer arrives in
about twenty milliseconds.

**This site.** The browser calls
`/wp-json/cepis/v1/lookup/{token}/{cep}` instead, and PHP calls cep.is through
`wp_remote_get()`. Choose this when a Content-Security-Policy on the checkout
forbids external requests, or when you want the answers cached server-side.
Answers are kept in transients: a hit for a week, since the database behind the
API is regenerated fortnightly and a week is half a refresh cycle; a "does not
exist" for a day, since a CEP absent today can appear in the next release.

The route carries a short-lived token derived from the site's salts, and
answers `403` without one. It is registered only while this mode is on.

### Fields already filled in

`keep` — the default — fills empty fields, replaces values this plugin wrote
itself, and leaves anything the shopper typed alone, so correcting a street by
hand survives the next CEP.

The state is the exception and is always replaced: the CEP decides it, and
WooCommerce pre-selects the store's own state on a fresh checkout.

## Supported checkouts

Both, and both verified in a real browser against a real store.

| checkout                                       | supported | how                                                                         |
| ---------------------------------------------- | --------- | --------------------------------------------------------------------------- |
| **Cart/Checkout Blocks** (the default since WooCommerce 8.3) | yes | reads and writes the `wc/store/cart` data store; no DOM is touched   |
| **Classic** `[woocommerce_checkout]`           | yes       | the widget fills the fields directly and announces progress in an `aria-live` region |

On the block checkout the fields are React-controlled, so the plugin drives the
official `setShippingAddress` / `setBillingAddress` actions and reports failures
through the checkout's own notice area. On the classic checkout the status
message appears under the CEP field, styleable through
`.cepis-autofill-status[data-cepis-state="…"]`.

Both fill billing and shipping. The cart block's shipping calculator is not
covered.

Verified on WordPress 7.0.2, WooCommerce 10.9.4, PHP 8.3. `Requires at least`
is declared as 6.9 because that is what WooCommerce 10.x itself requires; older
WordPress was not tested.

## Brazilian address fields

WooCommerce has no house-number and no neighbourhood field. When
[Brazilian Market on WooCommerce](https://wordpress.org/plugins/woocommerce-extra-checkout-fields-for-brazil/)
adds `billing_number` and `billing_neighborhood` to the classic checkout, this
plugin fills the neighbourhood and moves the cursor to the number. When they
are absent it fills what exists and does nothing else — the neighbourhood is
**not** written into `address_2`, which in WooCommerce means "apartment, suite,
unit" and would produce a wrong shipping label.

The block checkout has no such fields and no plugin currently adds them. A
store that registers its own with
`woocommerce_register_additional_checkout_field()` can map it:

```php
add_filter( 'cepis_woocommerce_blocks_fields', function ( $fields ) {
	$fields['bairro'] = 'my-plugin/neighborhood';

	return $fields;
} );
```

The classic equivalent is `cepis_woocommerce_classic_fields`, which takes CSS
selectors per address section, for themes and one-page-checkout plugins that
rename the fields. `cepis_woocommerce_messages` overrides what the shopper is
told.

## Development

```sh
make            # list the targets
make test       # stand a store up in Docker and drive the checkout in Chromium
make lint       # php -l, prettier --check, and phpcs when installed
make format     # apply prettier (writes)
make build      # produce dist/cepis-woocommerce-0.1.0.zip
make check      # lint, then test, then build
make clean      # remove build output and throw the test containers away
```

`make test` needs Docker and `bun`. It brings up WordPress, MySQL and WP-CLI
from `test/compose.yml`, installs and configures WooCommerce, and drives both
checkouts with Playwright's Chromium against a fake cep.is on the host, so no
test touches the network. Install Chromium with `bunx playwright install
chromium`, or point `CEPIS_CHROMIUM` at an existing binary.

`make phpcs` fetches PHP_CodeSniffer and the WordPress standard into `.phpcs/`;
`make lint` picks them up automatically once they are there.

### Refreshing the bundled dependencies

`lib/cepis/` is the [PHP client](https://cep.is) and
`assets/js/cepis-autofill.min.js` is the
[autofill widget](https://cep.is), both copied in rather than installed,
because a WordPress site is deployed by copying files and never runs
`composer install`.

```sh
tools/update-vendor.sh ../cepis-php ../cepis-autofill
```

That rebuilds the widget, copies both in, and leaves you a diff to review.

## Licence

ISC. See [LICENSE](LICENSE).