Skip to content

Instantly share code, notes, and snippets.

@tomazzaman
Last active July 28, 2018 07:34
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save tomazzaman/29a93e122f03a0f3e4d4 to your computer and use it in GitHub Desktop.
Save tomazzaman/29a93e122f03a0f3e4d4 to your computer and use it in GitHub Desktop.
How to create a testimonial widget with Backbone
var myWidgets = myWidgets || {};
// Model for a single testimonial
myWidgets.Testimonial = Backbone.Model.extend({
defaults: { 'quote': '', 'author': '' }
});
// Single view, responsible for rendering and manipulation of each single testimonial
myWidgets.TestimonialView = Backbone.View.extend( {
className: 'testimonial-widget-child',
events: {
'click .js-remove-testimonial': 'destroy'
},
initialize: function ( params ) {
this.template = params.template;
this.model.on( 'change', this.render, this );
return this;
},
render: function () {
this.$el.html( this.template( this.model.attributes ) );
return this;
},
destroy: function ( ev ) {
ev.preventDefault();
this.remove();
this.model.trigger( 'destroy' );
},
} );
// The list view, responsible for manipulating the array of testimonials
myWidgets.TestimonialsView = Backbone.View.extend( {
events: {
'click #js-testimonials-add': 'addNew'
},
initialize: function ( params ) {
this.widgetId = params.id;
// cached reference to the element in the DOM
this.$testimonials = this.$( '#js-testimonials-list' );
// collection of testimonials, local to each instance of myWidgets.testimonialsView
this.testimonials = new Backbone.Collection( [], {
model: myWidgets.Testimonial
} );
// listen to adding of the new testimonials
this.listenTo( this.testimonials, 'add', this.appendOne );
return this;
},
addNew: function ( ev ) {
ev.preventDefault();
// default, if there is no testimonials added yet
var testimonialId = 0;
if ( ! this.testimonials.isEmpty() ) {
var testimonialsWithMaxId = this.testimonials.max( function ( testimonial ) {
return testimonial.id;
} );
testimonialId = parseInt( testimonialsWithMaxId.id, 10 ) + 1;
}
var model = myWidgets.Testimonial;
this.testimonials.add( new model( { id: testimonialId } ) );
return this;
},
appendOne: function ( testimonial ) {
var renderedTestimonial = new myWidgets.TestimonialView( {
model: testimonial,
template: _.template( jQuery( '#js-testimonial-' + this.widgetId ).html() ),
} ).render();
this.$testimonials.append( renderedTestimonial.el );
return this;
}
} );
myWidgets.repopulateTestimonials = function ( id, JSON ) {
var testimonialsView = new myWidgets.TestimonialsView( {
id: id,
el: '#js-testimonials-' + id,
} );
testimonialsView.testimonials.add( JSON );
};
<?php
// Prevent direct access to this file
defined( 'ABSPATH' ) or die( 'Nope.' );
/**
* Register the widget with WordPress
*/
add_action( 'widgets_init', function(){
register_widget( 'Testimonial_Widget' );
});
class Testimonial_Widget extends WP_Widget {
/**
* Mandatory constructor needs to call the parent constructor with the
* following params: id (if false, one will be generated automatically),
* the title of the widget (can be translated, of course), and last, params
* to further configure the widget.
* see https://codex.wordpress.org/Widgets_API for more info
*/
public function __construct() {
parent::__construct(
false,
'Testimonials',
array( 'description' => 'My Testimonials Widget' )
);
}
/**
* Renders the widget to the visitors
*/
public function widget( $args, $instance ) {
$header = apply_filters( 'widget_title', empty( $instance['header'] ) ? '' : $instance['header'], $instance, $this->id_base ); ?>
<h3><?= $header ?></h3>
<?php foreach ( $instance['testimonials'] as $testimonial ): ?>
<blockquote>
<p><?= $testimonial['quote'] ?></p>
<footer>— <?= $testimonial['author'] ?></footer>
</blockquote>
<?php endforeach;
}
/**
* Sanitizes the widget input before saving the data
*/
public function update( $new_instance, $old_instance ) {
$instance = array();
$instance['header'] = wp_kses_post( $new_instance['header'] );
$instance['testimonials'] = $new_instance['testimonials'];
return $instance;
}
/**
* The most important function, used to show the widget form in the wp-admin
*/
public function form( $instance ) {
$header = empty( $instance['header'] ) ? 'Testimonials' : $instance['header'];
$testimonials = isset( $instance['testimonials'] )
? array_values( $instance['testimonials'] )
: array( array( 'id' => 1, 'quote' => '', 'author' => '', 'image' => '' ) );
?>
<!-- segment #1 -->
<p>
<label for="<?= $this->get_field_id( 'header' ); ?>">Header</label>
<input class="widefat" id="<?= $this->get_field_id( 'header' ); ?>" name="<?= $this->get_field_name( 'header' ); ?>" type="text" value="<?= esc_attr( $header ); ?>" />
</p>
<!-- segment #2 -->
<script type="text/template" id="js-testimonial-<?= $this->id; ?>">
<p>
<label for="<?= $this->get_field_id( 'testimonials' ); ?>-<%- id %>-quote">Quote:</label>
<textarea rows="4" class="widefat" id="<?= $this->get_field_id( 'testimonials' ); ?>-<%- id %>-quote" name="<?= $this->get_field_name( 'testimonials' ); ?>[<%- id %>][quote]"><%- quote %></textarea>
</p>
<p>
<label for="<?= $this->get_field_id( 'testimonials' ); ?>-<%- id %>-author">Author:</label>
<input class="widefat" id="<?= $this->get_field_id( 'testimonials' ); ?>-<%- id %>-author" name="<?= $this->get_field_name( 'testimonials' ); ?>[<%- id %>][author]" type="text" value="<%- author %>" />
</p>
<p>
<input name="<?= $this->get_field_name( 'testimonials' ); ?>[<%- id %>][id]" type="hidden" value="<%- id %>" />
<a href="#" class="js-remove-testimonial"><span class="dashicons dashicons-dismiss"></span>Remove Testimonial</a>
</p>
</script>
<!-- segment #3 -->
<div id="js-testimonials-<?= $this->id; ?>">
<div id="js-testimonials-list" style="padding: 0px 15px; background: #fafafa;"></div>
<p>
<a href="#" class="button" id="js-testimonials-add">Add New Testimonial</a>
</p>
</div>
<!-- segment #4 -->
<script type="text/javascript">
var testimonialsJSON = <?= json_encode( $testimonials ) ?>;
myWidgets.repopulateTestimonials( '<?= $this->id; ?>', testimonialsJSON );
</script>
<?php
}
}
<?php
/**
* Load Testimonial Widget
*/
require get_template_directory() . '/inc/class-testimonial-widget.php';
/**
* Enqueue admin testimonials javascript
*/
function testimonials_enqueue_scripts() {
wp_enqueue_script(
'admin-testimonials', get_template_directory_uri() . '/js/admin-testimonials.js',
array( 'jquery', 'underscore', 'backbone' )
);
}
add_action( 'admin_enqueue_scripts', 'testimonials_enqueue_scripts' );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment