| @@ -33,8 +33,18 @@ | ||
| 33 | 33 | * block stored there would be invisible on the page and the write would produce |
| 34 | 34 | * exactly the violation above. Those surfaces have their own FAQ modules, which |
| 35 | 35 | * `get-faq` reads and a human edits in the builder. |
| 36 | 36 | * |
| 37 | + * Oxygen and Breakdance replace `post_content` just as thoroughly and have no | |
| 38 | + * ThinkRank FAQ module, and until #831 the detection did not know them at all: | |
| 39 | + * the refusal never fired, the block was stored, and `will_emit_faqpage()` then | |
| 40 | + * published a FAQPage for questions that are on no page. They are refused for | |
| 41 | + * the same reason as the other three, with a message that sends the author to | |
| 42 | + * the builder's own accordion rather than to a ThinkRank module that does not | |
| 43 | + * exist. `FAQ_Content` now reads that accordion, so the refusal is no longer a | |
| 44 | + * dead end: the questions it holds are reported, and the author edits them where | |
| 45 | + * they live. | |
| 46 | + * | |
| 37 | 47 | * Two properties of the write matter: |
| 38 | 48 | * |
| 39 | 49 | * - **Byte-level editing.** Blocks are located with core's tokenizer and |
| 40 | 50 | * replaced by byte range, so every other block in the post is left exactly as |
| @@ -62,9 +72,9 @@ | ||
| 62 | 72 | */ |
| 63 | 73 | public function __construct() { |
| 64 | 74 | $this->id = 'thinkrank/update-faq'; |
| 65 | 75 | $this->label = __( 'Update ThinkRank FAQ', 'thinkrank' ); |
| 66 | - $this->description = __( 'Add FAQ questions and answers to a post as a visible ThinkRank FAQ block, which also produces FAQPage schema. Use mode "append" to add a block alongside anything already there, or "replace" to remove every ThinkRank FAQ block on the post first. Only posts built with the block editor can be written: a post rendered by Elementor, Bricks or Beaver is refused with unsupported_builder, because a block stored in its content would never be shown and marking up invisible content breaks Google\'s structured data policy. Call get-faq first to see which builder a post uses and what it already asks. Note that Google shows FAQ rich results only for well-known, authoritative government and health websites, so for most sites the value is being quotable by answer engines rather than a rich result.', 'thinkrank' ); | |
| 76 | + $this->description = __( 'Add FAQ questions and answers to a post as a visible ThinkRank FAQ block, which also produces FAQPage schema. Use mode "append" to add a block alongside anything already there, or "replace" to remove every ThinkRank FAQ block on the post first. Only posts built with the block editor can be written: a post rendered by Elementor, Bricks, Beaver, Oxygen or Breakdance is refused with unsupported_builder, because a block stored in its content would never be shown and marking up invisible content breaks Google\'s structured data policy. Call get-faq first to see which builder a post uses and what it already asks. Note that Google shows FAQ rich results only for well-known, authoritative government and health websites, so for most sites the value is being quotable by answer engines rather than a rich result.', 'thinkrank' ); | |
| 67 | 77 | } |
| 68 | 78 | |
| 69 | 79 | /** |
| 70 | 80 | * {@inheritDoc} |
| @@ -200,15 +210,16 @@ | ||
| 200 | 210 | if ( '' !== $builder ) { |
| 201 | 211 | return new \WP_Error( |
| 202 | 212 | 'thinkrank_unsupported_builder', |
| 203 | 213 | sprintf( |
| 204 | - /* translators: %s: page builder name. */ | |
| 205 | - __( 'This post is rendered by %s, which replaces the post content, so a FAQ block written here would never be shown. Add the questions with that builder\'s own ThinkRank FAQ module instead. Marking up content a reader cannot see breaks Google\'s structured data policy.', 'thinkrank' ), | |
| 206 | - $this->builder_label( $builder ) | |
| 214 | + /* translators: %s: why the post cannot be written, naming the builder. */ | |
| 215 | + __( '%s Marking up content a reader cannot see breaks Google\'s structured data policy.', 'thinkrank' ), | |
| 216 | + $this->writable_reason( $builder ) | |
| 207 | 217 | ), |
| 208 | 218 | [ |
| 209 | - 'status' => 422, | |
| 210 | - 'builder' => $builder, | |
| 219 | + 'status' => 422, | |
| 220 | + 'builder' => $builder, | |
| 221 | + 'builder_has_reader' => FAQ_Content::builder_is_readable( $builder ), | |
| 211 | 222 | ] |
| 212 | 223 | ); |
| 213 | 224 | } |
| 214 | 225 | |
| @@ -377,24 +388,8 @@ | ||
| 377 | 388 | return [ |
| 378 | 389 | 'content' => $out . substr( $content, $cursor ), |
| 379 | 390 | 'removed' => count( $spans ), |
| 380 | 391 | ]; |
| 381 | - } | |
| 382 | - | |
| 383 | - /** | |
| 384 | - * A readable name for a builder, for the refusal message. | |
| 385 | - * | |
| 386 | - * @param string $builder Builder key. | |
| 387 | - * @return string | |
| 388 | - */ | |
| 389 | - private function builder_label( string $builder ): string { | |
| 390 | - $labels = [ | |
| 391 | - FAQ_Content::SOURCE_ELEMENTOR => __( 'Elementor', 'thinkrank' ), | |
| 392 | - FAQ_Content::SOURCE_BRICKS => __( 'Bricks', 'thinkrank' ), | |
| 393 | - FAQ_Content::SOURCE_BEAVER => __( 'Beaver Builder', 'thinkrank' ), | |
| 394 | - ]; | |
| 395 | - | |
| 396 | - return $labels[ $builder ] ?? $builder; | |
| 397 | 392 | } |
| 398 | 393 | |
| 399 | 394 | /** |
| 400 | 395 | * The newest revision ID for a post, or 0 when it keeps none. |