| 20 |
20 |
# l'API REST reste servie via la forme ?rest_route= (ex. colorantic.com). |
| 21 |
21 |
_use_rest_route = False |
| 22 |
22 |
|
|
23 |
+ # Vieux WooCommerce (< 6.4) : la Store API n'est pas versionnée — |
|
24 |
+ # /wc/store/products répond mais /wc/store/v1/products donne rest_no_route |
|
25 |
+ # (ex. magillhats.com, restauré sur une vieille sauvegarde). Vide = sans /v1. |
|
26 |
+ _api_version = "v1" |
|
27 |
+ |
| 23 |
28 |
def _store_api_url(self, path: str, query: str = "") -> str: |
| 24 |
29 |
"""URL Store API : /wp-json/wc/store/v1/<path> ou ?rest_route= en secours.""" |
|
30 |
+ ver = f"{self._api_version}/" if self._api_version else "" |
| 25 |
31 |
if self._use_rest_route: |
| 26 |
32 |
sep = "&" if query else "" |
| 27 |
|
− return f"{self.base}/?rest_route=/wc/store/v1/{path}{sep}{query}" |
|
33 |
+ return f"{self.base}/?rest_route=/wc/store/{ver}{path}{sep}{query}" |
| 28 |
34 |
sep = "?" if query else "" |
| 29 |
|
− return f"{self.base}/wp-json/wc/store/v1/{path}{sep}{query}" |
|
35 |
+ return f"{self.base}/wp-json/wc/store/{ver}{path}{sep}{query}" |
| 30 |
36 |
|
| 31 |
37 |
def _get_items(self, url: str): |
| 32 |
38 |
"""JSON direct, sinon Scrapfly (Cloudflare & cie) en dernier recours.""" |
|
39 |
+ import time as _time |
| 33 |
40 |
try: |
| 34 |
|
− r = self.get(url) |
|
41 |
+ for _attempt in range(8): |
|
42 |
+ try: |
|
43 |
+ r = self.get(url) |
|
44 |
+ break |
|
45 |
+ except Exception as exc508: |
|
46 |
+ code = getattr(getattr(exc508, "response", None), "status_code", None) |
|
47 |
+ # hébergement à bout de ressources (CloudLinux « Resource Limit |
|
48 |
+ # Is Reached » 508 / « Insufficient Storage » 507, ex. |
|
49 |
+ # magillhats.com) : intermittent — ~1 requête sur 7 passe, |
|
50 |
+ # indépendant de l'IP; réessayer brièvement plutôt qu'échouer |
|
51 |
+ if code in (507, 508) and _attempt < 7: |
|
52 |
+ _time.sleep(3) |
|
53 |
+ continue |
|
54 |
+ raise |
| 35 |
55 |
try: |
| 36 |
56 |
return r.json() |
| 37 |
57 |
except ValueError: |
| 331 |
351 |
try: |
| 332 |
352 |
items = self._get_items(self._store_api_url("products", f"per_page=100&page={page}")) |
| 333 |
353 |
except Exception as exc: |
| 334 |
|
− if page == 1 and not self._use_rest_route: |
|
354 |
+ if page != 1: |
|
355 |
+ break |
|
356 |
+ items = None |
|
357 |
+ if self._api_version: |
|
358 |
+ # vieux WooCommerce (< 6.4) : Store API non versionnée |
|
359 |
+ # /wc/store/products, la route /v1/ donne rest_no_route — |
|
360 |
+ # tenter quel que soit l'échec, un 508 intermittent peut |
|
361 |
+ # masquer le 404 (ex. magillhats.com) |
|
362 |
+ self._api_version = "" |
|
363 |
+ try: |
|
364 |
+ items = self._get_items(self._store_api_url("products", f"per_page=100&page={page}")) |
|
365 |
+ except Exception: |
|
366 |
+ self._api_version = "v1" |
|
367 |
+ if items is None and not self._use_rest_route: |
| 335 |
368 |
# chemin /wp-json/ bloqué par l'hébergeur ? retenter via ?rest_route= |
| 336 |
369 |
self._use_rest_route = True |
| 337 |
370 |
try: |
| 338 |
371 |
items = self._get_items(self._store_api_url("products", f"per_page=100&page={page}")) |
| 339 |
372 |
except Exception: |
| 340 |
373 |
self._use_rest_route = False |
| 341 |
|
− first_page_exc = exc |
| 342 |
|
− break |
| 343 |
|
− else: |
| 344 |
|
− if page == 1: |
| 345 |
|
− first_page_exc = exc |
|
374 |
+ if items is None: |
|
375 |
+ first_page_exc = exc |
| 346 |
376 |
break |
| 347 |
377 |
if not isinstance(items, list) or not items: |
| 348 |
378 |
break |
| 349 |
379 |
|