I am trying to load posts outside WordPress on a static html page. So far I have a working example using React, http://v2.wp-api.org/ and https://github.com/mzabriskie/axios. This working example using react currently displays the posts properly but it is fragile and there is no fall back. Codepen example here, https://codepen.io/krogsgard/pen/NRBqPp/
I use this example to get my feed source using axios axios.get(this.props.source). Then I use the examples react function to grab my latest three posts, including titles and images and load them into a static html page via
render: function render() {
return React.createElement(
"div",
{ className: "post-wrapper" },
this.state.posts.map(function (post) {
return React.createElement(
"div",
{ key: post.link, className: "post" },
React.createElement(
"h2",
{ className: "post-title" },
React.createElement("a", {
href: post.link,
dangerouslySetInnerHTML: { __html: post.title.rendered }
})
),
post.featured_media ? React.createElement(
"a",
{ href: post.link },
React.createElement("img", { src: post._embedded['wp:featuredmedia'][0].source_url })
) : null
);
})
);
}
My blog's source wp json is
React.render(React.createElement(App, { source:
"myBlogURL.com/wp-json/wp/v2/posts/?_embed&per_page=3" }),
document.querySelector("#blog-post"));
Which correctly loads my latest 3 blog posts into the <div id="blog-posts">
I'm looking for a vanilla js way to do this with some fallback helpers. In case I forget to include the featured image to a post, the posts will not fail to load. Any ideas or examples would greatly be appreciated!
You are working way to hard for this. Wordpress CMS is designed for stuff like this. You are able to display posts in the form of a RSS feed by categories, tags and other taxonomies. pretty easily
• If you are not too good with code, you can find many widgets that'll take care of most of the work.
• If you need to do it yourself, below should get you there with JSON / jQuery.
<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js'></script>
<script type="text/javascript">
var MYBLOG_LIMIT = 3;
var MYWRAPPER_CLASS = 'homeblog';
var WP={open:function(b){var a={posts:function(){var d=MYBLOG_LIMIT;var e=0;var c={all:function(g){var f=b+"/api/get_recent_posts/";f+="?count="+d+"&page="+e+"&callback=?";jQuery.getJSON(f,function(l){var k=l.posts;for(var j=0;j<k.length;j++){var h=k[j];h.createComment=function(i,m){i.postId=h.id;a.comments().create(i,m)}}g(k)})},findBySlug:function(f,h){var g=b+"/api/get_post/";g+="?slug="+f+"&callback=?";jQuery.getJSON(g,function(i){h(i.post)})},limit:function(f){d=f;return c},page:function(f){e=f;return c}};return c},pages:function(){var c={findBySlug:function(d,f){var e=b+"/api/get_page/";e+="?slug="+d+"&callback=?";jQuery.getJSON(e,function(g){f(g.page)})}};return c},categories:function(){var c={all:function(e){var d=b+"/api/get_category_index/";d+="?callback=?";jQuery.getJSON(d,function(f){e(f.categories)})}};return c},tags:function(){var c={all:function(e){var d=b+"/api/get_tag_index/";d+="?callback=?";jQuery.getJSON(d,function(f){e(f.tags)})}};return c},comments:function(){var c={create:function(f,e){var d=b+"/api/submit_comment/";d+="?post_id="+f.postId+"&name="+f.name+"&email="+f.email+"&content="+f.content+"&callback=?";jQuery.getJSON(d,function(g){e(g)})}};return c}};return a}};
var blog = WP.open('https://www.fldtrace.com');
blog.posts().all(function(posts){
for(var i = 0; i < posts.length; i++){
jQuery('.'+MYWRAPPER_CLASS).append(function(){
return (posts[i].thumbnail) ? '<a class="lastpost_title" href="'+posts[i].url+'">
<h4>'+posts[i].title+'</h4>
</a><img src="'+posts[i].thumbnail+'"/>' : '<a href="'+posts[i].url+'">
<h4>'+posts[i].title+'</h4>
</a>';
});
}
});
</script>
<div class="homeblog">
</div>
You need to configure the next options
var MYBLOG_LIMIT = 1; will define how many posts will show. By default
is 1. var MYWRAPPER_CLASS = ‘homeblog’; – the class name of HTML
element where the post(s) will be shown. var blog =
WP.open(‘https://www.fldtrace.com/’); – this should link to your blog
main domain (mandatory) by default, will be shown the post thumbnail
and title both linked. The rest is CSS customization, including
adjusting the thumbnail size.
Read more here at source article.
Related
I am currently building a small Handlebars.js application. I have no prior experience and as I'm learning as I'm going along, I've been running in to a few issues.
My first issue is loading templates.
Currently I have functions like this for every single template I need to load
var populateDocs = function() {
var srcContent = $( '#docs-template' ).html(),
contentTemplate = Handlebars.compile( srcContent ),
htmlContent = contentTemplate( content.getItem( 'docs' ) );
$( '#docs' ).append( htmlContent );
};
I am reading templates from a content.json file so once this file is ready, I call multiple functions to populate each template.
content.onReady(
function() {
populateFooter();
populateHomework();
populateDocs();
populateContact();
generateTabs();
}
);
My question is. Is there a way I can load all these templates without having to call each function for each template?
I rather think the best you can do is to proceduralise things better.
If all the populateXxx() functions follow the same pattern as populateDocs() (or can be made to do so), then you can write :
var populate = function(id) {
$('#'+id).append(Handlebars.compile($('#'+id+'-template').html())(content.getItem(id)));
};
content.onReady(function() {
populate('footer');
populate('homework');
populate('docs');
populate('contact');
generateTabs();
});
or
content.onReady(function() {
['footer', 'homework', 'docs', 'contact'].forEach(populate);
generateTabs();
});
I want to create an element that users can insert it in the editor.
The hard part is that it needs to be shown differently from its source.
For example, I want to users insert this in the preview part:
23
And in the source part it should be shown like this:
<span class="tagSpecialClass">{{birthYear}}</span>
The main purpose is to show the mustache tags in a way that users can avoid writing them and just insert them from toolbar that automatically inserts the correct html and preview to it.
My issue is my understanding over CKEditor and the terms I need to read about them in order to implement such a plugin.
How can I force CKEditor to parse/compile/preview a specific tag differently?
Please tell me if my question is too generic!
This sounds like a job for CKEditor widgets (demos)!
Please take a look at the following example (JSFiddle). It will give you some basic idea how to use widgets to solve your problem. If you follow this official tutorial, you'll know how to implement editable parts in your widgets and enable editing with dialogs, which also might be helpful.
// Some CSS for the widget to make it more visible.
CKEDITOR.addCss( '.tagSpecialClass { background: green; padding: 3px; color: #fff } ' );
CKEDITOR.replace( 'editor', {
// A clean-up in the toolbar to focus on essentials.
toolbarGroups: [
{ name: 'document', groups: [ 'mode' ] },
{ name: 'basicstyles' },
{ name: 'insert' }
],
removeButtons: 'Image,Table,HorizontalRule,SpecialChar',
extraPlugins: 'widget',
on: {
pluginsLoaded: function() {
var editor = this;
// Define a new widget. This should be done in a separate plugin
// to keep things clear and maintainable.
editor.widgets.add( 'sampleWidget', {
// This will be inserted into the editor if the button is clicked.
template: '<span class="tagSpecialClass">23</span>',
// A rule for ACF, which permits span.tagSpecialClass in this editor.
allowedContent: 'span(tagSpecialClass)',
// When editor is initialized, this function will be called
// for every single element. If element matches, it will be
// upcasted as a "sampleWidget".
upcast: function( el ) {
return el.name == 'span' && el.hasClass( 'tagSpecialClass' );
},
// This is what happens with existing widget, when
// editor data is returned (called editor.getData() or viewing source).
downcast: function( el ) {
el.setHtml( '{{birthYear}}' );
},
// This could be done in upcast. But let's do it here
// to show that there's init function, which, unlike
// upcast, works on real DOM elements.
init: function() {
this.element.setHtml( '23' );
}
} );
// Just a button to show that "sampleWidget"
// becomes a command.
editor.ui.addButton && editor.ui.addButton( 'SampleWidget', {
label: 'Some label',
command: 'sampleWidget',
toolbar: 'insert,0'
} );
}
}
} );
HTML
<textarea id="editor">
<p>Some text.</p>
<p>And there's the widget <span class="tagSpecialClass">{{birthYear}}</span></p>
<p>Some text <span class="tagSpecialClass">{{birthYear}}</span>.</p>
</textarea>
Happy coding!
I'm trying to get Magnific Popup to display a title based on other elements around the target it uses. Given the following markup, I want the title to be "Foobar".
<div class="container">
<article>
<h2>Foo</h2>
<figure>
<a href="img/img-1.jpg">
<img src="img/img-1.jpg" />
</a>
<figcaption>
bar1
</figcaption>
</figure>
</article>
<article>
<h2>Foo</h2>
<figure>
<a href="img/img-2.jpg">
<img src="img/img-2.jpg" />
</a>
<figcaption>
bar2
</figcaption>
</figure>
</article>
</div>
What I've tried while looking for solutions online (including this one on StackOverflow) is the following code:
$('.container').magnificPopup({
delegate: 'article figure a',
type: 'image',
titleSrc: function(item) {
return item.el.parent('article').find('h2').text() + item.el.parent('article').find('figcaption').text();
},
gallery:{enabled:true}
});
Figuring the function might have been an issue I've even tried to simply return a constant string, but that seemed to do nothing:
titleSrc: function(item) {
return "fake Foobar";
}
Does anyone have any clues as what I'm doing wrong?
NOTE: It does work if I use titleSrc: 'title', but that's not the behavior I want, as it makes me have to duplicate content in the markup.
As per documentation titleSrc:{} should be inside image:{} and you can use item.el.parents() instead of item.el.parent().
Corrected Code
$('.container').magnificPopup({
delegate: 'article figure a',
type: 'image',
gallery:{enabled:true},
image: {
titleSrc: function(item) {
return item.el.parents('article').find('h2').html() + item.el.parents('article').find('figcaption').html();
}
}
});
My designed required me to have a title & description with each Image slide hence I required a custom title in magnific popup, I tried the answer from #krizna but I was only getting the title, to debug I went into js file of the magnefic popup (jquery.magnefic-popup.js) and found the function which gets called when custom Markup is parsed it is called appropriately "_getTitle".It get an item object as parameter.I logged this item object to find it had data attribute in which our item parameter goes.
I initialised the popup using items option (3rd way to initialise in the docs) here is my custom item object
items: [
{
src: 'https://c6.staticflickr.com/9/8785/16698139093_3c30729f1b.jpg"',
title: 'We buy Nike shoes',
description:'You might ask, why PhotoSwipe doesn\'t add this code automatically via JS, reason is simple – just to save file size, in case if you need some modification of layout'
},
{
src: 'https://c2.staticflickr.com/8/7662/17307905305_92ae5081bf_b.jpg"',
title: 'You can add HTML code dynamically via JS (directly before the initialization), or have it in the page initially (like it\'s done on the demo page)',
description:'You might ask, why PhotoSwipe doesn\'t add this code automatically via JS, reason is simple – just to save file size, in case if you need some modification of layout'
},
{
src: 'https://farm2.staticflickr.com/1043/5186867718_06b2e9e551_b.jpg',
title: 'Avoid serving big images (larger than 2000x1500px) for mobile, as they will dramatically reduce animation performanc',
description:'You might ask, why PhotoSwipe doesn\'t add this code automatically via JS, reason is simple – just to save file size, in case if you need some modification of layout'
}
],
each item has src of image, a title & a description , now my titleSrc function is
titleSrc: function(item) {
return '<p id="gallery-image-title">' + item.data.title +'</p>' + '<p id="gallery-image-description">' + item.data.description +'</p>';
}
I also modified the "_getTitle" function because it only parsed title property in item object(commented the first two lines), my "_getTitle" now looks like this
_getTitle = function(item) {
console.log(item);
/*if(item.data && item.data.title !== undefined)
return item.data.title;*/
var src = mfp.st.image.titleSrc;
if(src) {
if($.isFunction(src)) {
return src.call(mfp, item);
} else if(item.el) {
return item.el.attr(src) || '';
}
}
return '';
};
Now I have control over markup & have 2 dynamic src for title property.
I'm working with backbone.js, but as far as I've seen, it doesn't care what templating system you use. Currently I'm trying out mustache.js, but I'm open to other ones. I'm a little annoyed though with the way I have to put a template into a string:
var context = {
name: this.model.get('name'),
email: this.model.get('email')
}
var template = "<form>Name<input name='name' type='text' value='{{name}}' />Email<input name='email' type='text' value='{{email}}' /></form>";
var html = Mustache.to_html(template, context);
$(this.el).html(html);
$('#app').html(this.el);
I'd like if I could load it from a different file or something somehow. I want to be able to have template files in order to simplify things. For example, if I put it all in a string, I can't have breaks (well I can have html breaks, but that's not the point). After the line starts to get very long, it becomes unmanageable.
Tips?
Updated (4/11/14):
As answered by OP below:
Unfortunately, the jQuery team has moved the templating functionality out of jQuery Core. The code is still available as a library here: github.com/BorisMoore/jquery-tmpl and here: github.com/borismoore/jsrender
Original Answer:
I just used this a couple of hours ago:
http://api.jquery.com/category/plugins/templates/
It's an official jQuery plugin(i.e. the devs endorse it).
This is the function you need to use for loading templates from things other than strings: http://api.jquery.com/template/
Here's the code to have a template in HTML:
<script id="titleTemplate" type="text/x-jquery-tmpl">
<li>${Name}</li>
</script>
___________
// Compile the inline template as a named template
$( "#titleTemplate" ).template( "summaryTemplate" );
function renderList() {
// Render the movies data using the named template: "summaryTemplate"
$.tmpl( "summaryTemplate", movies ).appendTo( "#moviesList" );
}
It's in a <script> tag, because that's not visible by default.
Note the type="text/x-jquery-tmpl". If you omit that, it will try to parse it as JavaScript(and fail horribly).
Also note that "loading from a different file" is essentially the same as "reading a file" and then "loading from a string".
Edit
I just found this jQuery plugin - http://markdalgleish.com/projects/tmpload/ Does exactly what you want, and can be coupled with $.tmpl
I have built a lightweight template manager that loads templates via Ajax, which allows you to separate the templates into more manageable modules. It also performs simple, in-memory caching to prevent unnecessary HTTP requests. (I have used jQuery.ajax here for brevity)
var TEMPLATES = {};
var Template = {
load: function(url, fn) {
if(!TEMPLATES.hasOwnProperty(url)) {
$.ajax({
url: url,
success: function(data) {
TEMPLATES[url] = data;
fn(data);
}
});
} else {
fn(TEMPLATES[url]);
}
},
render: function(tmpl, context) {
// Apply context to template string here
// using library such as underscore.js or mustache.js
}
};
You would then use this code as follows, handling the template data via callback:
Template.load('/path/to/template/file', function(tmpl) {
var output = Template.render(tmpl, { 'myVar': 'some value' });
});
We are using jqote2 with backbone because it's faster than jQuery's, as you say there are many :)
We have all our templates in a single tpl file, we bind to our template_rendered so we can add jquery events etc etc
App.Helpers.Templates = function() {
var loaded = false;
var templates = {};
function embed(template_id, parameters) {
return $.jqote(templates[template_id], parameters);
}
function render(template_id, element, parameters) {
var render_template = function(e) {
var r = embed(template_id, parameters);
$(element).html(r);
$(element).trigger("template_rendered");
$(document).unbind(e);
};
if (loaded) {
render_template();
} else {
$(document).bind("templates_ready", render_template);
}
}
function load_templates() {
$.get('/javascripts/backbone/views/templates/templates.tpl', function(doc) {
var tpls = $(doc).filter('script');
tpls.each(function() {
templates[this.id] = $.jqotec(this);
});
loaded = true;
$(document).trigger("templates_ready");
});
}
load_templates();
return {
render: render,
embed: embed
};
}();
They look like
<script id="table" data-comment="generated!!!!! to change please change table.tpl">
<![CDATA[
]]>
</script>
I have a div that basically represents a book (so a nice div layout with an image of the book, title, price, red background if on sale etc.). So what i do is to get the properties of a book from the database, insert the values in kind of an html template and display it.
Now, once it is displayed i hate how i have to handle the data. I have to either parse css properties to figure out if a book is on sale for an example or i have to keep the data in another place as well (some javascript array or use the jquery data feature). The first option is ugly the second one would require me to update two things when one property changes - which is ugly as well.
So what i would like is to handle that block of html (that represents a single book) as an object. Where i can call obj.setPrice(30); and things like that and finally call obj.update(); so it would update its appearance.
Is there anyway to accomplish this ? Or something like this ? I just feel that once i render the data as html i loose control over it :(
Suppose your html div is like this
<div id="book1">
<div id="price">$30</div>
...
</div>
You can define a Book object as follows:
var Book = function(name) {
this.name = name;
}
Book.prototype = {
setPrice : function(price) {
this.price = price;
},
update : function() {
pricediv = document.getElementById(this.name)
pricediv.innerHTML = '$'+price;
}
}
var book = new Book('book1')
book.setPrice(50);
book.update();
I guess your best shot is write your own object / methods for that.
var Book = function(){
var price = args.price || 0,
color = args.color || 'red',
height = args.height || '200px',
width = args.width || '600px',
template = "<div style='background-color: COLOR; width=WIDTH; height: HEIGHT;'><span>$PRICE</span><br/></div>";
return {
setPrice: function(np){
price = np;
return this;
},
setColor: function(nc){
color = nc;
return this;
},
setHeight: function(nh){
height = nh;
return this;
},
render: function(){
template = template.replace(/COLOR/, color);
template = template.replace(/PRICE/, price);
// etc
// use jQuery or native javascript to form and append your html
$(template).appendTo(document.body);
}
};
};
This is just a pretty basic example which can be optimized like a lot. You may even think about using John Resigs microtemplate (http://ejohn.org/blog/javascript-micro-templating/)
Usage from the above example would look like:
var book = Book({
price: 30,
color: 'blue'
});
book.render();
To change values:
book.setPrice(140).setColor('yellow').setHeight('500').render();
I have been playing around with Microsoft's proposal for jQuery Templates and Data Linking and so far it's going awesome.
TLDR, checkout this demo.
It's extremely easy to just link up a piece of HTML with a JavaScript object and from thereon, only update the JavaScript object and the HTML updates automatically.
Here's a simple example. Create the HTML that will represent your widget.
<div class="book">
<img width="100" height="100" src="" />
<div class="title"></div>
<div class="price"></div>
</div>
Then create a JavaScript object and dynamically link it to the HTML above. Here is a sample object:
var book = {
title: "Alice in Wonderland",
price: 24.99,
onSale: true,
image: "http://bit.ly/cavCXS"
};
Now onto the actual linking part. The items we are going to link up are:
A data-onsale attribute in the outer div which will be either "true" or "false"
The image src attribute to the image property of our book
title div to the title property
price div to the price property
The following sets up the linking. Note that we are only doing a one way linking here, but it's possible to setup a two way linking also using the linkBoth function.
$(book)
.linkTo('title', '.title', 'html')
.linkTo('price', '.price', 'html')
.linkTo('image', '.book img', 'src')
.linkTo('onSale', '.book', 'data-onsale')
That's it. From now onwards, just update the book object and the HTML will automatically update. Update the properties of the book like you would update html attributes using the attr function.
$(book).attr({
price: 14.75
});
or
$(book).attr('price', 14.75);
The code above is only using Data Linking, but the proposal also mentions combining data linking with templates which would make this even more easier. From what I reckon, you would be able to do this and get the above functionality:
<script id="bookTemplate" type="text/html">
<div class="book" data-onsale="{{link onSale }}">
<img width="100" height="100" src="{{link image }}" />
<div class="title">{{link title }}</div>
<div class="price">{{link price }}</div>
</div>
</script>
Link the above template with the book object in one step and add it to the page:
$('#bookTemplate').render(book).appendTo('body')
Update the properties of the book object, and changes will reflect.