Feature Request / Ideas: Text For Product Feed From Cornerstone Content

You have full admin access. I think you may be after Appearance > Theme File Editor? It was disabled through the security plugin - now enabled. If you need full FTP access, please let me know and I will send the details over.

I have added the line (row 213 in Theme File Editor), which I hope is in the right place.

Other details in Secure Note!

Hi @charlie,

An update to yesterday evening’s reply. I have added the GLOBALS line you sent in your last reply. It appears to export the HTML correctly for the first time, so the ACF fields are being output. Thank you! The bulk plugin has also been rewritten using your update. There is a small duplication of data in the output (more details in Secure Note), though it is something I can live with.

The working function and plugin code is as below.

FUNCTION

// EXPORT AS HTML
// On Document save, update post meta field _cs_built_html with an HTML copy of the post
add_filter("cs_save_document", function($doc) {
    try {
        ob_start();

        // Needed For styling
        do_action("wp_enqueue_scripts");

        // Find document and renderContentFromDocument
        $GLOBALS['post'] = get_post($doc->id());
        $resolver = cornerstone("Resolver");
        $docDB = $resolver->getDocument( $doc->id() );
        $html = cornerstone("Resolver")->renderContentFromDocument($docDB);

        // Fetch ACF fields and append to HTML
        $fields = get_fields($doc->id());

        if ($fields) {
            error_log("ACF fields found: " . print_r($fields, true));
            foreach ($fields as $name => $value) {
                if($name == 'bird_animal_description') {
                    $html .= do_shortcode($value);
                } else {
                    $html .= $value;
                }
            }
        } else {
            error_log("No ACF fields found for document with ID: " . $doc->id());
        }

        $html .= ob_get_clean();

        // Attributes to remove
        $attributes = [
            'class', 'style', 'data-x-effect', 'data-x-slide-container', 'loading', 'width', 'height',
            'aria-hidden', 'tabindex', 'data-x-effect-provider', 'data-x-slide-context', 'data-x-slide',
            'aria-expanded', 'id', 'role', 'aria-selected', 'aria-controls', 'data-x-toggle', 'data-x-toggleable',
            'data-x-toggle-collapse', 'aria-labelledby'
        ];

        // Remove attributes
        foreach ($attributes as $attribute) {
            $html = preg_replace('/\s*' . $attribute . '\s*=\s*".*?"/i', '', $html);
        }

        // Remove content within certain tags
        $tags = ['style', 'iframe', 'script', 'i', 'blockquote'];
        foreach ($tags as $tag) {
            $html = preg_replace('/<' . $tag . '\b[^>]*>.*?<\/' . $tag . '>/is', '', $html);
        }

        // Remove span tags
        $html = preg_replace('~</?span[^>]*>~i', '', $html);

        // Convert special characters to ASCII
        $html = iconv('UTF-8', 'ASCII//IGNORE', $html);

        // Remove all div tags
        $html = preg_replace('~</?div[^>]*>~i', '', $html);

        // Update post meta with HTML
        update_post_meta($doc->id(), '_cs_built_html', $html);
    } catch(\Throwable $e) {
        trigger_error("Error with document HTML post meta saving : " . $e->getMessage());
    }
});

PLUGIN

<?php
/**
 * Plugin Name: Cornerstone Bulk HTML Generator
 * Description: This is a custom plugin to update all posts and generate HTML for Cornerstone.
 * Version: 1.0
 * Author: White Media
 * Author URI: https://www.whitemedia.uk/
 */

// Ensure direct access is blocked
defined('ABSPATH') || exit;

// Add admin menu
add_action('admin_menu', 'bulk_html_generator_menu');

function bulk_html_generator_menu() {
    add_menu_page('Bulk HTML Generator', 'Bulk HTML Generator', 'manage_options', 'custom-post-processor', 'bulk_html_generator_page', 'dashicons-hammer', 6);
}

// Add AJAX handler
add_action('wp_ajax_process_posts', 'ajax_process_posts');

function ajax_process_posts() {
    $selected_post_type = $_POST['post_type'];
    $processed_count = 0;

    $args = [
        'post_type' => $selected_post_type,
        'post_status' => 'publish',
        'posts_per_page' => -1
    ];
    $query = new WP_Query($args);
    while($query->have_posts()) {
        $query->the_post();
        $post_id = get_the_ID();
        process_post($post_id);
        $processed_count++;
    }
    wp_reset_postdata();

    echo json_encode(['processed' => $processed_count]);
    wp_die(); // Use wp_die() instead of die() for AJAX in WordPress
}

function bulk_html_generator_page() {
    $post_types = get_post_types(['public' => true], 'names');
    $selected_post_type = isset($_POST['post_type']) ? $_POST['post_type'] : '';
    $posts_count = $selected_post_type ? wp_count_posts($selected_post_type)->publish : 0;

    echo '<div class="wrap">';
    echo '<h1>Bulk HTML Generator</h1>';

    echo '<script>
    function startProcessing() {
        document.getElementById("startProcessingBtn").style.display = "none";
        document.getElementById("processingStatus").style.display = "block";
        var postData = new FormData();
        postData.append("action", "process_posts");
        postData.append("post_type", document.forms[0].post_type.value);
        fetch(ajaxurl, {
            method: "POST",
            body: postData
        })
        .then(response => response.json())
        .then(data => {
            document.getElementById("processingStatus").innerText = "Processed " + data.processed + " records.";
        });
    }
    </script>';

    echo '<form method="post">';
    echo '<label for="post_type">Select Post Type: </label>';
    echo '<select name="post_type" onchange="this.form.submit()">';
    echo '<option value="">-- Select --</option>';
    foreach($post_types as $post_type) {
        $selected = $selected_post_type == $post_type ? 'selected' : '';
        echo '<option value="' . $post_type . '" ' . $selected . '>' . $post_type . '</option>';
    }
    echo '</select>';
    echo '<p>Total Posts: ' . $posts_count . '</p>';
    if($selected_post_type) {
        echo '<input type="button" class="button button-primary" value="Start Processing" id="startProcessingBtn" onclick="startProcessing();">';
    }
    echo '</form>';
    
    echo '<p id="processingStatus" style="display: none;">Processing... <span class="spinner is-active" style="float:none;"></span></p>';

    echo '</div>';
}

function process_post($post_id) {
    try {
        ob_start();

        // Needed For styling
        do_action("wp_enqueue_scripts");

        // Find document and renderContentFromDocument
        $GLOBALS['post'] = get_post($post_id);
        $resolver = cornerstone("Resolver");
        $docDB = $resolver->getDocument($post_id);
        $html = cornerstone("Resolver")->renderContentFromDocument($docDB);

        // Fetch ACF fields and append to HTML
        $fields = get_fields($post_id);

        if ($fields) {
            error_log("ACF fields found: " . print_r($fields, true));
            foreach ($fields as $name => $value) {
                if ($name == 'bird_animal_description') {
                    $html .= do_shortcode($value);
                } else {
                    $html .= $value;
                }
            }
        } else {
            error_log("No ACF fields found for document with ID: " . $post_id);
        }

        $html .= ob_get_clean();

        // Attributes to remove
        $attributes = [
            'class', 'style', 'data-x-effect', 'data-x-slide-container', 'loading', 'width', 'height',
            'aria-hidden', 'tabindex', 'data-x-effect-provider', 'data-x-slide-context', 'data-x-slide',
            'aria-expanded', 'id', 'role', 'aria-selected', 'aria-controls', 'data-x-toggle', 'data-x-toggleable',
            'data-x-toggle-collapse', 'aria-labelledby'
        ];

        // Remove attributes
        foreach ($attributes as $attribute) {
            $html = preg_replace('/\s*' . $attribute . '\s*=\s*".*?"/i', '', $html);
        }

        // Remove content within certain tags
        $tags = ['style', 'iframe', 'script', 'i', 'blockquote'];
        foreach ($tags as $tag) {
            $html = preg_replace('/<' . $tag . '\b[^>]*>.*?<\/' . $tag . '>/is', '', $html);
        }

        // Remove span tags
        $html = preg_replace('~</?span[^>]*>~i', '', $html);

        // Convert special characters to ASCII
        $html = iconv('UTF-8', 'ASCII//IGNORE', $html);

        // Remove all div tags
        $html = preg_replace('~</?div[^>]*>~i', '', $html);

        // Update post meta with HTML
        update_post_meta($post_id, '_cs_built_html', $html);
    } catch (\Throwable $e) {
        trigger_error("Error with document HTML post meta saving : " . $e->getMessage());
    }
}

// Optionally, enqueue scripts and styles. This example just sets up the action hook.
add_action('admin_enqueue_scripts', 'bulk_html_generator_enqueue');

function bulk_html_generator_enqueue($hook) {
    if ('toplevel_page_custom-post-processor' !== $hook) {
        return;
    }

    // Enqueue your styles and scripts here
    // wp_enqueue_style(...)
    // wp_enqueue_script(...)
}

// Activation and Deactivation hooks
register_activation_hook(__FILE__, 'bulk_html_generator_activate');
register_deactivation_hook(__FILE__, 'bulk_html_generator_deactivate');

function bulk_html_generator_activate() {
    // Code to run when the plugin is activated
}

function bulk_html_generator_deactivate() {
    // Code to run when the plugin is deactivated
}

Thanks for all your help!!

See my secure note!

More in Secure Note!

Hi @charlie,

Despite what appeared to be success, we have hit problems. Not sure if it is the latest WP version, or something else. More in Secure Note.

Thanks,
Christopher

Hello! I will add a note below.

Hi! Good to hear from you. More in Secure Note.