This one could be a solution, probably not the most elegant.
For reference, loadPageInformation is the method I used to call the REST API, then, the response is stored in pageInfo, like this:
loadPageInformation: function(slug) {
this.pageInfo = null;
// retrieving page data using the page slug.
axios.get(this.appData.rest_url + '/wp/v2/pages?slug=' + slug)
.then( response => { this.pageInfo = response.data[0]; } )
.catch( error => { console.log( error ); } );
},
In your template file:
<template>
<div class="v-page" v-if="this.$root.pageInfo != null">
<b-row class="">
<b-col cols="12">
<h1>{{ this.$root.pageInfo.title.rendered }}</h1>
<div class="contact-form"></div>
</b-col>
</b-row>
<!-- footer. -->
<footer-component></footer-component>
</div>
</template>
<script>
export default {
created: function() {
this.$root.loadPageInformation(this.$route.params.pageSlug);
},
updated: function() {
$( ".cform7 .wpcf7" ).appendTo( ".contact-form" );
}
}
</script>
You can notice a jQuery line under the updated method that will basically cut the form from PHP and paste it in the template file. That line is the proposed solution. The form will be called with do_shortcode in PHP:
<div class="cform7 d-none">
<?php echo do_shortcode('[contact-form-7 id="104" title="Contact form"]'); ?>
</div>
EDIT: A different solution
I tested the previous solution and found some issues. So here a new approach.
Short answer: create a new Custom Post Type to print the shortcodes, then load the generated URL into the Vue component.
Very long answer:
For reference: loading the Vue generated JS and CSS files from functions.php should be the right process. It is going to be useful in next steps.
So I created a Custom Post Type called shortcodes, like this:
function custom_shortcodes_post() {
$labels = array(
'name' => __( 'Shortcodes' ),
'singular_name' => __( 'Shortcode' ),
'add_new' => __( 'Add new shortcode' ),
'add_new_item' => __( 'Add new shortcode' ),
'edit_item' => __( 'Edit shortcode' ),
'new_item' => __( 'New shortcode' ),
'all_items' => __( 'All shortcodes' ),
'view_item' => __( 'See shortcode' ),
'search_items' => __( 'Search shortcodes' ),
'not_found' => __( 'No shortcodes found' ),
'not_found_in_trash' => __( 'No shortcodes in trash' ),
'parent_item_colon' => '',
'menu_name' => 'Shortcodes'
);
$args = array(
'labels' => $labels,
'description' => 'Save shortcodes with specific data',
'public' => true,
'show_in_rest' => true,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => true,
'query_var' => true,
'rewrite' => array( 'slug' => 'shortcodes' ),
'capability_type' => 'post',
'has_archive' => false,
'hierarchical' => false,
'menu_position' => 6,
'supports' => array( 'title', 'editor' )
);
register_post_type( 'shortcodes', $args );
}
add_action( 'init', 'custom_shortcodes_post' );
Then I created a new shortcode post, and in the content, I wrote the shortcode that Contact Form 7 gives me. I also created single-shortcodes.php, like this:
<!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<?php wp_head(); ?>
</head>
<body style="background:none">
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
<?php the_content(); ?>
<?php endwhile; endif; ?>
<?php wp_footer(); ?>
</body>
</html>
Finally, the template file remains the same but with a different JS content:
<template>
<div class="v-page" v-if="this.$root.pageInfo != null">
<b-row class="">
<b-col cols="12">
<h1>{{ this.$root.pageInfo.title.rendered }}</h1>
<div class="contact-form"></div>
</b-col>
</b-row>
<!-- footer. -->
<footer-component></footer-component>
</div>
</template>
<script>
export default {
created: function() {
this.$root.loadPageInformation(this.$route.params.pageSlug);
},
updated: function() {
if (this.$route.params.pageSlug == 'contact') {
$( '.contact-form' ).load( '/shortcodes/contact-form/' );
}
}
}
</script>
After that, an error should appear in the console, because single-shortcodes.php is loading the JS and CSS files from Vue, so in functions.php I made a little fix:
if ( !is_singular( 'shortcodes' ) ) {
// here I load the JS and CSS files from Vue.
}
My entire piece of code to register CSS and JS files looks like this:
function rci_theme_enqueue() {
if ( !is_singular( 'shortcodes' ) ) {
// enqueue main style.
wp_enqueue_style(
'app',
get_template_directory_uri() . '/spa/dist/css/app.css'
);
// register the script.
wp_register_script(
'vue_app',
get_template_directory_uri() . '/spa/dist/app.js',
array(),
'1.0.0',
true
);
// localize the script with new data.
global $post;
$app_data = array(
'rest_url' => untrailingslashit( esc_url_raw( rest_url() ) ),
'theme_url' => get_template_directory_uri(),
'app_path' => $post->post_name, // page where the custom page template is loaded.
);
wp_localize_script( 'vue_app', 'app_data', $app_data );
// enqueued script with localized data.
wp_enqueue_script( 'vue_app' );
}
}
add_action( 'wp_enqueue_scripts', 'rci_theme_enqueue' );
Again: to me, it does not sound like an elegant solution, but unfortunately, when mixing Vue with WordPress, you will lose some of the WordPress core features.
Hope it helps to someone.