| @@ -58,16 +58,35 @@ | ||
| 58 | 58 | ); |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | 61 | /** |
| 62 | - * Purge a specific list of URLs. CF accepts up to 30 per call; | |
| 63 | - * caller should chunk if it has more. | |
| 62 | + * Files sent per `purge_cache` call. | |
| 64 | 63 | * |
| 64 | + * Cloudflare's own limit is higher and varies by plan; 30 is what its | |
| 65 | + * official WordPress plugin chunks at, and staying there keeps the | |
| 66 | + * request body small on hosts with a modest `max_execution_time`. | |
| 67 | + */ | |
| 68 | + private const PURGE_FILES_PER_CALL = 30; | |
| 69 | + | |
| 70 | + /** | |
| 71 | + * Purge a specific list of URLs. | |
| 72 | + * | |
| 73 | + * Sent in chunks, so a list longer than one call still arrives in full. | |
| 74 | + * It used to be truncated to the first 30 instead, and the | |
| 75 | + * caller was told the purge succeeded — so on a site with more than 30 | |
| 76 | + * affected pages the rest silently stayed at the edge. Nothing in the | |
| 77 | + * result said which, because as far as the response was concerned the | |
| 78 | + * call did succeed. | |
| 79 | + * | |
| 80 | + * Stops at the first failure and returns it, rather than carrying on and | |
| 81 | + * reporting the last outcome: the usual reason a chunk fails is the token | |
| 82 | + * or the zone, which the next chunk would hit too. | |
| 83 | + * | |
| 65 | 84 | * @param string[] $urls |
| 66 | 85 | * @return array{ok:bool,status:int,body:array} |
| 67 | 86 | */ |
| 68 | 87 | public static function purge_urls( array $opts, array $urls ): array { |
| 69 | - $urls = array_values( array_filter( array_map( 'strval', $urls ) ) ); | |
| 88 | + $urls = array_values( array_unique( array_filter( array_map( 'strval', $urls ) ) ) ); | |
| 70 | 89 | if ( empty( $urls ) ) { |
| 71 | 90 | return self::fail( 0, 'No URLs supplied.' ); |
| 72 | 91 | } |
| 73 | 92 | $zone = (string) ( $opts['zone_id'] ?? '' ); |
| @@ -73,14 +92,23 @@ | ||
| 73 | 92 | $zone = (string) ( $opts['zone_id'] ?? '' ); |
| 74 | 93 | if ( '' === $zone ) { |
| 75 | 94 | return self::fail( 0, 'Zone ID is empty.' ); |
| 76 | 95 | } |
| 77 | - return self::request( | |
| 78 | - $opts, | |
| 79 | - 'POST', | |
| 80 | - '/zones/' . rawurlencode( $zone ) . '/purge_cache', | |
| 81 | - array( 'files' => array_slice( $urls, 0, 30 ) ) | |
| 82 | - ); | |
| 96 | + | |
| 97 | + $result = array(); | |
| 98 | + foreach ( array_chunk( $urls, self::PURGE_FILES_PER_CALL ) as $chunk ) { | |
| 99 | + $result = self::request( | |
| 100 | + $opts, | |
| 101 | + 'POST', | |
| 102 | + '/zones/' . rawurlencode( $zone ) . '/purge_cache', | |
| 103 | + array( 'files' => $chunk ) | |
| 104 | + ); | |
| 105 | + if ( empty( $result['ok'] ) ) { | |
| 106 | + return $result; | |
| 107 | + } | |
| 108 | + } | |
| 109 | + | |
| 110 | + return $result; | |
| 83 | 111 | } |
| 84 | 112 | |
| 85 | 113 | /** |
| 86 | 114 | * Flip development mode on or off. CF auto-disables it after 3 |