<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://mwiki.costasano.club/index.php?action=history&amp;feed=atom&amp;title=ICT%3ADrupal_11.3_Technical_Note_-_Custom_tweaks</id>
	<title>ICT:Drupal 11.3 Technical Note - Custom tweaks - Revision history</title>
	<link rel="self" type="application/atom+xml" href="https://mwiki.costasano.club/index.php?action=history&amp;feed=atom&amp;title=ICT%3ADrupal_11.3_Technical_Note_-_Custom_tweaks"/>
	<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:Drupal_11.3_Technical_Note_-_Custom_tweaks&amp;action=history"/>
	<updated>2026-04-17T19:44:31Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.45.1</generator>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:Drupal_11.3_Technical_Note_-_Custom_tweaks&amp;diff=1552&amp;oldid=prev</id>
		<title>Mngr: Mngr moved page ICT:Drupal 11.3 Techniacl Note - Custom tweaks to ICT:Drupal 11.3 Technical Note - Custom tweaks without leaving a redirect</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:Drupal_11.3_Technical_Note_-_Custom_tweaks&amp;diff=1552&amp;oldid=prev"/>
		<updated>2026-03-22T22:03:02Z</updated>

		<summary type="html">&lt;p&gt;Mngr moved page &lt;a href=&quot;/index.php?title=ICT:Drupal_11.3_Techniacl_Note_-_Custom_tweaks&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;ICT:Drupal 11.3 Techniacl Note - Custom tweaks (page does not exist)&quot;&gt;ICT:Drupal 11.3 Techniacl Note - Custom tweaks&lt;/a&gt; to &lt;a href=&quot;/ICT:Drupal_11.3_Technical_Note_-_Custom_tweaks&quot; title=&quot;ICT:Drupal 11.3 Technical Note - Custom tweaks&quot;&gt;ICT:Drupal 11.3 Technical Note - Custom tweaks&lt;/a&gt; without leaving a redirect&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;en&quot;&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;← Older revision&lt;/td&gt;
				&lt;td colspan=&quot;1&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;Revision as of 22:03, 22 March 2026&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;2&quot; class=&quot;diff-notice&quot; lang=&quot;en&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;(No difference)&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
	<entry>
		<id>https://mwiki.costasano.club/index.php?title=ICT:Drupal_11.3_Technical_Note_-_Custom_tweaks&amp;diff=1550&amp;oldid=prev</id>
		<title>Mngr: Created page with &quot;= Drupal 11.3 Technical Note: Heritage Project Custom Tweaks =  == Overview == This document outlines the custom module created for the Heritage Project to handle specific user experience (UX) and data integrity requirements that are not met by core Drupal 11.3 configuration.  == Features == # &#039;&#039;&#039;Status Message Link Removal:&#039;&#039;&#039; Replaces the linked node title in &quot;Saved&quot; messages with plain text for Historians, preventing them from leaving their View. # &#039;&#039;&#039;Date Format Vali...&quot;</title>
		<link rel="alternate" type="text/html" href="https://mwiki.costasano.club/index.php?title=ICT:Drupal_11.3_Technical_Note_-_Custom_tweaks&amp;diff=1550&amp;oldid=prev"/>
		<updated>2026-03-22T15:50:10Z</updated>

		<summary type="html">&lt;p&gt;Created page with &amp;quot;= Drupal 11.3 Technical Note: Heritage Project Custom Tweaks =  == Overview == This document outlines the custom module created for the Heritage Project to handle specific user experience (UX) and data integrity requirements that are not met by core Drupal 11.3 configuration.  == Features == # &amp;#039;&amp;#039;&amp;#039;Status Message Link Removal:&amp;#039;&amp;#039;&amp;#039; Replaces the linked node title in &amp;quot;Saved&amp;quot; messages with plain text for Historians, preventing them from leaving their View. # &amp;#039;&amp;#039;&amp;#039;Date Format Vali...&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;= Drupal 11.3 Technical Note: Heritage Project Custom Tweaks =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
This document outlines the custom module created for the Heritage Project to handle specific user experience (UX) and data integrity requirements that are not met by core Drupal 11.3 configuration.&lt;br /&gt;
&lt;br /&gt;
== Features ==&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Status Message Link Removal:&amp;#039;&amp;#039;&amp;#039; Replaces the linked node title in &amp;quot;Saved&amp;quot; messages with plain text for Historians, preventing them from leaving their View.&lt;br /&gt;
# &amp;#039;&amp;#039;&amp;#039;Date Format Validation:&amp;#039;&amp;#039;&amp;#039; Enforces a `dd/mm/yyyy` format on all text fields ending in `_day` and performs a calendar sanity check (e.g., blocking Feb 31st).&lt;br /&gt;
&lt;br /&gt;
== Implementation: heritage_tweaks.module ==&lt;br /&gt;
This code is stored in `web/modules/custom/heritage_tweaks/heritage_tweaks.module`.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * @file&lt;br /&gt;
 * Heritage Project: Link removal and Date Validation for Drupal 11.3.&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
use Drupal\Core\Form\FormStateInterface;&lt;br /&gt;
use Drupal\Core\Messenger\MessengerInterface;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Implements hook_form_BASE_FORM_ID_alter() for node_form.&lt;br /&gt;
 */&lt;br /&gt;
function heritage_tweaks_form_node_form_alter(&amp;amp;$form, FormStateInterface $form_state, $form_id) {&lt;br /&gt;
  &lt;br /&gt;
  // 1. LINK REMOVAL: Remove node link for non-admins.&lt;br /&gt;
  $form[&amp;#039;actions&amp;#039;][&amp;#039;submit&amp;#039;][&amp;#039;#submit&amp;#039;][] = &amp;#039;heritage_tweaks_clean_save_message&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
  // 2. DATE VALIDATION: Target fields ending in _day.&lt;br /&gt;
  $form[&amp;#039;#validate&amp;#039;][] = &amp;#039;heritage_tweaks_date_validate&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
  // 3. UI HINTING: Add placeholders to help users.&lt;br /&gt;
  foreach ($form as $key =&amp;gt; &amp;amp;$element) {&lt;br /&gt;
    if (str_ends_with($key, &amp;#039;_day&amp;#039;) &amp;amp;&amp;amp; isset($element[&amp;#039;widget&amp;#039;][&amp;#039;value&amp;#039;])) {&lt;br /&gt;
      $element[&amp;#039;widget&amp;#039;][&amp;#039;value&amp;#039;][&amp;#039;#attributes&amp;#039;][&amp;#039;placeholder&amp;#039;] = &amp;#039;dd/mm/yyyy&amp;#039;;&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Removes the node link from the status message for non-administrators.&lt;br /&gt;
 */&lt;br /&gt;
function heritage_tweaks_clean_save_message($form, FormStateInterface $form_state) {&lt;br /&gt;
  if (\Drupal::currentUser()-&amp;gt;hasPermission(&amp;#039;administer nodes&amp;#039;)) {&lt;br /&gt;
    return;&lt;br /&gt;
  }&lt;br /&gt;
  $messenger = \Drupal::messenger();&lt;br /&gt;
  $node = $form_state-&amp;gt;getFormObject()-&amp;gt;getEntity();&lt;br /&gt;
  $messenger-&amp;gt;deleteByType(MessengerInterface::TYPE_STATUS);&lt;br /&gt;
  $messenger-&amp;gt;addStatus(t(&amp;#039;@type %title has been updated.&amp;#039;, [&lt;br /&gt;
    &amp;#039;@type&amp;#039; =&amp;gt; $node-&amp;gt;type-&amp;gt;entity-&amp;gt;label(),&lt;br /&gt;
    &amp;#039;%title&amp;#039; =&amp;gt; $node-&amp;gt;label(),&lt;br /&gt;
  ]));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Validates that fields ending in _day follow the dd/mm/yyyy format.&lt;br /&gt;
 */&lt;br /&gt;
function heritage_tweaks_date_validate(array &amp;amp;$form, FormStateInterface $form_state) {&lt;br /&gt;
  $values = $form_state-&amp;gt;getValues();&lt;br /&gt;
&lt;br /&gt;
  foreach ($values as $field_name =&amp;gt; $value) {&lt;br /&gt;
    if (str_ends_with($field_name, &amp;#039;_day&amp;#039;)) {&lt;br /&gt;
      &lt;br /&gt;
      $date_string = (is_array($value) &amp;amp;&amp;amp; isset($value[&amp;#039;value&amp;#039;])) ? $value[&amp;#039;value&amp;#039;] : &amp;#039;&amp;#039;;&lt;br /&gt;
&lt;br /&gt;
      if (!empty($date_string)) {&lt;br /&gt;
        // Regex check for format: dd/mm/yyyy.&lt;br /&gt;
        $regex = &amp;#039;/^(0[1-9]|[1-2][0-9]|3[0-1])\/(0[1-9]|1[0-2])\/([0-9]{4})$/&amp;#039;;&lt;br /&gt;
        &lt;br /&gt;
        if (!preg_match($regex, $date_string)) {&lt;br /&gt;
          $form_state-&amp;gt;setErrorByName($field_name, t(&amp;#039;The date must be in dd/mm/yyyy format.&amp;#039;));&lt;br /&gt;
        } &lt;br /&gt;
        else {&lt;br /&gt;
          // Calendar sanity check (Feb 30th, etc.).&lt;br /&gt;
          $parts = explode(&amp;#039;/&amp;#039;, $date_string);&lt;br /&gt;
          // PHP checkdate order: Month, Day, Year.&lt;br /&gt;
          if (!checkdate((int)$parts[1], (int)$parts[0], (int)$parts[2])) {&lt;br /&gt;
            $form_state-&amp;gt;setErrorByName($field_name, t(&amp;#039;This is not a valid calendar date.&amp;#039;));&lt;br /&gt;
          }&lt;br /&gt;
        }&lt;br /&gt;
      }&lt;br /&gt;
    }&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Maintenance Commands ==&lt;br /&gt;
Whenever this code is updated, clear the Drupal cache:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
drush cr&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Drupal 11]] [[Category:Heritage Project]] [[Category:ICT:pages]]&lt;/div&gt;</summary>
		<author><name>Mngr</name></author>
	</entry>
</feed>