0

I'm using Godaddy Hosting, PHP 5, and Wordpress 4.2.1

I have 34,000 + posts that need outdated href tags removed. I am able to remove tags, one post at a time, by using this code in a page template and changing the post_id manually. Thank you @ialocin for the wp-kses addition. The wp_postmeta table has 347,602 rows but only 34,788 have the "simple_fields" row.

<?php $allowed_html = array(
        'p' => array(),
        'img' => array(
            'alt' => true,
            'align' => true,
            'border' => true,
            'height' => true,
            'hspace' => true,
            'longdesc' => true,
            'vspace' => true,
            'src' => true,
            'usemap' => true,
            'width' => true,
        ),
        'br' => array()
    );
?>            
<?php $source = get_post_meta(24532, '_simple_fields_fieldGroupID_1_fieldID_1_numInSet_0', true); ?>
<?php update_post_meta(24532, '_simple_fields_fieldGroupID_1_fieldID_1_numInSet_0', wp_kses ($source, $allowed_html) ); ?>

However, I need to apply this to many thousands of wp_postmeta rows. After modifying this example from @TheDeadMedic, I was able to throw an error with the following code, but so far it does nothing to the database.

The error is:

Fatal error: Allowed memory size of 67108864 bytes exhausted (tried to allocate 32 bytes) in .../wp-includes/wp-db.php on line 2204

If I change the posts_per_page to -1, it does not appear to do anything. It just refreshes the page.

<?php 
/**
 * Update All postmeta
 *
 */
$args = array(
    'fields'            => 'ids', // MAGIC! Just get an array of id's, no objects committed to memory
    'posts_per_page'    => 500,  // Batch size: look at all posts
    'post_type'         => 'post',
    'date_query'        => array( // Make sure the post is over 30 days old
        array(
            'column' => 'post_date_gmt',
            'before' => '1 month ago'
        )
    ),
);
$query = new WP_Query;
$paged = 1;
$count = 0;
$total = null;
do {
    $args['no_found_rows'] = isset( $total ); // No need to SQL_CALC_FOUND_ROWS on subsequent iterations
    $args['paged'] = $paged++;

    $post_ids = $query->query( $args );
    update_postmeta_cache( $post_ids ); // Get all meta for this group of posts
    if ( ! isset( $total ) )
        $total = $query->found_posts;
        $count += $query->post_count;
    foreach ( $post_ids as $post_id ) {
        $allowed_html = array( // Declare tags not to be removed
            'p' => array(),
            'img' => array(
                'alt' => true,
                'align' => true,
                'border' => true,
                'height' => true,
                'hspace' => true,
                'longdesc' => true,
                'vspace' => true,
                'src' => true,
                'usemap' => true,
                'width' => true,
            ),
            'br' => array()
        );          
        $source = get_post_meta($post_id, '_simple_fields_fieldGroupID_1_fieldID_1_numInSet_0', true);
        update_post_meta($$post_id, '_simple_fields_fieldGroupID_1_fieldID_1_numInSet_0', wp_kses ($source, $allowed_html) );
    }
} while ( $count < $total );
?>

Can anyone see what is off or missing? Does the 'fields' => 'ids', // MAGIC! from @TheDeadMedic need to be "post_id" or does this need to be a foreach instead of while or other?

What is the best way to do this automatically, dynamically, procedurally, else wise or other?

Any solutions, leads, clues or hints are greatly appreciated.

4 Answers 4

3

Firstly, I would consider using one of WordPress' wp_kses-like functions, instead of PHP's strip_tags().

Secondly, query your posts with WP_Query or get_posts() with the fields parameter set to ids - seems like you don't need more than that.

Thirdly, split up your loop into steps that are effective and manageable. Because 34000+ posts will likely reach the limits of your server - at the very least regarding processing time.

You could for example make smart use of the posts_per_page and/or offset parameters for WP_Query/get_posts. Or you might do it by handling the complete array of IDs you can get by setting posts_per_page to -1 another way with PHP. For an exemplary approach take a look at the following answer by @TheDeadMedic on a similar matter.

6
  • Thank you for the wp_kses info. I updated my short version, and updated the question title. I am looking into making this run as a loop with the links you provided. I will also look at putting this in the post loop, and running the update as the posts are viewed by the users Commented Jul 11, 2015 at 6:55
  • My pleasure. If you really are planing on doing it on post views, then you have to be certain the $post variable is available, it gets initialized just before the wp hook, so this is the earliest one you can use. Additionally, if you do it that way, then you should add a post meta on posts that have been updated, so you can use it for checking, if the change has happened. After all there is no reason for doing it over and over again. Besides, with it you can query for the change by the post meta, giving you a possibility to monitor the process. @Lawrence1972 Commented Jul 11, 2015 at 10:01
  • I updated the code to run a loop, but it throws an error. Do you see anything obvious out of place? Commented Jul 15, 2015 at 17:52
  • The error is pretty obvious, you have exhausted your memory limit. Instead of setting the post_per_page aka here as »batch size« to get more posts - after all -1 stands for all of them , you should try to lower it to an amount your server can actually handle. @Lawrence1972 Commented Jul 15, 2015 at 18:07
  • I was able to get it to work. I posted the code I used. Thanks for the help. Commented Jul 19, 2015 at 8:34
1

The quickest solution is export posts table from database, replace tags this using any code-editor. For posts content are simple text not serialized, in this way you can do all replacement in less than 10 minutes without any hassle. Then import the sql file in db.

Thanks

1
  • I tried your idea first. I used find and replace in Dreamweaver CC 2015. I could not get DWCC to find any tag using Search in: Document / specific tag / strip tag. I could find tags if I searched Source Code, but to replace, I need a Reg Expression that removes the <a href tag, but leaves the content. After a few hours of troubleshooting, I have paused the pursuit of that method. If you have further suggestions, please let me know. Commented Jul 11, 2015 at 6:45
1

The easiest way to do this would be via SQL. Firstly take a backup of your database in case anything goes wrong. Then using phpMyAdmin or a similar SQL frontend run this SQL command:

UPDATE wp_posts SET post_content = REPLACE(post_content, '<br>', '');

This will replace the tag

<br>

with nothing in all post content.

If the tags are in post meta and not post content then it's a little more work as you'll need to go into your database and find which meta key the tags are in.

Look into your wp__postmeta table and look for the field you've listed above in the meta_key column then you can run this SQL query:

UPDATE wp_postmeta WHERE meta_key = 'YourMetaKey' SET meta_value = REPLACE(meta_value, '<br>', '');

Run these commands for each tag you want to remove from post content or post meta.

2
  • Will this work with the <a href tag? I want to remove the tag, but keep the link text. Commented Jul 11, 2015 at 6:47
  • No, I'll add a solution to my answer to this for you. Commented Jul 13, 2015 at 15:43
1

Finally, I was able to iterate through all 34,788 entries, but only by running the job in smaller batches based on the post date. Here is the final code that I used on a page template. Thank you @ialocin for setting me on the right path. The job is done, but there has to be a better, more automatic, way to iterate through the posts without setting post date or blowing out the memory. If you have a better way, please post it here.

 <?php 
    /**
     * Remove href tags from postmeta by post date
     *
     */
    $args = array(
        'post_type' => 'post',
        'fields' => 'ids',
        'posts_per_page' => -1,  // Grab all Post IDs
        'date_query'        => array( // Set the date range of the posts you want effected
            array(
                'after'     => 'June 1st, 2010',
                'before'    => array(
                    'year'  => 2012,
                    'month' => 12,
                    'day'   => 30,
                ),
                'inclusive' => true,
            ),
        ),
    );
    $query = new WP_Query($args);
    if ($query->have_posts()):
        foreach( $query->posts as $id ):
            $allowed_html = array( // Declare tags not to be removed
                'p' => array(),
                'img' => array(
                    'alt' => true,
                    'align' => true,
                    'border' => true,
                    'height' => true,
                    'hspace' => true,
                    'longdesc' => true,
                    'vspace' => true,
                    'src' => true,
                    'usemap' => true,
                    'width' => true,
                ),
                'br' => array()
            );  
        // retrieve the postmeta for the specific custom field, only if it has data.
        $source = get_post_meta($id,'_simple_fields_fieldGroupID_1_fieldID_1_numInSet_0', true);
        // write it back, but remove the tags with wp_kses
        update_post_meta($id, '_simple_fields_fieldGroupID_1_fieldID_1_numInSet_0', wp_kses ($source, $allowed_html) );
        // Wipe this post's meta from memory
        wp_cache_delete($id, 'post_meta' );
        endforeach;
    endif;
    ?>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.