“WPML (WordPress Multilingual) makes it easy to build multilingual sites and run them. It’s powerful enough for corporate sites, yet simple for blogs.” – WPML
I have been running and setting up multilingual websites for more than 12 years. WordPress and related integrations have gladly come a long way to make our life’s a lot easier.
For basic content WPML is almost plug & play, but I do see more and more sites / customers struggling with more complex setups. WPML is one of the most popular multilingual plugins and is used on x00.000 of websites.
Just so you know, WPML is a commercial solution!
The amount of settings has increased a lot over the years and offers possible solutions for almost any content / plugin setup.
But for more complex setups, I would suggest to hire a professional to look over the settings or study the plugin documentation carefully.
Especially with a lot of content, it can quickly increase problems and the need to revisit specific content over and over again.
WPML lets you translate any text that comes from themes / theme frameworks (DIVI, Elemetor, Gutenberg …), plugins, menus, slugs, SEO and additionally supported integrations (Gravity Forms, ACF, WooCommerce …).
You can translate content internally for yourself, using translation management to translate with an internal team of translators or get help from external translators / translation services.
The latest version also offers AI translations, which allows you to get a decent start for most of your content.
In addition to the above, WPML String Translation allows you to translate texts that are not in posts, pages and taxonomy. This includes the site’s tagline, general texts in admin screens, widget titles and many other areas.
Well, I am a bit biased. I have not looked much at other solutions for the past 5 years, as it offers all I really need.
I have used it on projects from 2 to 15 languages and it scales nicely. At least with proper hosting attached!
Anything can be tweaked through the API, Hooks and custom integrations. I have build additional WPML tools for my customers, to streamline some of the repeating / boring tasks.
Their support is responsive and the forum already provides a huge amount of answers to most of the questions that might come up.
If you develop / maintain multiple customer websites with multilingual content, the investment is quickly
amortized. I do offer WPML to my maintenance package customers, maybe something to consider ;)
Its an essential solution in my WP toolbox.
WPML 4.5 is on its way and will include a “Translate Everything” feature, among other fixes and enhancements.
Translate Everything allows you to translate all of your site’s content automatically as you create it. You can then review the translations on the front-end before publishing.
Admin Enhancer is the first free plugin released under the cubicFUSION brand. The plugin is still work in progress, but a tool that is already used within some of my client projects. I am using this plugin to centralise things I love & need, when sending out a finished website or project.
NEW: DASHBOARD GUTENBERG / DASHBOARD TEMPLATES
NEW: ADMIN TOOLBAR
UPDATE: SHORTCODES
This version includes a new addon “GUTENBERG DASHBOARD“, that allows you to build a White-Label Admin Dashboards using the Gutenberg Editor.
It integrates with the SHORTCODES addon and allows to drop in the dashboard widgets via its own Gutenberg Block.
The Block provides settings to overwrite CSS from the admin widgets, allowing you tweak them a bit — for better visual integration. The Dashboard template itself can be tweaked using CSS and Sass via SCSS now 😉
I am also releasing the first integration of the “ADMIN TOOLBAR” addon, which allows you to tweak some of the admin toolbar and footer options (Hide WP Logo, Hide Toolbar on Frontend, Hide Menu Items ..)
Already working on 0.3 … ENJOY!
While Gutenberg is becoming more stable with each release, documentation is only growing slowly. Many parts are outdated, superficial or completely undocumented.
For more complex or individual requirements you have to dive deep. Gladly the browser console allows you to easily checkout what is driving the editor.
Open your browser developer console and start exploring wp. / wp.data. / wp.api. .
What each function does, can be read in the Block Editor Handbook.
At this stage of the development, many things are still changing. So using the API direcly is mostly a matter of reading the documentation, checking the implementation within the core codebase and using trial & error.
Some mysteries have already been solved by others or they provide the right lead. Check Stack Overflow and especially the WordPress Development area for solutions.
Its still like a treasure hunt most of the time LOL Perfect for those that love to solve puzzles :)
Just my cup of tea or better coffee!
It surely is a benefit, as the whole Gutenberg Editor is build upon React. But for simple tweaks its not a must. But once you start going deeper, you will see the benefit and will learn to love React yourself.
ECMAScript 6 is also known as ES6 and ECMAScript 2015.
ES5 is on its way out and ES6 is supported on all modern browsers since end of 2016.
Older browsers can be supported using a polyfill, that augments those browsers and allows them to use the new ES6 features.
React and also Gutenberg builds on the new Javascript functionality, but ES5 examples can also be found.
You can also easily compile ES6 to ES5 using Babel in your development environment or online.
I will be using the following sections to highlight some things that puzzled me and might help others to get a grip on things. I will be extending this, as I discover or solve more Gutenberg mysteries :)
I will keep the example code in ES5 for now, as that is the easiest way to start tinkering. I will also focus on things that can be used from external code. Most of the small code snippets are connected to each other.
These little code snippets are all connected and showcase how to retrieve a selection from a block and change or remove a text format.
Make sure the editor has loaded and the DOM can be accessed.
1 2 3 |
wp.domReady(function() { // Your code here }); |
1 2 3 4 |
wp.data.select('core/block-editor').getSelectedBlock(); // Block ID - reference var blockUID = wp.data.select('core/block-editor').getSelectedBlock().clientId; |
1 2 3 4 5 |
// Start of selection var selectionStart = wp.data.select('core/block-editor').getSelectionStart(); // End of selection var selectionEnd = wp.data.select('core/block-editor').getSelectionEnd(); |
The actual offset can be found within the OBJECT.
1 |
wp.data.select('core/block-editor').getSelectionEnd().offset; |
1 2 3 4 5 6 7 8 |
// Get block var block = wp.data.select('core/block-editor').getSelectedBlock(); // Attributes var blockAttributes = block.attributes; // Content var blockContent = block.attributes.content; |
1 2 3 4 |
var richTextContent = wp.richText.create( { blockContent }); |
1 |
var activeTextFormats = blockContent.formats; |
This function is documented, but wont work from the outside that easily. This normally checks the isActive state of the component. Here a small workaround using Lodash.
1 2 3 4 5 6 7 |
var formatToCheck = "core/text-color"; var formatToCheckisActive = true; if(_.find(value.formats[selectionStart], { type: formatToCheck })) { formatToCheckisActive = false; } |
Formats are saved within the Richtext object under formats and the text formats are stored within arrays that correspond to the actual index + range of the selection. So if a text-color has been applied from index 4 to 8, you will find the corresponding array for that.
Works well and does the trick for now. Here the output from the developer console, showing the arrays for an 18 character long paragraph:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
formats: Array(18) 0: Array(1) 0: {type: "core/bold"} length: 1 __proto__: Array(0) 1: Array(1) 0: {type: "core/bold"} length: 1 __proto__: Array(0) 2: [{…}] 3: [{…}] 4: [{…}] 14: [{…}] 15: [{…}] 16: [{…}] 17: [{…}] length: 18 __proto__: Array(0) |
I am using the core/text-color format with applyFormat as an example, can be anything.
1 2 3 4 5 6 7 8 |
richTextContent = wp.richText.applyFormat( richTextContent, { type: 'core/text-color', attributes:{class: "some-color-class"} }, selectionStart, selectionEnd ); |
insertObject can insert content at the start of the selection, with the rest between selectionStart and selectionEnd getting removed. There is also insert, which allows you to simply add a HTML string into the Richtext value.
1 2 3 4 5 6 |
richTextContent = wp.richText.insertObject( richTextContent, 'core/text-color', selectionStart, selectionEnd ); |
removeFormat allows you to remove a text format from the current selection.
1 2 3 4 5 6 |
richTextContent = wp.richText.removeFormat( richTextContent, 'core/text-color', selectionStart, selectionEnd ); |
Would be nice to use toggleFormat here, but that works within native components and not by selection index as the two calls above.
1 2 3 |
var prepNewHTML = wp.richText.toHTMLString( {richTextContent } ); |
1 2 3 4 5 |
wp.data.dispatch( 'core/block-editor' ).updateBlock( blockUID, { attributes: { content: prepNewHTML } } ); |
I will add some more Gutenberg examples in the future.
I am always looking for easy ways to white label the WordPress administration for myself and my clients. A nice personal touch for each project and an easy way to declutter the interface.
These are my personal favorites, that I use on a regular basis.
There are a lot of solutions out there, but many break easily and are really heavy to load. Some of these solutions I tried also break easily on new WordPress Upgrades. The first two below are currently my favorites.
When sharing the administration with your customer, you often need to make it as simple a possible for them. Depending on your setup, the menu becomes cluttered and overwhelming really fast.
I often trim menus for each user role, to make only those options accessible that are really needed.
When sharing the administration with multiple users, its always nice to add some personality to the user profiles as well.
WP User Profiles
“WP User Profiles is a sophisticated way to edit users in WordPress.”
The plugin provides other small addons, like WP User Avatars. Neat plugin to tweak admins, editors and other users.
Enjoy
Alex
Updated 25.03. : Some function names changed in the latest beta version.
ACF 5.8 Beta introduced an easy way to create your custom Gutenberg blocks. I am already using it heavily for a current project, to easily organize content and media assets.
Really powerful, when combined with Timber as well, which has been the foundation of many of my themes for years now ;)
Organizing data using ACF is nice, but sometimes you seek access to that saved block data directly. I hate it when I am confined to boundaries and the data flow is restricted or hidden. I need things to be accessible to choose the creative flow myself.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
// Parse blocks from post content $blocks = parse_blocks($your_post_content); $collect = array(); // Loop through the blocks foreach($blocks as $block){ //Setup global block post data context // before: acf_setup_postdata acf_setup_meta( $block['attrs']['data'], $block['attrs']['id'], true ); // Get ACF fields $fields = get_fields(); // I am using this to organize my assets. // Each block of mine has a unique identifier as its first field: // $uid = $block['attrs']['data'][array_keys($block['attrs']['data'])[0]] // I would do: // $collect[$uid] = $fields; // Collection of fields using the block id. $collect[$block['attrs']['id']] = $fields; // Restore global context // before: acf_reset_postdata acf_reset_meta( $block['attrs']['id'] ); } |
There you go, enjoy some free block data :)
I was a big skeptic, when it comes to WordPress and the new Gutenberg editor, but combined with ACF + Timber its pure magic :) Looking forward to things to come!
Cheers
Alex
Extended example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
$collect = []; $blocks = parse_blocks($your->post_content); foreach($blocks as $block){ if( isset($block['attrs']['data']) && !empty($block['attrs']['data'][array_keys($block['attrs']['data'])[0]])){ acf_setup_meta( $block['attrs']['data'], $block['attrs']['id'], true ); $fields = get_fields(); acf_reset_meta( $block['attrs']['id'] ); $collect[$block['attrs']['data'][array_keys($block['attrs']['data'])[0]]] = array('render' => render_block( $block ), 'field' => $fields, 'block' => $block ); }else{ $collect['main'] .= render_block( $block ); } } |
The $collect array will hold all data, including all ACF fields. You will have full access to any field, including repeater fields. The $collect[‘main’] will just collect the standard post content.