Plugin Directory

Changeset 3455197


Ignore:
Timestamp:
02/06/2026 08:05:35 AM (2 weeks ago)
Author:
contentpen
Message:

add fallback regex-based HTML to Gutenberg conversion for servers without php-xml extension

Location:
contentpen
Files:
6 edited
1 copied

Legend:

Unmodified
Added
Removed
  • contentpen/tags/1.0.8/README.txt

    r3455153 r3455197  
    44Requires at least: 5.8
    55Tested up to: 6.7
    6 Stable tag: 1.0.7
     6Stable tag: 1.0.8
    77Requires PHP: 7.4
    88License: GPLv2 or later
     
    5555== Changelog ==
    5656
     57= 1.0.8 =
     58* Added fallback regex-based conversion for servers without php-xml extension
     59* Fixed critical error on servers missing DOMDocument class
     60
     61= 1.0.7 =
     62* Bug fix for Gutenberg block conversion
     63
     64= 1.0.6 =
     65* Added HTML to Gutenberg block conversion for posts
     66
    5767= 1.0.0 =
    5868* Initial release
     
    6070== Upgrade Notice ==
    6171
    62 = 1.0.0 =
    63 Initial release of ContentPen WordPress plugin.
    64 
    65 = 1.0.7 =
    66 Fixed HTML to Gutenberg block conversion issue.
     72= 1.0.8 =
     73* Added fallback regex-based conversion for servers without php-xml extension
     74* Fixed critical error on servers missing DOMDocument class
  • contentpen/tags/1.0.8/contentpen-plugin.php

    r3455153 r3455197  
    55 * Plugin URI: https://contentpen.ai
    66 * Description: Contentpen is an AI-powered content writing assistant designed to help businesses create, optimize, and publish SEO-friendly blog posts at scale. By combining deep research with your brand's unique voice, Contentpen crafts high-impact articles that outperform your competition.
    7  * Version: 1.0.7
     7 * Version: 1.0.8
    88 * Requires at least: 5.8
    99 * Requires PHP: 7.4
     
    2020}
    2121
    22 define('CONTENTPEN_VERSION', '1.0.7');
     22define('CONTENTPEN_VERSION', '1.0.8');
    2323define('CONTENTPEN_PLUGIN_DIR', plugin_dir_path(__FILE__));
    2424define('CONTENTPEN_PLUGIN_URL', plugin_dir_url(__FILE__));
  • contentpen/tags/1.0.8/includes/class-gutenberg-converter.php

    r3455149 r3455197  
    2727        if (strpos($html, '<!-- wp:') !== false) {
    2828            return $html;
     29        }
     30
     31        // Check if DOMDocument is available (requires php-xml extension)
     32        if (!class_exists('DOMDocument')) {
     33            // Fallback: use regex-based conversion
     34            return self::convert_with_regex($html);
    2935        }
    3036
     
    269275        return "<!-- wp:code -->\n" . $html . "\n<!-- /wp:code -->\n\n";
    270276    }
     277
     278    /**
     279     * Fallback regex-based conversion when DOMDocument is not available.
     280     *
     281     * @param string $html The HTML content to convert.
     282     * @return string The converted Gutenberg block content.
     283     */
     284    private static function convert_with_regex($html)
     285    {
     286        $output = '';
     287
     288        // Pattern to match top-level block elements
     289        $pattern = '/<(p|h[1-6]|ul|ol|blockquote|table|figure|pre)(\s[^>]*)?>.*?<\/\1>/is';
     290
     291        $last_pos = 0;
     292        if (preg_match_all($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
     293            foreach ($matches[0] as $index => $match) {
     294                $full_match = $match[0];
     295                $pos = $match[1];
     296                $tag = strtolower($matches[1][$index][0]);
     297
     298                // Handle any text between matches
     299                if ($pos > $last_pos) {
     300                    $between = trim(substr($html, $last_pos, $pos - $last_pos));
     301                    if (!empty($between) && !preg_match('/^\s*$/', $between)) {
     302                        $output .= self::wrap_paragraph('<p>' . $between . '</p>');
     303                    }
     304                }
     305
     306                // Convert based on tag
     307                switch ($tag) {
     308                    case 'p':
     309                        $output .= self::wrap_paragraph($full_match);
     310                        break;
     311                    case 'h1':
     312                    case 'h2':
     313                    case 'h3':
     314                    case 'h4':
     315                    case 'h5':
     316                    case 'h6':
     317                        $level = (int) substr($tag, 1);
     318                        $output .= self::wrap_heading($full_match, $level);
     319                        break;
     320                    case 'ul':
     321                        $output .= self::wrap_list($full_match, false);
     322                        break;
     323                    case 'ol':
     324                        $output .= self::wrap_list($full_match, true);
     325                        break;
     326                    case 'blockquote':
     327                        $output .= self::wrap_quote($full_match);
     328                        break;
     329                    case 'table':
     330                        $output .= self::wrap_table($full_match);
     331                        break;
     332                    case 'figure':
     333                        if (stripos($full_match, '<img') !== false) {
     334                            $output .= self::wrap_image($full_match);
     335                        } else {
     336                            $output .= $full_match . "\n\n";
     337                        }
     338                        break;
     339                    case 'pre':
     340                        $output .= self::wrap_code($full_match);
     341                        break;
     342                    default:
     343                        $output .= "<!-- wp:html -->\n" . trim($full_match) . "\n<!-- /wp:html -->\n\n";
     344                }
     345
     346                $last_pos = $pos + strlen($full_match);
     347            }
     348
     349            // Handle any remaining content after last match
     350            if ($last_pos < strlen($html)) {
     351                $remaining = trim(substr($html, $last_pos));
     352                if (!empty($remaining) && !preg_match('/^\s*$/', $remaining)) {
     353                    $output .= self::wrap_paragraph('<p>' . $remaining . '</p>');
     354                }
     355            }
     356        }
     357
     358        // If no matches found, wrap entire content
     359        if (empty($output)) {
     360            return self::wrap_paragraph($html);
     361        }
     362
     363        return trim($output);
     364    }
    271365}
  • contentpen/trunk/README.txt

    r3455153 r3455197  
    44Requires at least: 5.8
    55Tested up to: 6.7
    6 Stable tag: 1.0.7
     6Stable tag: 1.0.8
    77Requires PHP: 7.4
    88License: GPLv2 or later
     
    5555== Changelog ==
    5656
     57= 1.0.8 =
     58* Added fallback regex-based conversion for servers without php-xml extension
     59* Fixed critical error on servers missing DOMDocument class
     60
     61= 1.0.7 =
     62* Bug fix for Gutenberg block conversion
     63
     64= 1.0.6 =
     65* Added HTML to Gutenberg block conversion for posts
     66
    5767= 1.0.0 =
    5868* Initial release
     
    6070== Upgrade Notice ==
    6171
    62 = 1.0.0 =
    63 Initial release of ContentPen WordPress plugin.
    64 
    65 = 1.0.7 =
    66 Fixed HTML to Gutenberg block conversion issue.
     72= 1.0.8 =
     73* Added fallback regex-based conversion for servers without php-xml extension
     74* Fixed critical error on servers missing DOMDocument class
  • contentpen/trunk/contentpen-plugin.php

    r3455153 r3455197  
    55 * Plugin URI: https://contentpen.ai
    66 * Description: Contentpen is an AI-powered content writing assistant designed to help businesses create, optimize, and publish SEO-friendly blog posts at scale. By combining deep research with your brand's unique voice, Contentpen crafts high-impact articles that outperform your competition.
    7  * Version: 1.0.7
     7 * Version: 1.0.8
    88 * Requires at least: 5.8
    99 * Requires PHP: 7.4
     
    2020}
    2121
    22 define('CONTENTPEN_VERSION', '1.0.7');
     22define('CONTENTPEN_VERSION', '1.0.8');
    2323define('CONTENTPEN_PLUGIN_DIR', plugin_dir_path(__FILE__));
    2424define('CONTENTPEN_PLUGIN_URL', plugin_dir_url(__FILE__));
  • contentpen/trunk/includes/class-gutenberg-converter.php

    r3455149 r3455197  
    2727        if (strpos($html, '<!-- wp:') !== false) {
    2828            return $html;
     29        }
     30
     31        // Check if DOMDocument is available (requires php-xml extension)
     32        if (!class_exists('DOMDocument')) {
     33            // Fallback: use regex-based conversion
     34            return self::convert_with_regex($html);
    2935        }
    3036
     
    269275        return "<!-- wp:code -->\n" . $html . "\n<!-- /wp:code -->\n\n";
    270276    }
     277
     278    /**
     279     * Fallback regex-based conversion when DOMDocument is not available.
     280     *
     281     * @param string $html The HTML content to convert.
     282     * @return string The converted Gutenberg block content.
     283     */
     284    private static function convert_with_regex($html)
     285    {
     286        $output = '';
     287
     288        // Pattern to match top-level block elements
     289        $pattern = '/<(p|h[1-6]|ul|ol|blockquote|table|figure|pre)(\s[^>]*)?>.*?<\/\1>/is';
     290
     291        $last_pos = 0;
     292        if (preg_match_all($pattern, $html, $matches, PREG_OFFSET_CAPTURE)) {
     293            foreach ($matches[0] as $index => $match) {
     294                $full_match = $match[0];
     295                $pos = $match[1];
     296                $tag = strtolower($matches[1][$index][0]);
     297
     298                // Handle any text between matches
     299                if ($pos > $last_pos) {
     300                    $between = trim(substr($html, $last_pos, $pos - $last_pos));
     301                    if (!empty($between) && !preg_match('/^\s*$/', $between)) {
     302                        $output .= self::wrap_paragraph('<p>' . $between . '</p>');
     303                    }
     304                }
     305
     306                // Convert based on tag
     307                switch ($tag) {
     308                    case 'p':
     309                        $output .= self::wrap_paragraph($full_match);
     310                        break;
     311                    case 'h1':
     312                    case 'h2':
     313                    case 'h3':
     314                    case 'h4':
     315                    case 'h5':
     316                    case 'h6':
     317                        $level = (int) substr($tag, 1);
     318                        $output .= self::wrap_heading($full_match, $level);
     319                        break;
     320                    case 'ul':
     321                        $output .= self::wrap_list($full_match, false);
     322                        break;
     323                    case 'ol':
     324                        $output .= self::wrap_list($full_match, true);
     325                        break;
     326                    case 'blockquote':
     327                        $output .= self::wrap_quote($full_match);
     328                        break;
     329                    case 'table':
     330                        $output .= self::wrap_table($full_match);
     331                        break;
     332                    case 'figure':
     333                        if (stripos($full_match, '<img') !== false) {
     334                            $output .= self::wrap_image($full_match);
     335                        } else {
     336                            $output .= $full_match . "\n\n";
     337                        }
     338                        break;
     339                    case 'pre':
     340                        $output .= self::wrap_code($full_match);
     341                        break;
     342                    default:
     343                        $output .= "<!-- wp:html -->\n" . trim($full_match) . "\n<!-- /wp:html -->\n\n";
     344                }
     345
     346                $last_pos = $pos + strlen($full_match);
     347            }
     348
     349            // Handle any remaining content after last match
     350            if ($last_pos < strlen($html)) {
     351                $remaining = trim(substr($html, $last_pos));
     352                if (!empty($remaining) && !preg_match('/^\s*$/', $remaining)) {
     353                    $output .= self::wrap_paragraph('<p>' . $remaining . '</p>');
     354                }
     355            }
     356        }
     357
     358        // If no matches found, wrap entire content
     359        if (empty($output)) {
     360            return self::wrap_paragraph($html);
     361        }
     362
     363        return trim($output);
     364    }
    271365}
Note: See TracChangeset for help on using the changeset viewer.