Jump to content

How to disable multi-language page title for one template


androbey
 Share

Recommended Posts

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

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)?

  1. Edit the template you don't want ML support for
  2. Go to Advanced Tab
  3. Scroll to the bottom
  4. Disable ML support for the template

Advanced Tab

template_edit_advanced.thumb.png.91e0120fe0339f55a771b0b96d331a74.png

Disable ML Support

template_edit_advanced_disable_ml_support.thumb.png.5bfcc4ee505197588ae1ae23274ea4f0.png

Link to comment
Share on other sites

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

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 by kongondo
Link to comment
Share on other sites

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

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

Here's how I managed to do this by hook or crook ?.

Summary

  1. Hooks alone are not enough
  2. We still need to be able to switch templates and view/enable languages if those templates support languages
  3. We need to be able to do this both during page creation and post-creation
  4. We need CSS, JavaScript and Hooks
  5. We use hooks to: (a) deactivate non-default languages (b) to pass an array of template IDs that we designate as mono-lingual
  6. We use CSS to hide unrequired language tabs, inputs and labels
  7. We use JavaScript to add/remove 'hide' classes as needed
  8. 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
  9. 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

 

  • Like 2
Link to comment
Share on other sites

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".

  • Like 3
Link to comment
Share on other sites

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

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;
	}
});

 

  • Like 6
Link to comment
Share on other sites

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 by kongondo
Link to comment
Share on other sites

@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

  • 2 years later...

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

  • 3 months later...

@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:

mfuY22c.png

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

  • Like 1
Link to comment
Share on other sites

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...