i'm struggeling with one challenge to do in my custom theme for Wordpress. I want to have content specific controls in my Theme Customizer. I know there is option "active_callback", but this is not sufficient for my purpose and i read 2 documentation articles about customizer and this https://make.wordpress.org/core/2014/07/08/customizer-improvements-in-4-0/ article, but still have no clue, here is what i want to achieve:
For example, i want to have "show sidebar" checkbox, but this checkbox should be more contextual specifix. For example, when i will be on homepage, there will be just one checkbox as "Show sidebar default" but when i will go into some post, i want there 3 checkboxes:
"Show sidebar default" - id="show_sidebar"
"Show sidebar in Post archive page" - id="show_sidebar_archive_{post_type}"
"Show sidebar for this post" - id="show_sidebar_singular_{post_id}"
So when i want to have this kind of specific IDs for control, just active_callback is not enought, becauce it can just show/hide controls, i can't create new when URL in iframe changes.
There could be 2 sollutions:
1. Better - when i could somehow create/remove controls by context, it would be best solution. If it's somehow possible with customizer API, give me som hint please
2. Not good, but sufficient - is at least possible somehow reload whole /wp-admin/customize.php?url= with new clicked url? this could be enought for a while
thx for any advices!
Ok, i figured out that second solution, here is code. It's enought for me for now.
'use strict';
(function ($) {
/**
* This is important fix for Theme Customizer
* It will change whole customizer url, because we need to load
* all controls ahan for new url, because of hierarchical options
*/
if ( /\/customize\.php$/.test( window.location.pathname ) ) {
wp.customize.bind( 'preview-ready', function() {
var body = $( 'body' );
body.off( 'click.preview' );
body.on( 'click.preview', 'a[href]', function( event ) {
var link, isInternalJumpLink;
link = $( this );
isInternalJumpLink = ( '#' === link.attr( 'href' ).substr( 0, 1 ) );
event.preventDefault();
if ( isInternalJumpLink && '#' !== link.attr( 'href' ) ) {
$( link.attr( 'href' ) ).each( function() {
this.scrollIntoView();
} );
}
/*
* Note the shift key is checked so shift+click on widgets or
* nav menu items can just result on focusing on the corresponding
* control instead of also navigating to the URL linked to.
*/
if ( event.shiftKey || isInternalJumpLink ) {
return;
}
//self.send( 'scroll', 0 );
//self.send( 'url', link.prop( 'href' ) );
var newUrl = link.prop( 'href' );
var currentUrl = window.location.href;
var customizeUrl = currentUrl.substring(0, currentUrl.indexOf("?url=") + 5) + newUrl;
// Reload whole customizer for new url
window.parent.location.replace(customizeUrl);
});
} );
}
})(jQuery);
//# sourceMappingURL=customizer.js.map
Related
I'd like to add pagination to the latest posts gutenberg block. This block fetches posts through withSelect() and getEntityRecords(), similar to the block editor handbook.
The REST API returns two handy header fields for use in pagination:
"X-WP-Total" and "X-WP-TotalPages"
https://developer.wordpress.org/rest-api/using-the-rest-api/pagination/
Does anyone know if its possible to access these header fields in a dynamic block which fetches posts through withSelect() and getEntityRecords() and set state for the total number of pages and the current page?
Here's the simplyfied version of block.js:
( function( blocks, element, data ) {
var registerBlockType = blocks.registerBlockType,
withSelect = data.withSelect;
registerBlockType( 'mdwpb/latest-posts', {
title: 'latest posts',
icon: 'megaphone',
category: 'widgets',
attributes: {},
edit: withSelect( function( select ) {
return {
// here's where the magic happens, I think..
posts: select( 'core' ).getEntityRecords( 'postType', 'post', {per_page: 1, page: 1})
numberOfPages: ?,
};
} )( function( props ) {
if ( ! props.posts ) {
return "Loading...";
}
if ( props.posts.length === 0 ) {
return "No posts";
}
var className = props.className;
var post = props.posts[ 0 ];
return (
<div>
{ props.posts.map( ( post ) => (
<h3 className={props.className}>
{post.title.rendered}
</h3>
))}
</div>
);
} ),
} );
}(
window.wp.blocks,
window.wp.element,
window.wp.data,
) );
I tried adding the numberOfPages to the withSelect function through an apiFetch:
numberOfPages: wp.apiFetch({
path: wp.url.addQueryArgs( 'wp/v2/posts', {per_page: 1, page: 1} ),
parse: false,
}).then( response => { return response.headers.get('X-WP-TotalPages'); } ),
This kindof works, but I get a promise when I use console.log of the numberOfPages prop in the function(props). So I feel adding a apiFetch to the withSelect is not the way to go, or is it?
I haven't found a solution to properly get the number of pages, but what I did as a workaround is to run an additional getEntityRecords query for once with the same parameters as the main one, only switching the order the other way around (setting orderby parameter to asc or desc) and limiting it to only one item (per_page set to 1). From this I get the last item in my target set. Once I have that, I can compare the ID with all the ID's of the entities returned by the main pagination query. As soon as I find the ID of the last item in the set returned by the main query, I know this was the last page, so I can disable the "load next page" button or so.
It is not a full value solution, as it lacks the ability to tell in advance how many pages there will be, but still better than leaving the user clicking on "load more" to no avail until they give up.
I am currently working on a custom Wordpress plugin which requires the user to create a list in a form, and so to help them populate their list, I have implemented the Wordpress Thickbox. I have made the Thickbox display, with the content I would like, however what I am struggling to do is pass the data back to the original form.
The Original Form is like this:
<input name="input_that_wants_data" id="input_for_data" type="text" />
Click Here for Modal
Just like you would expect any form to be. Basically I want the information from the modal to pass my string back to the input_for_data
The code inside the modal has multiple table rows like this:
<td><input type="checkbox" class="modal_checkbox_class" value="'.$data->value.'"></td>
Basically what I would like to do is build an array of the values of each clicked checkbox, and then use the split function of Javascript to turn it into a string which I would return to the input field outside of the modal.
Any and all help is greatly appreciated. I would prefer a Javascript/JQuery solution to this
I used this tutorial to do something that you want:
https://code.tutsplus.com/tutorials/getting-started-with-the-wordpress-media-uploader--cms-22011
My code looks like this:
function renderMediaUploader() {
'use strict';
var file_frame, image_data;
/**
* If an instance of file_frame already exists, then we can open it
* rather than creating a new instance.
*/
if ( undefined !== file_frame ) {
file_frame.open();
return;
}
/**
* If we're this far, then an instance does not exist, so we need to
* create our own.
*
* Here, use the wp.media library to define the settings of the Media
* Uploader. We're opting to use the 'post' frame which is a template
* defined in WordPress core and are initializing the file frame
* with the 'insert' state.
*
* We're also not allowing the user to select more than one image.
*/
file_frame = wp.media.frames.file_frame = wp.media({
title: 'Select or Upload Media Of Your Chosen Persuasion',
button: {
text: 'Use this media'
},
multiple: true
});
//add items from thickbox to table
file_frame.on( 'select', function() {
var attachment = file_frame.state().get('selection').toJSON();
jQuery.each(attachment, function(i, val){
jQuery('table').show();
jQuery('table tbody').append('<tr class="table_row"><td class="col-sm-2"><img class="img-responsive" src="'+val.url+'"></td><td class="col-sm-8"><input style=" display: block;" type="text" name="entry[url][]" value="'+ val.url +'"></td></tr>');
});
});
// Now display the actual file_frame
file_frame.open();
}
(function( $ ) {
'use strict';
$(function() {
$( '#set-footer-thumbnail' ).on( 'click', function( evt ) {
// Stop the anchor's default behavior
evt.preventDefault();
// Display the media uploader
renderMediaUploader();
});
});
})( jQuery );
Codewaggle's answer here got me started and I also have looked at Reinmar's answer, but I can't quite put this together.
I want to create a plugin with five custom spans (correction, deletion, suggestion...etc.) that I can then add to my CSS and have a button to apply each style using CKeditor in Drupal 7.
I don't want to use the drop-down for styles and prefer to have buttons with icons for each class added.
I used the basicstyles plugin as a jumping off point, but I have never done anything in javascript before so I am really in the dark.
I have added
config.extraPlugins = 'poligoeditstyles';
to the config file and set up the file structure of my plugin according to the guide on the CKeditor.
I assume that if all has gone according to plan I should see a button to drag into my toolbar, but, alas! No joy. I can see nothing added to my CKeditor toolbar when I add content or on the configuration page in Drupal:
admin/config/content/ckeditor/edit/Advanced
Am I missing something? Any help would be appreciated!
Here's my plugin code:
/**
* POLIGO edit styles plug-in for CKeditor based on the Basic Styles plugin
*/
CKEDITOR.plugins.add( 'poligoeditstyles', {
icons: 'correction,suggestion,deletion,commendation,dontunderstand', // %REMOVE_LINE_CORE%
init: function( editor ) {
var order = 0;
// All buttons use the same code to register. So, to avoid
// duplications, let's use this tool function.
var addButtonCommand = function( buttonName, buttonLabel, commandName, styleDefiniton ) {
// Disable the command if no definition is configured.
if ( !styleDefiniton )
return;
var style = new CKEDITOR.style( styleDefiniton );
// Listen to contextual style activation.
editor.attachStyleStateChange( style, function( state ) {
!editor.readOnly && editor.getCommand( commandName ).setState( state );
});
// Create the command that can be used to apply the style.
editor.addCommand( commandName, new CKEDITOR.styleCommand( style ) );
// Register the button, if the button plugin is loaded.
if ( editor.ui.addButton ) {
editor.ui.addButton( buttonName, {
label: buttonLabel,
command: commandName,
toolbar: 'poligoeditstyles,' + ( order += 10 )
});
}
};
var config = editor.config,
lang = editor.lang;
addButtonCommand( 'Correction', 'That's a mistake', 'correction', config.coreStyles_correction );
addButtonCommand( 'Suggestion', 'That's OK, but I suggest...', 'suggestion', config.coreStyles_suggestion );
addButtonCommand( 'Deletion', 'You don't need that', 'deletion', config.coreStyles_deletion );
addButtonCommand( 'Commendation', 'Great job!', 'commendation', config.coreStyles_commendation );
addButtonCommand( 'Dontunderstand', 'I don't understand what you mean', 'dontunderstand', config.coreStyles_dontunderstand );
}
});
// POLIGO Editor Inline Styles.
CKEDITOR.config.coreStyles_correction = { element : 'span', attributes : { 'class': 'correction' }};
CKEDITOR.config.coreStyles_suggestion = { element : 'span', attributes : { 'class': 'suggestion' }};
CKEDITOR.config.coreStyles_deletion = { element : 'span', attributes : { 'class': 'deletion' }};
CKEDITOR.config.coreStyles_commendation = { element : 'span', attributes : { 'class': 'commendation' }};
CKEDITOR.config.coreStyles_dontunderstand = { element : 'span', attributes : { 'class': 'dontunderstand' }};
Shot in the dark here but have you added your button to your config.toolbar in your initialization or config somewhere else - see http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Toolbar
I'm using Dojo's Dijit Layout for generating content tab-panes similar to Dijit Theme Tester Demo. All of the tabs here are closeable.
The issue is: when I close a tab it goes back to the first tab in the list instead of the previous tab (available next to it).
You can think of it like opening a new tab in Firefox or Chrome and try closing the last tab.... on closing tab, it changes the focus to the previous tab which is a predictable behavior for working with tabs. But with dijit.TabContainers, by default it goes back to the very first tab instead of previous one. This is a serious flaw when you consider the UI basics.
I have checked with dojo docs, but don't found any hint on this. Any idea how to it?
Ok so when the [X] button on the dijit.layout.ContentPane (tab) is clicked an event onClose is generated, the dijit.layout.TabContainer is listening to this event, so when this happens, it executes the callback closeChild() then the function removeChild() is executed, this last one is the one you should override.
The tabContainer inherits this two functions from dijit.layout.StackContainer you should check the API documentation.
So for being able to modify the default behavior of the closing tabs, you should override the default functionality, in the example below i do this. Read the comments for info on where to add your logic.
E.g.
<script>
require([
"dojo/parser",
"dojo/_base/lang", //this is the one that has the extend function
"dojo/topic", //this is needed inside the overrided function
"dijit/layout/TabContainer",
"dijit/layout/ContentPane",
"dojo/domReady!"
], function(Parser, lang, topic, tabContainer, contentPane){
Parser.parse();
// this will extend the tabContainer class and we will override the method in question
lang.extend(tabContainer, {
// this function, i copied it from the dijit.layout.StackContainer class
removeChild: function(/*dijit._Widget*/ page){
// for this to work i had to add as first argument the string "startup"
this.inherited("startup", arguments);
if(this._started){
// also had to call the dojo.topic class in the require statement
topic.publish(this.id + "-removeChild", page);
}
if(this._descendantsBeingDestroyed){ return; }
if(this.selectedChildWidget === page){
this.selectedChildWidget = undefined;
if(this._started){
var children = this.getChildren();
if(children.length){
// this is what you want to add your logic
// the var children (array) contains a list of all the tabs
// the index selects the tab starting from left to right
// left most being the 0 index
this.selectChild(children[0]);
}
}
}
if(this._started){
this.layout();
}
}
});
// now you can use your modified tabContainer WALAAAAAAA!
// from here on, normal programmatic tab creation
var tc = new tabContainer({
style: "height: 100%; width: 100%;",
}, "tab-container-div-id");
var cp1 = new contentPane({
title: "First Tab",
closable: true
});
tc.addChild(cp1);
var cp2 = new contentPane({
title: "Second Tab",
closable: true
});
tc.addChild(cp2);
var cp3 = new contentPane({
title: "Third Tab",
selected: true,
closable: true
});
tc.addChild(cp3);
tc.startup();
});
</script>
In Dojo 1.10, reverting to the previous tab is the normal behaviour for TabContainers (instead of reverting to the first tab).
Presumably, you could use dojo/aspect to get the old behaviour (warning: not tested):
require( [ 'dijit/registry', 'dojo/aspect', 'dojo/_base/lang' ],
function( registry, aspect, lang )
{
var tabContainer = registry.byId( 'tab_container');
aspect.before( tabContainer, 'removeChild', lang.hitch( tabContainer, function( page )
{
if(this.selectedChildWidget === page)
{
this.selectedChildWidget = undefined;
if(this._started)
{
var children = this.getChildren();
this.selectChild( children[0] );
}
}
return page;
} ) );
}
);
Or, alternatively, you could use the onClose extension point on a tab's ContentPane:
require( [ 'dijit/registry', 'dojo/_base/lang' ],
function( registry, lang ) {
newTabPane.onClose = lang.hitch(this, function () {
// select first
var tabContainer = registry.byId('tab_container'),
all_tabs = tabContainer.getChildren();
tabContainer.selectChild( all_tabs[0] );
// allow save to go ahead
return true;
});
}
);
Obviously, both these approaches would allow you to select a specific different pane on a tab being closed instead with a little tweaking...
I try for some time now to set the active Tab of this theme when the user clicks an image (above the tabs).
http://www.elegantthemes.com/preview/Nova/
I found the normal tab change code in the scripts.php, but I have no idea of how to change it to make it work with clicking any image that are above the tabs.
$service_li.find('a').click(function(){
var $a = jQuery(this),
next_tab = $a.parent('li').prevAll().length,
next_tab_height = $service_tabs.find('>div').eq(next_tab).outerHeight();
if ( next_tab != active_tab ) {
$service_tabs.css({height:next_tab_height});
$service_div.filter(':visible')
.animate( {opacity: 'hide'},500, function(){
jQuery(this).parent().find('>div').eq(next_tab).animate( {opacity: 'show'},500 );
} )
;
$service_li.removeClass(active_tabstate).filter(':eq('+next_tab+')').addClass(active_tabstate);
active_tab = next_tab;
}
return false;
}).hover(function(){
if ( !jQuery(this).parent('li').hasClass(active_tabstate) && !is_ie ) jQuery(this).fadeTo('slow',.7);
}, function(){
if (!is_ie) jQuery(this).fadeTo('slow',1);
});
}
Maybe someone can help out ?
I don't quite understand what or better yet, why you've conjured that thing over there, but i would use jQuery Tabs, so you can easily access the tab object by entering the id in the URL (firefox only) or by using something like.. .tabs( "select" , index ) , you can find more documentation in the URL above.