androbey Posted October 6, 2020 Share Posted October 6, 2020 Hi all, I am currently playing with a site using multi language support, including "PageTitleLanguage". Now, for one template multi language title is not needed, but the rest of fields should still support multi lanuage. When creating a page a user is now halted to add a title in all enabled languages. I did not come up with a solution and frankly don't even know what hook to look at. What would be a could way to disable multi language support for page title field (or to hide input for non-default languages)? Link to comment Share on other sites More sharing options...
kongondo Posted October 7, 2020 Share Posted October 7, 2020 6 hours ago, androbey said: I did not come up with a solution and frankly don't even know what hook to look at. No hook needed :-). 6 hours ago, androbey said: What would be a could way to disable multi language support for page title field (or to hide input for non-default languages)? Edit the template you don't want ML support for Go to Advanced Tab Scroll to the bottom Disable ML support for the template Advanced Tab Disable ML Support Link to comment Share on other sites More sharing options...
androbey Posted October 7, 2020 Author Share Posted October 7, 2020 Hi @kongondo, thank you for your reply. Although I did not see it before, it does not solve my problem. This setting would disable multi language for entire template. However I am only interested in disabling multi language for page title field. I hope it's understandable. Link to comment Share on other sites More sharing options...
kongondo Posted October 7, 2020 Share Posted October 7, 2020 (edited) 1 hour ago, androbey said: However I am only interested in disabling multi language for page title field. Of course you are! Sorry about that. I need to get more sleep ?. OK, back to the issue. You might have noticed this yourself. It seems ProcessWire does not allow you to create two title fields. At least that's what I am seeing here, i.e. I cannot create a new field and make it to be of type Page Title. I haven't seen a setting to change that. However, we can change the type of an existing title field from Page Title Multi-language to Page Title. But that's not what we want. Hmm, let's try something else. We can trick ProcessWire by duplicating the current title field! OK, progress...until you look at the type for the cloned Page Title field. In my case, I am testing in a multilingual site and in the clone, for type choices, we now only get Page Title Multi-Language!We cannot change the type to Page Title! Interesting...The original title field can still have its type changed; but, you don't want to do that because you will lose the multilingual data for the pages that currently use that title field! Thoughts, anyone? We can always hook, but was just wondering... :-) Edited October 7, 2020 by kongondo Link to comment Share on other sites More sharing options...
androbey Posted October 7, 2020 Author Share Posted October 7, 2020 You described almost exactly what I found out so far. However, the trick with duplicating "PageTitleLanguage" was new. I did duplicate that and manually changed type of this field in the database. Obviously I can hook on page creation to fill the duplicated title field with data from page name. So that would work in theory. Also, I would have to keep the "original" title field in sync, when I whant to keep that field. But I also obviously missed another point: page name is also unnecessary in multi language. So that would be another "problem", which I (as I assume) can not solve with the duplicate trick. Link to comment Share on other sites More sharing options...
kongondo Posted October 7, 2020 Share Posted October 7, 2020 17 minutes ago, kongondo said: It seems ProcessWire does not allow you to create two title fields. Note to self: Like I said, I really need to get more sleep! Although all fields in ProcessWire are custom fields, the Title field is somewhat special and I suppose that's why ProcessWire treats it so. 8 minutes ago, androbey said: But I also obviously missed another point: page name is also unnecessary in multi language. So that would be another "problem", which I (as I assume) can not solve with the duplicate trick. Let me have a think... Link to comment Share on other sites More sharing options...
kongondo Posted October 7, 2020 Share Posted October 7, 2020 Found a solution :-). Will post here tomorrow. Link to comment Share on other sites More sharing options...
kongondo Posted October 8, 2020 Share Posted October 8, 2020 Here's how I managed to do this by hook or crook ?. Summary Hooks alone are not enough We still need to be able to switch templates and view/enable languages if those templates support languages We need to be able to do this both during page creation and post-creation We need CSS, JavaScript and Hooks We use hooks to: (a) deactivate non-default languages (b) to pass an array of template IDs that we designate as mono-lingual We use CSS to hide unrequired language tabs, inputs and labels We use JavaScript to add/remove 'hide' classes as needed We need to load the CSS and JavaScript in the admin. There are various ways to do this. I've simply added them via templates/admin.php You'll notice some brief FOUC, but they are not major and can probably be sorted out using CSS and JavaScript. I've left in some example code in the CSS (see below) Code CSS Spoiler /* hide language selector tabs and other languages page name inputs + default language name input label */ form.hide_other_languages div#langTabs_Inputfield_title li, form.hide_other_languages li#wrap_Inputfield__pw_page_name div.LanguageSupport:not(.exclude_hide_other_languages), form.hide_other_languages div.LanguageSupport.exclude_hide_other_languages label.LanguageSupportLabel { display: none !important; } /* (attempt to) fade in language tabs to avoid fouc */ /* div#langTabs_Inputfield_title li { animation: fadeIn ease 2s; -webkit-animation: fadeIn ease 2s; -moz-animation: fadeIn ease 2s; -o-animation: fadeIn ease 2s; -ms-animation: fadeIn ease 2s; } @keyframes fadeIn { 0% { opacity: 0; } 100% { opacity: 1; } } @-moz-keyframes fadeIn { 0% { opacity: 0; } 100% { opacity: 1; } } @-webkit-keyframes fadeIn { 0% { opacity: 0; } 100% { opacity: 1; } } @-o-keyframes fadeIn { 0% { opacity: 0; } 100% { opacity: 1; } } @-ms-keyframes fadeIn { 0% { opacity: 0; } 100% { opacity: 1; } } */ JavaScript Spoiler /** * DOM ready * */ document.addEventListener("DOMContentLoaded", function () { // check if we have hidden input with IDs of monolingual templates // if in template monolingual monitoring if (document.getElementById("nonLanguageTemplates")) { // mark wrapper for default language name for 'display:none' exclusion markDefaultLanguageNameForExclusion(); // check value of currently selected template onLoadGetSelectedTemplate(); // add 'change' event listener to templates' select (for both page Add and Edit) monitorSelectedTemplate(); } }); function markDefaultLanguageNameForExclusion() { const defaultLanguageName = document.getElementById( "Inputfield__pw_page_name_path" ); if (defaultLanguageName) { defaultLanguageName.parentNode.classList.add( "exclude_hide_other_languages" ); } } function monitorSelectedTemplate() { const templateSelect = document.getElementById("template"); if (templateSelect) { templateSelect.addEventListener( "change", handleTemplateSelectChange, false ); } } function handleTemplateSelectChange(e) { const elem = e.target; setOtherLanguagesVisibility(elem.value); } function onLoadGetSelectedTemplate() { const templatesSelect = document.getElementById("template"); if (templatesSelect) { setOtherLanguagesVisibility(templatesSelect.value); } } function setOtherLanguagesVisibility(selectedTemplateID) { const monolingualTemplateIDs = getMonolingualTemplates(); // if we have monolingual template IDs to work with if (monolingualTemplateIDs.length) { const hide = monolingualTemplateIDs.includes( parseInt(selectedTemplateID) ); hideOtherLanguages(hide); } } function getMonolingualTemplates() { const monolingualTemplatesInput = document.getElementById( "nonLanguageTemplates" ); let monolingualTemplates = []; if (monolingualTemplatesInput) { monolingualTemplates = monolingualTemplatesInput.value .split(",") .map((t) => parseInt(t)); } return monolingualTemplates; } function hideOtherLanguages(hide = false) { const inputWithMonolingualTemplateIDs = document.getElementById( "nonLanguageTemplates" ); if (inputWithMonolingualTemplateIDs) { const pageForm = document.getElementById( inputWithMonolingualTemplateIDs.dataset.context ); // we found the form: add class to hide/show language inputs and tabs if (pageForm) { hide ? pageForm.classList.add("hide_other_languages") : pageForm.classList.remove("hide_other_languages"); } } } PHP /site/templates/admin.php Spoiler <?php namespace ProcessWire; $config->styles->add($config->urls->templates . "styles/my-custom-admin.css"); $config->scripts->add($config->urls->templates . "scripts/my-custom-admin.js"); require $config->paths->adminTemplates . 'controller.php'; /site/ready.php Spoiler <?php namespace ProcessWire; // names of monolingual templates here $monolingualTemplatesNames = ['no-other-languages', 'no-other-languages-2', 'no-other-languages-3']; //------------- $monolingualTemplatesNamesSelector = implode('|', $monolingualTemplatesNames); $monolingualTemplates = $templates->find("name=$monolingualTemplatesNamesSelector"); $monolingualTemplatesCSV = $monolingualTemplates->count ? $monolingualTemplates->implode(',', 'id') : ''; // HOOK After ProcessPageAdd Execute // we insert hidden input with csv string of IDs of templates we want to be 'MONO-LANGUAGE' $wire->addHookAfter('ProcessPageAdd::execute', function (HookEvent $event) use ($monolingualTemplatesCSV) { // if no templates IDs specified, return if (empty($monolingualTemplatesCSV)) { return; } //----------------- $markup = $event->return; $pattern = "/<form id=[\"']ProcessPageAdd[\"']/"; $replacementHTML = "<input id='nonLanguageTemplates' type='hidden' value='{$monolingualTemplatesCSV}' data-context='ProcessPageAdd'>"; // @note: prepend using back references + limiting to one $out = preg_replace($pattern, $replacementHTML . '$0', $markup, 1); // set the modified value back to the return value $event->return = $out; }); // HOOK After ProcessPageEdit Execute // we insert hidden input with csv string of templates we want to be 'MONO-LANGUAGE' $wire->addHookAfter('ProcessPageEdit::execute', function (HookEvent $event) use ($monolingualTemplatesCSV) { // if no templates IDs specified, return if (empty($monolingualTemplatesCSV)) { return; } //----------------- $markup = $event->return; $pattern = "/<p id=[\"']PageIDIndicator[\"']/"; $replacementHTML = "<input id='nonLanguageTemplates' type='hidden' value='{$monolingualTemplatesCSV}' data-context='ProcessPageEdit'>"; // @note: prepend using back references + limiting to one $out = preg_replace($pattern, $replacementHTML . '$0', $markup, 1); // set the modified value back to the return value $event->return = $out; }); //------------------------------- // HOOK After Pages Added // for templates matching our 'MONO-LANGUAGE' templates // we set their 'other languages' as inactive $pages->addHookAfter("added", function (HookEvent $event) use ($monolingualTemplatesNames) { // get the new page we are hooking into $page = $event->arguments[0]; // if non-relevant template, return if (!in_array($page->template->name, $monolingualTemplatesNames)) { return; } foreach (wire('languages') as $language) { if ($language->name == 'default') { continue; } // deactivate other language $page->setAndSave("status$language", 0); } }); Other approaches, anyone? Demo 2 Link to comment Share on other sites More sharing options...
Robin S Posted October 8, 2020 Share Posted October 8, 2020 On 10/7/2020 at 9:37 AM, androbey said: When creating a page a user is now halted to add a title in all enabled languages. I might be misunderstanding something (I don't normally work on multi-language sites), but isn't it optional to enter page titles in any language other than the default? The user isn't forced to add a title in all enabled languages as far as I can see. So it seems like it's a question of user education more than anything else, the lesson being "only create page titles in languages that you need", which is really part of a more basic general lesson that any CMS user must learn: "only fill out fields that you have information for". 3 Link to comment Share on other sites More sharing options...
kongondo Posted October 9, 2020 Share Posted October 9, 2020 10 hours ago, Robin S said: but isn't it optional to enter page titles in any language other than the default? The user isn't forced to add a title in all enabled languages as far as I can see. Yes you are right Robin and you raise some good points. Now that I read this... On 10/6/2020 at 9:37 PM, androbey said: When creating a page a user is now halted to add a title in all enabled languages. I see that I probably misunderstood the OP question. 10 hours ago, Robin S said: So it seems like it's a question of user education more than anything else, the lesson being "only create page titles in languages that you need", which is really part of a more basic general lesson that any CMS user must learn: "only fill out fields that you have information for". Good point. I am wondering though, couldn't the converse also apply in this case? i.e. Quote "Always ask as less as possible/shorter is better — get rid of all inessential fields." aka, don't show an input that the user does not need to fill ?. Anecdotes I've heard from developers who work on multi-language sites is that if they can, they often resort to hiding what the user doesn't need to fill, as in spite of the education, their users still get confused by/forget/ignore...etc the instructions. Link to comment Share on other sites More sharing options...
Robin S Posted October 9, 2020 Share Posted October 9, 2020 5 hours ago, kongondo said: in spite of the education, their users still get confused by/forget/ignore...etc the instructions Yeah, we all struggle with that sometimes. ? I did a bit of experimenting and here's another way the language options can be removed from the title field: // Single-language title field for "test-template" at Page Add $wire->addHookAfter('ProcessPageAdd::getAllowedTemplates', function(HookEvent $event) { $tpls = $event->return; $t = $event->wire()->templates->get('test-template'); if(isset($tpls[$t->id])) $tpls[$t->id]->noLang = 1; $event->return = $tpls; }); // Single-language title field for "test-template" at Page Edit $wire->addHookAfter('ProcessPageEdit::buildFormContent', function(HookEvent $event) { /** @var InputfieldForm $form */ $form = $event->return; $page = $event->object->getPage(); if($page->template == 'test-template') { $title = $form->getChildByName('title'); if($title) $title->useLanguages = false; } }); 6 Link to comment Share on other sites More sharing options...
kongondo Posted October 9, 2020 Share Posted October 9, 2020 (edited) 19 minutes ago, Robin S said: I did a bit of experimenting and here's another way the language options can be removed from the title field: Nice one Robin! Much cleaner than what I proposed. At Page Add, it responds to template change but not so at Page Edit. Edited October 9, 2020 by kongondo Link to comment Share on other sites More sharing options...
androbey Posted October 9, 2020 Author Share Posted October 9, 2020 @kongondo Wow, thank you for your effort! I would agree that user education is indeed a valid point, but also they sometimes don't behave like should do. Also giving the users some freedom is usually a good idea (if they do use the system as intended). @Robin S solution is of course really nice. Both solutions have some minor drawback for me (language page variants are disabled by default) and I thought it may be better to let the user edit the page name after all. That's why I changed Robin's solution to hide multi language title field on page creation: $this->addHookAfter('ProcessPageAdd::buildForm', function(HookEvent $event) { $restrictedTemplates = ['test-template']; $restrictedTemplatesIds = wire('templates')->find("name=". join('|', $restrictedTemplates))->explode('id'); $form = $event->return; $template = $form->template; if($template && in_array($template->value, $restrictedTemplatesIds)){ $form->title->useLanguages = false; $form->_pw_page_name->collapsed = Inputfield::collapsedYes; } }); This way I have the best of both aproaches (for me): Page has no multi language title, but page has nevertheless all languages enabled. Could probably be improved but it does its job for me. Thank you again! Link to comment Share on other sites More sharing options...
bernhard Posted April 7, 2023 Share Posted April 7, 2023 Thx @Robin S for your snippet, it was really helpful today ? When using RockMigrations MagicPages this gets as simple as adding this to your custom page class: public function editForm($form) { $form->get('title')->useLanguages = false; } Link to comment Share on other sites More sharing options...
bernhard Posted July 21, 2023 Share Posted July 21, 2023 @Robin S just had an issue with your solution that caused some headache. The problem is that "useLanguages" only disables the language UI of the title field, but from the API it is still a multilang field. The problem here is that the field actually shows and stores values in the user's language, which can lead to serious inconsistancies: So it looks like the page's title is "ttt" but for a user with the default language it is actually "test222" I'll report back when I found a solution but just wanted to mention that here in case someone is using that snippet. https://github.com/processwire/processwire-issues/issues/1787 1 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now