/**
  * Generate article.json contents. It does so by looping though all data,
  * generating valid JSON and adding attachments to workspace/tmp directory.
  *
  * @return string The generated JSON for article.json
  * @access private
  */
 private function generate_json()
 {
     // Base JSON
     $json = array('version' => '1.1', 'identifier' => 'post-' . $this->content_id(), 'language' => 'en', 'title' => $this->content_title());
     // Builders
     $json['documentStyle'] = $this->build_article_style();
     foreach ($this->builders as $name => $builder) {
         $arr = $builder->to_array();
         if ($arr) {
             $json[$name] = $arr;
         }
     }
     $json = apply_filters('apple_news_generate_json', $json, $this->content_id());
     $json = json_encode($json);
     // Check the JSON for unicode errors.
     // For now, we'll assume that multiple unicode characters in sequence
     // containing the  (\u00C2) indicate a problem as that has been the
     // most common indication of the issue.
     preg_match_all('/(\\\\u[0-9a-fA-F]{4}){2,}/', $json, $matches);
     if (!empty($matches[0])) {
         // Get a unique list of character sequences
         $character_sequences = array_unique($matches[0]);
         foreach ($character_sequences as &$sequence) {
             // Convert back to a display format
             $sequence = json_decode('{ "value":"' . $sequence . '"}');
             $sequence = $sequence->value;
         }
         $this->workspace->log_error('json_errors', sprintf(__('Invalid unicode character sequences were found that could cause display issues on Apple News: %s', 'apple-news'), implode(', ', $character_sequences)));
     }
     return $json;
 }
 /**
  * Given a node, returns an array of all the components inside that node. If
  * the node is a component itself, returns an array of only one element.
  *
  * @param DomNode $node
  * @return array
  * @static
  * @access public
  */
 public static function get_components_from_node($node)
 {
     $result = array();
     foreach (self::$components as $shortname => $class) {
         $matched_node = $class::node_matches($node);
         // Nothing matched? Skip to next match.
         if (!$matched_node) {
             continue;
         }
         // Did we match several components? If so, a hash is returned. Both the
         // body and heading components can returns this, in the case they find
         // non-markdown-able elements inside.
         if (is_array($matched_node)) {
             foreach ($matched_node as $base_component) {
                 $result[] = self::get_component($base_component['name'], $base_component['value']);
             }
             return $result;
         }
         // We matched a single node
         $html = $node->ownerDocument->saveXML($matched_node);
         $result[] = self::get_component($shortname, $html);
         return $result;
     }
     // Nothing found. Maybe it's a container element?
     if ($node->hasChildNodes()) {
         foreach ($node->childNodes as $child) {
             $result = array_merge($result, self::get_components_from_node($child, $node));
         }
         // Remove all nulls from the array
         $result = array_filter($result);
     }
     // If nothing was found, log this as a component error by recording the node name.
     // Only record components with a tagName since otherwise there is nothing to report.
     // Others nodes without a match are almost always just stray empty text nodes
     // that are always safe to remove. Paragraphs should also be ignored for this reason.
     if (empty($result) && (!empty($node->tagName) && 'p' !== $node->tagName)) {
         self::$workspace->log_error('component_errors', $node->tagName);
     }
     return $result;
 }