TinyMCE views API improvements

In WordPress 4.2 there will be changes to the experimental TinyMCE views API. We don’t recommend this for use in production unless you closely follow the development.

If you’re using it we’d love to get some feedback: bugs, suggestions, things you wish you could do with it… You’re also welcome to leave a comment with a link to your project. I’d love to know what kind of content you’re using it for and how you’re using it.

Summary of the changes:

  • Simpler registration.
  • An easier way to update the view in the edit method.
  • You can choose to leave the text instead of replacing it with a loader. This is especially useful for our oEmbed views because we don’t know if the URL can be embedded until we get a response from the server.
  • You can now update the view text with a text of a different type (e.g. audio to playlist).
  • No need to use the setIframes method directly, render and setContent will handle it for you.
  • Already rendered views will never refresh again while editing other content. They do refresh when undoing or redoing things though, because TinyMCE resets the whole content unfortunately.
  • Options set in the match method (previously toView) will be added automatically to the view instance.
  • A couple of memory leaks were fixed and there’s a better way to bind and unbind views.
  • We added documentation for all the methods.

How to use the API

Registration:

window.wp.mce.views.register( 'unique_name', {
	...
} );

If you’re converting shortcodes to views, make sure unique_name is the same. They’ll be matched automatically. If you’re interested in custom matching, take a look at the embedURL registration in core.

If the content of your view is static, you can set the content property directly, if it is dynamic, overwrite getContent. In most cases an ajax request is needed to generate the content, so use the initialize method and cache the content. Passing it through render will cache it automatically.

This example will display the most recent images.

initialize: function() {
	var self = this;

	wp.ajax.post( 'query-attachments', {
		query: {
			post_mime_type: 'image'
		}
	} )
	.done( function( response ) {
		self.render( _.map( response, function( data ) {
			return '<img src=' + data.sizes.thumbnail.url + ' alt=' + data.alt + '>';
		} ).join( '' ) );
	} );
}

To add UI for editing a view, you need to add an edit method. This example is taken from the gallery view. Use the callback to update the view with the modified text (shortcode).

edit: function( text, update ) {
	var frame = wp.media.gallery.edit( text );

	frame.state( 'gallery-edit' ).on( 'update', function( selection ) {
		update( wp.media.gallery.shortcode( selection ).string() );
	} );

	frame.on( 'close', function() {
		frame.detach();
	} );
}

It is not recommended to run JavaScript in the editor iframe. If you need to run scripts it is best to use a sandbox iframe inside the view. The API will automatically do this for you if it detects scripts in your content. For example the Google Maps API might alter the editor’s iframe body. This is not acceptable because the body content is serialised by TinyMCE on saving.

In this example the content will be put in an iframe and you can do anything you want in that document.

content: [
	'<script src="//maps.googleapis.com/maps/api/js?sensor=false"></script>',
	'<style>img { max-width: none; }</style>',
	'<div id="map" style="width: 100%;height: 500px;"></div>',
	'<script>new google.maps.Map( document.getElementById( "map" ), { zoom: 0, center: new google.maps.LatLng( 0, 0 ) } )</script>'
].join( '' )

If you do want to run scripts, use the bind and unbind methods and make sure there are no memory leaks.

#4-2, #dev-notes