A new approach to RAMP

We use RAMP, and it causes me a lot of headaches. Most of our RAMP problems come from the way I’ve customized it to work with our custom theme. RAMP proper is pretty solid, if slow, but doesn’t handle all of the custom fields that let us link to other pages on the site or display images in the media library while tightly controlling formatting. Those fields store Post IDs, and the Post IDs on the live site are different from the staging site, so RAMP does two things to make sure all of those links and images work after shipping pages over to live:

  1. It adds the linked pages and files to a batch automatically, to be sure they’re present on the live site – whether that’s really needed or not, and
  2. It runs a little function to translate the Post IDs after RAMPing, based on the guid of the item (which is the same on stage and live).

This basically works a lot of the time, but not all of the time, and when it fails we wind up with broken images and links that a developer has to manually fix on the live site – and it makes the batches huge, and therefore incredibly slooowwwww.


We went through a really weird series of problems earlier this year, marked by more and more bizarre RAMP problems. One time, the live site failed to run the function to generate thumbnails after new images were imported and I had to run it manually with WP-CLI (thankgodforwpcli amiright?). Thinking this might be our new reality I thought, you know, I could just rig our templates up to run ‘generate thumbnails’ on the fly if need be.

Well, I didn’t need to. I eventually found the root of our weird problems to be an unrelated plugin which I’ve now turned off. But the idea of adding some “smarts” to the template itself stuck with me, because not every problem went away – sometimes after RAMPing, we still wind up with broken images and links.

The self-healing template

Struggling to get RAMP to catch every Post ID translation is something I am ready to be done with. There’s a lot of poorly-documented, convoluted looping involved in every RAMP batch and it’s painful as hell to work with.

But our templates – I wrote a lot of those myself in the earliest days of our site. They are dead simple to work with. And the function to do the Post ID translation is always available via RAMP, all it needs is the guid. I thought the idea of making the templates “self-healing” held some promise and everyone involved in the project is ready for us to be done with our RAMP woes, so I didn’t have any trouble getting this idea prioritized as something for me to work on.

The design

It’s pretty simple:

  1. During editing, capture the guid for each linked page and file, and stick it into the postmeta along with the post id that CMB2 is already capturing. Set a flag to signify that an edit has been made and Post ID translation will be needed.
  2. After RAMPing to the live site, when the page is viewed, the template will check the flag, run Post ID translation on all the fields with a captured guid, then reset the flag to prevent the translation routine from being run on every view.

The implementation

In the CMB2 definition of our custom fields, I added hidden fields to hold the guids. After experimenting with various CMB2 callbacks (most of which aren’t available for hidden fields, a fact that’s not actually documented), I finally found some example code in a CMB2 examples repo that did what I needed using an action hook. The example wasn’t actually working, exactly, but it was enough to get me headed down the right path.

I created a function that will run on this hook, look up the guid via the Post ID, then save the guid to postmeta in the hidden field. I have to give the hook an anonymous function rather than just the name of my guid capturing function, because I need to be able to feed it the names of the fields I need to capture guid for, and some other stuff. My co-workers and I had never seen this way of calling a hook before so I will include some code here for the curious.

function define_guidfields() {
    // repeating field with two fields we need guids for:
    $guidfields2_fields[] = "_card_link";
    $guidfields2_fields[] = "_card_image";
    $guidfields2["_cardstemplate"] = $guidfields2_fields;

    return $guidfields2;

// make sure the utilities class is available before calling its function
// lest we bring the whole site down
add_action( 'cmb2_save_post_fields__cardsmetabox',
    function( $post_id, $updated, $cmb ) {
        if ( class_exists( 'Utilities_Cmb2' ) ) $cmb2_helper = new Utilities_Cmb2();
        else $cmb2_helper = null;
        $cmb2_helper->set_guid( $post_id, $updated, $cmb, $guidfields2 = define_guidfields() );
    }, 10, 4 );

In the template itself, I use RAMP settings to determine if we are on a sending site or a receiving site, because we don’t want to run the translation routine on our sending site. I also hard coded the name of our staging site to ensure that it is never treated as a receiving site, just to be cautious. This setup will allow us a lot of flexibility that we will need when doing testing as we have different setups for RAMP testing in different places.

Just before links and images are displayed, the Post ID translation will occur if possible (if we have the needed guid). If translation runs but returns an empty object, then the rare case of the linked page or file being missing from the site is recognized and the page element that depends on that missing link doesn’t display. In that case, I also pass a message out to the log that something is missing.

Finally toward the end of the template, after all display work has been done and the various arrays with our CMB2 custom fields have been rebuilt with corrected Post IDs, we attempt to do an update to the postmeta in the database. If we have missing items, we do the update, but don’t reset the flag. This means that as soon as the missing items are RAMPed over, the page will “heal” itself and the flag will be set – but it will not be necessary to re-RAMP the page with missing links just to reset the flag.

Happiness ensues

Or so we hope. I’ve deployed the first self-healing template and it has been out there for a few days. We need to add the “self-healing” code to several more templates and shortcodes before we can try out some of our biggest problem pages and see how they run. But it works in testing, has not caused obvious problems in the live environment, and I remain optimistic.