Wordpress - Why might a plugin's 'do_shortcode' not work in an AJAX request?

WP Ajax runs both public as well as closed calls via admin.php. This means that you don't have access to the whole wp environment, such as do_shortcode(), which is inside /wp-includes/shortcodes.php.

This still can get worked around (and as well for oEmbed). See the following example that you could use in your AJAX callback to enable both oEmbed handlers as well as shortcode handlers for a \WP_Post::post_content property.

/** \WP_Post $post */
$post = get_post();

/** @var \WP_Embed $wp_embed */
global $wp_embed;

$wp_embed->post_ID = $post->ID;

// [embed] shortcode
$wp_embed->run_shortcode( $post->post_content );

// plain links on their own line
$wp_embed->autoembed( $post->post_content );

// Enable shortcodes
do_shortcode( $post->post_content );

PROTip: Never call echo do_shortcode( '[some-short-code arg="foo"]' ); directly. A shortcode is just a placeholder for the editor. Every shortcode must have a callback attached. Use the callback instead. This saves you from running expensive Regex checks.

The answer is to sidestep admin-ajax restrictions by handling it yourself, as @OneTrickPony suggests.

add_action( 'init', function() { 
  ps_register_shortcode_ajax( 'ps_get_survey_form', 'ps_get_survey_form' ); 
} );

function ps_register_shortcode_ajax( $callable, $action ) {

  if ( empty( $_POST['action'] ) || $_POST['action'] != $action )

  call_user_func( $callable );

function ps_get_survey_form() {
    echo do_shortcode( '[contact-form-7 id="397" title="contact form 1"]' );