wp/wp-includes/js/wp-api.js
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
   105 	wp.api.utils.parseISO8601 = function( date ) {
   105 	wp.api.utils.parseISO8601 = function( date ) {
   106 		var timestamp, struct, i, k,
   106 		var timestamp, struct, i, k,
   107 			minutesOffset = 0,
   107 			minutesOffset = 0,
   108 			numericKeys = [ 1, 4, 5, 6, 7, 10, 11 ];
   108 			numericKeys = [ 1, 4, 5, 6, 7, 10, 11 ];
   109 
   109 
   110 		// ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string
   110 		/*
   111 		// before falling back to any implementation-specific date parsing, so that’s what we do, even if native
   111 		 * ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string
   112 		// implementations could be faster.
   112 		 * before falling back to any implementation-specific date parsing, so that’s what we do, even if native
       
   113 		 * implementations could be faster.
       
   114 		 */
   113 		//              1 YYYY                2 MM       3 DD           4 HH    5 mm       6 ss        7 msec        8 Z 9 ±    10 tzHH    11 tzmm
   115 		//              1 YYYY                2 MM       3 DD           4 HH    5 mm       6 ss        7 msec        8 Z 9 ±    10 tzHH    11 tzmm
   114 		if ( ( struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec( date ) ) ) {
   116 		if ( ( struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec( date ) ) ) {
   115 
   117 
   116 			// Avoid NaN timestamps caused by “undefined” values being passed to Date.UTC.
   118 			// Avoid NaN timestamps caused by “undefined” values being passed to Date.UTC.
   117 			for ( i = 0; ( k = numericKeys[i] ); ++i ) {
   119 			for ( i = 0; ( k = numericKeys[i] ); ++i ) {
   182 
   184 
   183 	/**
   185 	/**
   184 	 * Extract a route part based on negative index.
   186 	 * Extract a route part based on negative index.
   185 	 *
   187 	 *
   186 	 * @param {string}   route          The endpoint route.
   188 	 * @param {string}   route          The endpoint route.
   187 	 * @param {int}      part           The number of parts from the end of the route to retrieve. Default 1.
   189 	 * @param {number}   part           The number of parts from the end of the route to retrieve. Default 1.
   188 	 *                                  Example route `/a/b/c`: part 1 is `c`, part 2 is `b`, part 3 is `a`.
   190 	 *                                  Example route `/a/b/c`: part 1 is `c`, part 2 is `b`, part 3 is `a`.
   189 	 * @param {string}  [versionString] Version string, defaults to `wp.api.versionString`.
   191 	 * @param {string}  [versionString] Version string, defaults to `wp.api.versionString`.
   190 	 * @param {boolean} [reverse]       Whether to reverse the order when extracting the route part. Optional, default false.
   192 	 * @param {boolean} [reverse]       Whether to reverse the order when extracting the route part. Optional, default false.
   191 	 */
   193 	 */
   192 	wp.api.utils.extractRoutePart = function( route, part, versionString, reverse ) {
   194 	wp.api.utils.extractRoutePart = function( route, part, versionString, reverse ) {
   230 	};
   232 	};
   231 
   233 
   232 	/**
   234 	/**
   233 	 * Add args and options to a model prototype from a route's endpoints.
   235 	 * Add args and options to a model prototype from a route's endpoints.
   234 	 *
   236 	 *
   235 	 * @param {array}  routeEndpoints Array of route endpoints.
   237 	 * @param {Array}  routeEndpoints Array of route endpoints.
   236 	 * @param {Object} modelInstance  An instance of the model (or collection)
   238 	 * @param {Object} modelInstance  An instance of the model (or collection)
   237 	 *                                to add the args to.
   239 	 *                                to add the args to.
   238 	 */
   240 	 */
   239 	wp.api.utils.decorateFromRoute = function( routeEndpoints, modelInstance ) {
   241 	wp.api.utils.decorateFromRoute = function( routeEndpoints, modelInstance ) {
   240 
   242 
   244 		_.each( routeEndpoints, function( routeEndpoint ) {
   246 		_.each( routeEndpoints, function( routeEndpoint ) {
   245 
   247 
   246 			// Add post and edit endpoints as model args.
   248 			// Add post and edit endpoints as model args.
   247 			if ( _.includes( routeEndpoint.methods, 'POST' ) || _.includes( routeEndpoint.methods, 'PUT' ) ) {
   249 			if ( _.includes( routeEndpoint.methods, 'POST' ) || _.includes( routeEndpoint.methods, 'PUT' ) ) {
   248 
   250 
   249 				// Add any non empty args, merging them into the args object.
   251 				// Add any non-empty args, merging them into the args object.
   250 				if ( ! _.isEmpty( routeEndpoint.args ) ) {
   252 				if ( ! _.isEmpty( routeEndpoint.args ) ) {
   251 
   253 
   252 					// Set as default if no args yet.
   254 					// Set as default if no args yet.
   253 					if ( _.isEmpty( modelInstance.prototype.args ) ) {
   255 					if ( _.isEmpty( modelInstance.prototype.args ) ) {
   254 						modelInstance.prototype.args = routeEndpoint.args;
   256 						modelInstance.prototype.args = routeEndpoint.args;
   261 			} else {
   263 			} else {
   262 
   264 
   263 				// Add GET method as model options.
   265 				// Add GET method as model options.
   264 				if ( _.includes( routeEndpoint.methods, 'GET' ) ) {
   266 				if ( _.includes( routeEndpoint.methods, 'GET' ) ) {
   265 
   267 
   266 					// Add any non empty args, merging them into the defaults object.
   268 					// Add any non-empty args, merging them into the defaults object.
   267 					if ( ! _.isEmpty( routeEndpoint.args ) ) {
   269 					if ( ! _.isEmpty( routeEndpoint.args ) ) {
   268 
   270 
   269 						// Set as default if no defaults yet.
   271 						// Set as default if no defaults yet.
   270 						if ( _.isEmpty( modelInstance.prototype.options ) ) {
   272 						if ( _.isEmpty( modelInstance.prototype.options ) ) {
   271 							modelInstance.prototype.options = routeEndpoint.args;
   273 							modelInstance.prototype.options = routeEndpoint.args;
   323 				 *                        or 'date_modified_gmt'. Optional, defaults to 'date'.
   325 				 *                        or 'date_modified_gmt'. Optional, defaults to 'date'.
   324 				 */
   326 				 */
   325 				setDate: function( date, field ) {
   327 				setDate: function( date, field ) {
   326 					var theField = field || 'date';
   328 					var theField = field || 'date';
   327 
   329 
   328 					// Don't alter non parsable date fields.
   330 					// Don't alter non-parsable date fields.
   329 					if ( _.indexOf( parseableDates, theField ) < 0 ) {
   331 					if ( _.indexOf( parseableDates, theField ) < 0 ) {
   330 						return false;
   332 						return false;
   331 					}
   333 					}
   332 
   334 
   333 					this.set( theField, date.toISOString() );
   335 					this.set( theField, date.toISOString() );
   344 				 */
   346 				 */
   345 				getDate: function( field ) {
   347 				getDate: function( field ) {
   346 					var theField   = field || 'date',
   348 					var theField   = field || 'date',
   347 						theISODate = this.get( theField );
   349 						theISODate = this.get( theField );
   348 
   350 
   349 					// Only get date fields and non null values.
   351 					// Only get date fields and non-null values.
   350 					if ( _.indexOf( parseableDates, theField ) < 0 || _.isNull( theISODate ) ) {
   352 					if ( _.indexOf( parseableDates, theField ) < 0 || _.isNull( theISODate ) ) {
   351 						return false;
   353 						return false;
   352 					}
   354 					}
   353 
   355 
   354 					return new Date( wp.api.utils.parseISO8601( theISODate ) );
   356 					return new Date( wp.api.utils.parseISO8601( theISODate ) );
   356 			},
   358 			},
   357 
   359 
   358 			/**
   360 			/**
   359 			 * Build a helper function to retrieve related model.
   361 			 * Build a helper function to retrieve related model.
   360 			 *
   362 			 *
   361 			 * @param  {string} parentModel      The parent model.
   363 			 * @param {string} parentModel      The parent model.
   362 			 * @param  {int}    modelId          The model ID if the object to request
   364 			 * @param {number} modelId          The model ID if the object to request
   363 			 * @param  {string} modelName        The model name to use when constructing the model.
   365 			 * @param {string} modelName        The model name to use when constructing the model.
   364 			 * @param  {string} embedSourcePoint Where to check the embedds object for _embed data.
   366 			 * @param {string} embedSourcePoint Where to check the embedds object for _embed data.
   365 			 * @param  {string} embedCheckField  Which model field to check to see if the model has data.
   367 			 * @param {string} embedCheckField  Which model field to check to see if the model has data.
   366 			 *
   368 			 *
   367 			 * @return {Deferred.promise}        A promise which resolves to the constructed model.
   369 			 * @return {Deferred.promise}        A promise which resolves to the constructed model.
   368 			 */
   370 			 */
   369 			buildModelGetter = function( parentModel, modelId, modelName, embedSourcePoint, embedCheckField ) {
   371 			buildModelGetter = function( parentModel, modelId, modelName, embedSourcePoint, embedCheckField ) {
   370 				var getModel, embeddeds, attributes, deferred;
   372 				var getModel, embeddeds, attributes, deferred;
   410 			},
   412 			},
   411 
   413 
   412 			/**
   414 			/**
   413 			 * Build a helper to retrieve a collection.
   415 			 * Build a helper to retrieve a collection.
   414 			 *
   416 			 *
   415 			 * @param  {string} parentModel      The parent model.
   417 			 * @param {string} parentModel      The parent model.
   416 			 * @param  {string} collectionName   The name to use when constructing the collection.
   418 			 * @param {string} collectionName   The name to use when constructing the collection.
   417 			 * @param  {string} embedSourcePoint Where to check the embedds object for _embed data.
   419 			 * @param {string} embedSourcePoint Where to check the embedds object for _embed data.
   418 			 * @param  {string} embedIndex       An addiitonal optional index for the _embed data.
   420 			 * @param {string} embedIndex       An addiitonal optional index for the _embed data.
   419 			 *
   421 			 *
   420 			 * @return {Deferred.promise}        A promise which resolves to the constructed collection.
   422 			 * @return {Deferred.promise} A promise which resolves to the constructed collection.
   421 			 */
   423 			 */
   422 			buildCollectionGetter = function( parentModel, collectionName, embedSourcePoint, embedIndex ) {
   424 			buildCollectionGetter = function( parentModel, collectionName, embedSourcePoint, embedIndex ) {
   423 				/**
   425 				/**
   424 				 * Returns a promise that resolves to the requested collection
   426 				 * Returns a promise that resolves to the requested collection
   425 				 *
   427 				 *
   435 					deferred        = jQuery.Deferred();
   437 					deferred        = jQuery.Deferred();
   436 
   438 
   437 				postId    = parentModel.get( 'id' );
   439 				postId    = parentModel.get( 'id' );
   438 				embeddeds = parentModel.get( '_embedded' ) || {};
   440 				embeddeds = parentModel.get( '_embedded' ) || {};
   439 
   441 
   440 				// Verify that we have a valid post id.
   442 				// Verify that we have a valid post ID.
   441 				if ( ! _.isNumber( postId ) || 0 === postId ) {
   443 				if ( ! _.isNumber( postId ) || 0 === postId ) {
   442 					deferred.reject();
   444 					deferred.reject();
   443 					return deferred;
   445 					return deferred;
   444 				}
   446 				}
   445 
   447 
   509 				/**
   511 				/**
   510 				 * Get meta by key for a post.
   512 				 * Get meta by key for a post.
   511 				 *
   513 				 *
   512 				 * @param {string} key The meta key.
   514 				 * @param {string} key The meta key.
   513 				 *
   515 				 *
   514 				 * @return {object} The post meta value.
   516 				 * @return {Object} The post meta value.
   515 				 */
   517 				 */
   516 				getMeta: function( key ) {
   518 				getMeta: function( key ) {
   517 					var metas = this.get( 'meta' );
   519 					var metas = this.get( 'meta' );
   518 					return metas[ key ];
   520 					return metas[ key ];
   519 				},
   521 				},
   520 
   522 
   521 				/**
   523 				/**
   522 				 * Get all meta key/values for a post.
   524 				 * Get all meta key/values for a post.
   523 				 *
   525 				 *
   524 				 * @return {object} The post metas, as a key value pair object.
   526 				 * @return {Object} The post metas, as a key value pair object.
   525 				 */
   527 				 */
   526 				getMetas: function() {
   528 				getMetas: function() {
   527 					return this.get( 'meta' );
   529 					return this.get( 'meta' );
   528 				},
   530 				},
   529 
   531 
   530 				/**
   532 				/**
   531 				 * Set a group of meta key/values for a post.
   533 				 * Set a group of meta key/values for a post.
   532 				 *
   534 				 *
   533 				 * @param {object} meta The post meta to set, as key/value pairs.
   535 				 * @param {Object} meta The post meta to set, as key/value pairs.
   534 				 */
   536 				 */
   535 				setMetas: function( meta ) {
   537 				setMetas: function( meta ) {
   536 					var metas = this.get( 'meta' );
   538 					var metas = this.get( 'meta' );
   537 					_.extend( metas, meta );
   539 					_.extend( metas, meta );
   538 					this.set( 'meta', metas );
   540 					this.set( 'meta', metas );
   540 
   542 
   541 				/**
   543 				/**
   542 				 * Set a single meta value for a post, by key.
   544 				 * Set a single meta value for a post, by key.
   543 				 *
   545 				 *
   544 				 * @param {string} key   The meta key.
   546 				 * @param {string} key   The meta key.
   545 				 * @param {object} value The meta value.
   547 				 * @param {Object} value The meta value.
   546 				 */
   548 				 */
   547 				setMeta: function( key, value ) {
   549 				setMeta: function( key, value ) {
   548 					var metas = this.get( 'meta' );
   550 					var metas = this.get( 'meta' );
   549 					metas[ key ] = value;
   551 					metas[ key ] = value;
   550 					this.set( 'meta', metas );
   552 					this.set( 'meta', metas );
   585 				/**
   587 				/**
   586 				 * Set the tags for a post.
   588 				 * Set the tags for a post.
   587 				 *
   589 				 *
   588 				 * Accepts an array of tag slugs, or a Tags collection.
   590 				 * Accepts an array of tag slugs, or a Tags collection.
   589 				 *
   591 				 *
   590 				 * @param {array|Backbone.Collection} tags The tags to set on the post.
   592 				 * @param {Array|Backbone.Collection} tags The tags to set on the post.
   591 				 *
   593 				 *
   592 				 */
   594 				 */
   593 				setTags: function( tags ) {
   595 				setTags: function( tags ) {
   594 					var allTags, newTag,
   596 					var allTags, newTag,
   595 						self = this,
   597 						self = this,
   631 				/**
   633 				/**
   632 				 * Set the tags for a post.
   634 				 * Set the tags for a post.
   633 				 *
   635 				 *
   634 				 * Accepts a Tags collection.
   636 				 * Accepts a Tags collection.
   635 				 *
   637 				 *
   636 				 * @param {array|Backbone.Collection} tags The tags to set on the post.
   638 				 * @param {Array|Backbone.Collection} tags The tags to set on the post.
   637 				 *
   639 				 *
   638 				 */
   640 				 */
   639 				setTagsWithCollection: function( tags ) {
   641 				setTagsWithCollection: function( tags ) {
   640 
   642 
   641 					// Pluck out the category ids.
   643 					// Pluck out the category IDs.
   642 					this.set( 'tags', tags.pluck( 'id' ) );
   644 					this.set( 'tags', tags.pluck( 'id' ) );
   643 					return this.save();
   645 					return this.save();
   644 				}
   646 				}
   645 			},
   647 			},
   646 
   648 
   669 				/**
   671 				/**
   670 				 * Set the categories for a post.
   672 				 * Set the categories for a post.
   671 				 *
   673 				 *
   672 				 * Accepts an array of category slugs, or a Categories collection.
   674 				 * Accepts an array of category slugs, or a Categories collection.
   673 				 *
   675 				 *
   674 				 * @param {array|Backbone.Collection} categories The categories to set on the post.
   676 				 * @param {Array|Backbone.Collection} categories The categories to set on the post.
   675 				 *
   677 				 *
   676 				 */
   678 				 */
   677 				setCategories: function( categories ) {
   679 				setCategories: function( categories ) {
   678 					var allCategories, newCategory,
   680 					var allCategories, newCategory,
   679 						self = this,
   681 						self = this,
   716 				/**
   718 				/**
   717 				 * Set the categories for a post.
   719 				 * Set the categories for a post.
   718 				 *
   720 				 *
   719 				 * Accepts Categories collection.
   721 				 * Accepts Categories collection.
   720 				 *
   722 				 *
   721 				 * @param {array|Backbone.Collection} categories The categories to set on the post.
   723 				 * @param {Array|Backbone.Collection} categories The categories to set on the post.
   722 				 *
   724 				 *
   723 				 */
   725 				 */
   724 				setCategoriesWithCollection: function( categories ) {
   726 				setCategoriesWithCollection: function( categories ) {
   725 
   727 
   726 					// Pluck out the category ids.
   728 					// Pluck out the category IDs.
   727 					this.set( 'categories', categories.pluck( 'id' ) );
   729 					this.set( 'categories', categories.pluck( 'id' ) );
   728 					return this.save();
   730 					return this.save();
   729 				}
   731 				}
   730 			},
   732 			},
   731 
   733 
   833 			 * Set nonce header before every Backbone sync.
   835 			 * Set nonce header before every Backbone sync.
   834 			 *
   836 			 *
   835 			 * @param {string} method.
   837 			 * @param {string} method.
   836 			 * @param {Backbone.Model} model.
   838 			 * @param {Backbone.Model} model.
   837 			 * @param {{beforeSend}, *} options.
   839 			 * @param {{beforeSend}, *} options.
   838 			 * @returns {*}.
   840 			 * @return {*}.
   839 			 */
   841 			 */
   840 			sync: function( method, model, options ) {
   842 			sync: function( method, model, options ) {
   841 				var beforeSend;
   843 				var beforeSend;
   842 
   844 
   843 				options = options || {};
   845 				options = options || {};
   853 				}
   855 				}
   854 
   856 
   855 				if ( _.isFunction( model.nonce ) && ! _.isEmpty( model.nonce() ) ) {
   857 				if ( _.isFunction( model.nonce ) && ! _.isEmpty( model.nonce() ) ) {
   856 					beforeSend = options.beforeSend;
   858 					beforeSend = options.beforeSend;
   857 
   859 
   858 					// @todo enable option for jsonp endpoints
   860 					// @todo Enable option for jsonp endpoints.
   859 					// options.dataType = 'jsonp';
   861 					// options.dataType = 'jsonp';
   860 
   862 
   861 					// Include the nonce with requests.
   863 					// Include the nonce with requests.
   862 					options.beforeSend = function( xhr ) {
   864 					options.beforeSend = function( xhr ) {
   863 						xhr.setRequestHeader( 'X-WP-Nonce', model.nonce() );
   865 						xhr.setRequestHeader( 'X-WP-Nonce', model.nonce() );
   986 			 * Set nonce header before every Backbone sync.
   988 			 * Set nonce header before every Backbone sync.
   987 			 *
   989 			 *
   988 			 * @param {string} method.
   990 			 * @param {string} method.
   989 			 * @param {Backbone.Model} model.
   991 			 * @param {Backbone.Model} model.
   990 			 * @param {{success}, *} options.
   992 			 * @param {{success}, *} options.
   991 			 * @returns {*}.
   993 			 * @return {*}.
   992 			 */
   994 			 */
   993 			sync: function( method, model, options ) {
   995 			sync: function( method, model, options ) {
   994 				var beforeSend, success,
   996 				var beforeSend, success,
   995 					self = this;
   997 					self = this;
   996 
   998 
  1061 
  1063 
  1062 			/**
  1064 			/**
  1063 			 * Fetches the next page of objects if a new page exists.
  1065 			 * Fetches the next page of objects if a new page exists.
  1064 			 *
  1066 			 *
  1065 			 * @param {data: {page}} options.
  1067 			 * @param {data: {page}} options.
  1066 			 * @returns {*}.
  1068 			 * @return {*}.
  1067 			 */
  1069 			 */
  1068 			more: function( options ) {
  1070 			more: function( options ) {
  1069 				options = options || {};
  1071 				options = options || {};
  1070 				options.data = options.data || {};
  1072 				options.data = options.data || {};
  1071 
  1073 
  1087 			},
  1089 			},
  1088 
  1090 
  1089 			/**
  1091 			/**
  1090 			 * Returns true if there are more pages of objects available.
  1092 			 * Returns true if there are more pages of objects available.
  1091 			 *
  1093 			 *
  1092 			 * @returns null|boolean.
  1094 			 * @return {null|boolean}
  1093 			 */
  1095 			 */
  1094 			hasMore: function() {
  1096 			hasMore: function() {
  1095 				if ( null === this.state.totalPages ||
  1097 				if ( null === this.state.totalPages ||
  1096 					 null === this.state.totalObjects ||
  1098 					 null === this.state.totalObjects ||
  1097 					 null === this.state.currentPage ) {
  1099 					 null === this.state.currentPage ) {
  1338 						// Include the array of route endpoints for easy reference.
  1340 						// Include the array of route endpoints for easy reference.
  1339 						endpoints: modelRoute.route.endpoints
  1341 						endpoints: modelRoute.route.endpoints
  1340 					} );
  1342 					} );
  1341 				} else {
  1343 				} else {
  1342 
  1344 
  1343 					// This is a model without a parent in its route
  1345 					// This is a model without a parent in its route.
  1344 					modelClassName = wp.api.utils.capitalizeAndCamelCaseDashes( routeName );
  1346 					modelClassName = wp.api.utils.capitalizeAndCamelCaseDashes( routeName );
  1345 					modelClassName = mapping.models[ modelClassName ] || modelClassName;
  1347 					modelClassName = mapping.models[ modelClassName ] || modelClassName;
  1346 					loadingObjects.models[ modelClassName ] = wp.api.WPApiBaseModel.extend( {
  1348 					loadingObjects.models[ modelClassName ] = wp.api.WPApiBaseModel.extend( {
  1347 
  1349 
  1348 						// Function that returns a constructed url based on the id.
  1350 						// Function that returns a constructed url based on the ID.
  1349 						url: function() {
  1351 						url: function() {
  1350 							var url = routeModel.get( 'apiRoot' ) +
  1352 							var url = routeModel.get( 'apiRoot' ) +
  1351 								routeModel.get( 'versionString' ) +
  1353 								routeModel.get( 'versionString' ) +
  1352 								( ( 'me' === routeName ) ? 'users/me' : routeName );
  1354 								( ( 'me' === routeName ) ? 'users/me' : routeName );
  1353 
  1355 
  1491 	wp.api.endpoints = new Backbone.Collection();
  1493 	wp.api.endpoints = new Backbone.Collection();
  1492 
  1494 
  1493 	/**
  1495 	/**
  1494 	 * Initialize the wp-api, optionally passing the API root.
  1496 	 * Initialize the wp-api, optionally passing the API root.
  1495 	 *
  1497 	 *
  1496 	 * @param {object} [args]
  1498 	 * @param {Object} [args]
  1497 	 * @param {string} [args.nonce] The nonce. Optional, defaults to wpApiSettings.nonce.
  1499 	 * @param {string} [args.nonce] The nonce. Optional, defaults to wpApiSettings.nonce.
  1498 	 * @param {string} [args.apiRoot] The api root. Optional, defaults to wpApiSettings.root.
  1500 	 * @param {string} [args.apiRoot] The api root. Optional, defaults to wpApiSettings.root.
  1499 	 * @param {string} [args.versionString] The version string. Optional, defaults to wpApiSettings.root.
  1501 	 * @param {string} [args.versionString] The version string. Optional, defaults to wpApiSettings.root.
  1500 	 * @param {object} [args.schema] The schema. Optional, will be fetched from API if not provided.
  1502 	 * @param {Object} [args.schema] The schema. Optional, will be fetched from API if not provided.
  1501 	 */
  1503 	 */
  1502 	wp.api.init = function( args ) {
  1504 	wp.api.init = function( args ) {
  1503 		var endpoint, attributes = {}, deferred, promise;
  1505 		var endpoint, attributes = {}, deferred, promise;
  1504 
  1506 
  1505 		args                      = args || {};
  1507 		args                      = args || {};
  1512 			attributes.schema = wpApiSettings.schema;
  1514 			attributes.schema = wpApiSettings.schema;
  1513 		}
  1515 		}
  1514 
  1516 
  1515 		if ( ! initializedDeferreds[ attributes.apiRoot + attributes.versionString ] ) {
  1517 		if ( ! initializedDeferreds[ attributes.apiRoot + attributes.versionString ] ) {
  1516 
  1518 
  1517 			// Look for an existing copy of this endpoint
  1519 			// Look for an existing copy of this endpoint.
  1518 			endpoint = wp.api.endpoints.findWhere( { 'apiRoot': attributes.apiRoot, 'versionString': attributes.versionString } );
  1520 			endpoint = wp.api.endpoints.findWhere( { 'apiRoot': attributes.apiRoot, 'versionString': attributes.versionString } );
  1519 			if ( ! endpoint ) {
  1521 			if ( ! endpoint ) {
  1520 				endpoint = new Endpoint( attributes );
  1522 				endpoint = new Endpoint( attributes );
  1521 			}
  1523 			}
  1522 			deferred = jQuery.Deferred();
  1524 			deferred = jQuery.Deferred();