Upgrade Your Drupal Skills

We trained 1,000+ Drupal Developers over the last decade.

See Advanced Courses NAH, I know Enough
Jun 11 2021
Jun 11

After quite some Google searching I found some answers that came close, but nothing that worked straight away. So to prevent you from puzzling and searching, here is how to get the image field url from a referenced node in a Twig node template

Use this code for example in node--blog--teaser.html.twig :

{{ node.field_REFERENCE.entity.field_IMAGE.entity.alt.value }}

Replace 'field_REFERENCE' with your node reference field system name, and replace 'field_IMAGE'  with the system name of your image field.

And by the way: more on Twig file naming conventions in Drupal here.

Drupal theming Planet Drupal Written by Joris Snoek | Nov 06, 2021

Join the conversation

Jun 07 2021
Jun 07

Last month we implemented the 'Resources' page on iias.asia, as you can see: you can filter the Resource nodes on this page in the right of the screen. This is a Drupal View with exposed filters, which are placed via a block via Twig Tweak module.

There is a 'Region' Filter and a 'Tags' taxonomy reference field, which are also used in other content types. 

We only wanted to show used terms in the drop downs.

So, there are other pages (Views) that also implemented this tag as a filter (like the Alumni page). But of course: those pages have other content types, so 'used tags' are also different.

So here is how we limited the used tags, per Drupal View, this article gave us a kickstart.

YOURMODULE.module:
/**
 * Implements hook_form_alter()
 *
 */
function YOURMODULE_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
  // Id's of the forms we want to alter.
  $form_ids = [
    'views-exposed-form-resources-page-1' => 'resource',
    'views-exposed-form-reviews-page-1' => 'review',
    'views-exposed-form-available-for-review-page-1' => 'review',

  ];
  // Targeted taxonomy term fields.
  $select_fields = ['tid_2', 'field_tags_target_id'];
  // Continue only if current form_id is one in defined array.
  if (array_key_exists($form['#id'], $form_ids)) {
    // Loop through targeted fields.
    foreach ($select_fields as $select_field) {
      // Get 'terms in use', switch query on which field is currently in the loop.
      // This only works if you have 1 or 2 targeted filters.
      $available_terms = ($select_field == 'tid_2')
                        ? _get_available_terms_region($form_ids[$form['#id']], $form['#id'])
                        : _get_available_terms_tags($form_ids[$form['#id']], $form['#id']);
      // Continue if $available_terms exists.
      if (isset($available_terms)) {
        // Unset the existing list.
        unset($form[$select_field]['#options']);
        // Build new list with 'terms in use'.
        $form[$select_field]['#options']['All'] = '- Any -';
        foreach ($available_terms as $available_term) {
          $tid = $available_term[0];
          $name = $available_term[1];
          $form[$select_field]['#options'][$tid] = $name;
        }
      }
    }
  }
}
/**
 * Custom function to query and build new filter list.
 *
 * @param $node_type
 * @param $exposed_block_id
 * @return array
 */
function _get_available_terms_region($node_type, $exposed_block_id) {
  // Table name of tags field.
  $node_tags_table = 'node__field_profile_region';
  // Query data.
  $query = \Drupal::database()->select($node_tags_table, 'nft');
  $query->distinct();
  $query->join('taxonomy_term_field_data', 'tname', 'tname.tid = nft.field_profile_region_target_id');
  $query->join('node', 'node', 'node.nid = nft.entity_id');
  $query->fields('nft', ['field_profile_region_target_id']);
  $query->fields('tname', ['name']);
  $query->orderBy('tname.name');
  // Dynamically query node type.
  $query->condition('node.type', $node_type);
  if($exposed_block_id == 'views-exposed-form-available-for-review-page-1') {
    $query->join('node__field_boolean_1', 'available', 'available.entity_id = nft.entity_id');
    $query->condition('available.field_boolean_1_value', 1);
  }
  $result = $query->execute();
  // Build term list.
  $term_list = [];
  while ($row = $result->fetchAssoc()) {
    array_push($term_list, [$row['field_profile_region_target_id'], $row['name']]);
  }
  // Return term list.
  return $term_list;
}

/**
 * Custom function to query and build new filter list.
 *
 * @param $node_type
 * @param $exposed_block_id
 * @return array
 */
function _get_available_terms_tags($node_type, $exposed_block_id) {
  // Table name of tags field
  $node_tags_table = 'node__field_tags';
  // Query data.
  $query = \Drupal::database()->select($node_tags_table, 'nft');
  $query->distinct();
  $query->join('taxonomy_term_field_data', 'tname', 'tname.tid = nft.field_tags_target_id');
  $query->join('node', 'node', 'node.nid = nft.entity_id');
  $query->fields('nft', ['field_tags_target_id']);
  $query->fields('tname', ['name']);
  $query->orderBy('tname.name');
  // Dynamically query node type.
  $query->condition('node.type', $node_type);
  if($exposed_block_id == 'views-exposed-form-available-for-review-page-1') {
    $query->join('node__field_boolean_1', 'available', 'available.entity_id = nft.entity_id');
    $query->condition('available.field_boolean_1_value', 1);
  }
  $result = $query->execute();
  // Build term list.
  $term_list = [];
  while ($row = $result->fetchAssoc()) {
    array_push($term_list, [$row['field_tags_target_id'], $row['name']]);
  }
  // Return list.
  return $term_list;
}

Custom functions in the block above, we put these in the same .module file, but maybe it's better to place it in a Drupal service for example. Of course you can always refactor this into one function -more dynamic. But I'll leave that up to you :)

I hope this gives you a head start, please let me know if you have any questions or improvements.

Drupal code Planet Drupal Written by Joris Snoek | Jun 07, 2021

Join the conversation

Jun 02 2021
Jun 02

If you need a temporary buffer in Drupal to save data to, Drupal's tempstore service might come in handy. We used it for example in a webshop module, where users didn't have a saved address yet and also had to option to never save their address permanently (because of gdpr).

So, after some searching, the code is pretty straight forward. This example might save you some time to implement it

We implemented this in a custom Drupal webshop service, the functions are called in other code via dependency injection. So here is how to set and get your custom data with help of Drupal's tempstore:

(Be aware: the tempstore data wíll expire automatically)

  /**
   * Set data in Drupal's temp_store.
   *
   * @param array $vars
   */
  public function setMyDataInTempStore(array $vars) {
    // Get tempstore service.
    $tempstore = \Drupal::service('tempstore.private');
    // Get tempstore data we need.
    $tempstore_data = $tempstore->get('my_custom_key');
    $params = $tempstore_data->get('params');
    // Fill vars.
    $params['var_1'] = $vars['var_1'];
    $params['var_2'] = $vars['var_2'];
    // Save vars to tempstore.
    $tempstore_data->set('params', $params);
  }

  /**
   * Get data from Drupal's temp_store.
   *
   * @return array
   */
  public function getMyDataInTempStore() {
    // Get tempstore service.
    $tempstore = \Drupal::service('tempstore.private');
    // Get tempstore data we need.
    $tempstore_data = $tempstore->get('my_custom_key');
    $tempstore_params = $tempstore_data->get('params');
    // Get vars.
    $my_var_1 = $tempstore_params['var_1'];
    $my_var_2 = $tempstore_params['var_2'];
    // Return data in array.
    return [
      'var_1' => $my_var_1,
      'var_2' => $my_var_2,
    ];
  }
Drupal code Planet Drupal Written by Joris Snoek | Jun 02, 2021

Join the conversation

May 25 2021
May 25

Last week we released a new version of OpenLucius: a lean and fast Drupal social collaboration distribution with features like: groups, social posts, messages, group chats, stories, file -and folder management, notebooks, categories, activity streams, notifications, @-mentions, comments and likes.

OpenLucius 2.0 has been in production for the last ~5 months, it's stable enough to go into beta! We also keep on improving: what we globally did since last release:

  • Added new features;
  • Enhanced existing features;
  • Tweaked UI / Design.

All work we did was based on feedback we got internally, from our customers -and trial users. And we plan to keep it this way, so if you have ideas for new/better features: let me know!

The fastest way to explore OpenLucius is by trying it via the product site. And since a lot has changed, I though I'd make it easy on myself by just showing off with current main features -with the newest on top, here you go:

Task / Kanban Board (*Sneak peak*)

You can already try this task board, but it needs work to get it to an open source release. We plan on releasing this as an add-on contrib module:

Screenshot kanban board

@-mentions (*new*)

What we really missed in previous version where @-mention, so that's now included in texts and chats, with autocomplete:

screenshot @mentions

@group mention: As you can see, you can also mention everyone in current group.

Technical background: via Drupal core's CKEditor this was hard to accomplish, so we tested out other editors and came up with open source editor Summernote, a light-weight editor based on Bootstrap. It's extendable, able to facilitate inline-editing and it's also very nice that it automatically inherits theme styling (since it's not loaded via an iframe). 

Also, we are building a Kanban/Scrum board with highly interactive modals and for example: inline editing of card descriptions and comments. For that we also needed a lean editor.

And last but not least: we could tweak the editor UI, making it blend with the theme smoothly.

Summernote also facilitates drag-and-drop images & texts:

Drag/drop images (*new*)

So drag-and-drop images is now available in all text editors:

screenshot drag and drop images

It also has some great, user friendly, inline image options:

Screenshot image options summernote editor

General settings (*new*)

Set global colors, homepage tabs and homepage image:

screenshot General settings

Order book pages (*new*)

You can now order book pages easily, with unlimited depth:

Screenshot order pages

Groups

Screenshot groups home

  1. Group name, with drop down for group settings.
  2. Group sections, with activity badges that you can turn on/off per group.
  3. Group activity stream, bundled per day.

Activity streams (global and per group)

Homepage with activity stream example:

Screenshot homepage

  1. Home banner, configurable;
  2. Stories;
  3. Activity stream, personalised, bundled per day, per group;
  4. Your Groups, with link to group archive;
  5. Social posts, global, can also be turned off.

Social posts

Screenshot  social posts

Messages

Screenshot messages

Group chats

Screenshot group chats

Stories

Screenshot stories

File -and folders management

Screenshot docs and files

Notebooks

Overview:

Screenshot notebooks

  1. Hierarchical book pages;
  2. Order pages modal;
  3. Like and comment;
  4. Add file attachments to comments and notebooks.

Order pages easily, with unlimited depth:

Screenshot order pages

Use notebooks for example for:

  • Project documentation
  • Manuals
  • Notes
  • Web links
  • Agreements
  • Minutes
  • Ideas
  • Brainstorm sessions
  • Onboarding information
  • House rules
  • Customer information
  • ...whatever needs text.

Notifications (non-disturbing)

Screenshot notifications

Comments

Screenshot reacties

Likes

Screenshot Likes

Get it, got it, get that!

That's it for now, if you want to test OpenLucius this instant, that of course is possible via the product website. Or download and install OpenLucius yourself via the project page on Drupal.org

Planet Drupal Written by Joris Snoek | May 25, 2021

Join the conversation

Jan 08 2021
Jan 08

(Available as freelancer)

Joris Snoek

Business Consultant
/ Drupal Developer

Last week we released 'group chats' in Drupal distribution OpenLucius, a social productivity platform. At first sight it maybe looks like a small module. But it took quite some effort to get to this release. Also because I wanted to release it open source: no concessions in (code) quality and maintainability.

Our 'group chat journey' started around 3 years ago, when we kicked off building OpenLucius on Drupal 8. We thought it was best to implement the realtimeness with MongoDB, because of the no sequel character and its speed. Also, a lot of chat examples were using the MEAN stack.

ReactJS / VueJS (not needed)

Also, javascript frameworks like ReactJS and VueJS were/are a hype -some developers like to jump on it without looking into native Drupal alternatives, I also fell into that trap -it's a dangerous area:

Hello over-engineering, complexity and project misery.

We thought we needed it for frontend interactivity, but that implementation added even more unnecessary complexity to the project.

Drupal 8

After a long struggle, that Drupal 8 version never saw the light of day. We did use it for a while internally but it was not suitable for the outside world -that's a euphemism right there.

Native Drupal 9 group chat, a PoC

So about a year ago I started with a proof of concept to see if realtime group chat was possible with use of just Mysql and jQuery, it turned out it did! So that meant that the group chat module could be implemented native in Drupal.

That was a huge relief and paved the way to an open source release. Because I wanted the installation process to be as simple as possible for everybody, not complex with installing ReactJS / MongoDB and what not.

Just click through the Drupal install wizard and done, that was the goal -and we reached that.

Well.., full disclosure: one piece of external tech required is Node.js (with Socket.io). Else realtime emitting/pushing messages in 'rooms' (group chats) just isn't going to work, Drupal core has no Websocket tech built-in.

But installing the Node.js chat engine also is a few click operation after installing OpenLucius. And: it's optional, so a basic Drupal wizard install is the only thing required to get OpenLucius up and running.

Fast forward 2021, Drupal natives Mysql and jQuery FTW!

So, after the successful proof of concept in 2020, it is safe to say:

be very considered when implementing external tech. Drupal core has excellent native tech for facilitating speed and interactive UI's.

Of course the tech you choose in the end depends on your requirements/user stories. But just make sure you invest enough time in analysing Drupal core and contrib modules, before integrating external tech.

Especially if you want to release open source.

Code for performance

So Drupal natives Mysql and jQuery can work great.. as long as you code it right. And with 'right' I mean, in our case of the group chat, that the code needs to be as lean as possible: chat messages must eventually be realtime.

So I implemented custom Drupal entities and custom code that only does the thing it needs to do, nothing more and certainly nothing less (so for example the Drupal core node system is obviously not handy in this case).

To wrap it up, it turned out that these rules prevailed:

It's hard to make things simple. Experience is the grandmaster of all skills.

Technical details in next blog

In my follow up blog I will get into the tech behind the group chat in Drupal: the use cases and how I implemented them, all without page refresh / Drupal AJAX based:

  • Chat screen initialisation
  • Adding messages and realtime emitting them to all chat users
  • Files uploads via AJAX
  • Dynamic theme libraries, for socket.io connection
  • Node.js / Socket.io implementation
  • @mentions javascript library, with auto suggest
  • Mailing the people that where @mentioned
  • Security and permissions
  • Security hardening with group uuid's
  • How to handle CORS if socket.io runs on external server
  • If connection drops, make sure no messages are missed
  • Edit messages via AJAX
  • Deleting files from the chat via AJAX
  • Dependency injection

    So stay tuned y'all!

Try now or download open source

If you want to test the group chat in OpenLucius this instant, that of course is possible, click here to get started -> Hit 'try now' button. Or download and install OpenLucius yourself via the project page on Drupal.org

Jun 19 2019
Jun 19

(Available as freelancer)

Joris Snoek

Business Consultant
/ Drupal Developer

Last month we worked in a project where we implemented a progressively decoupled Drupal platform. We needed a React.js frontend to to all kind of magic that was less available in Twig. Also, this way frontend engineers and backend engineers could work more loosely together, which is great.

Main reason we choose progressive decoupled instead of fully decoupled is because we wanted to make use of Drupal's roles, permissions and authentication, plus some other Drupal native stuff that in fully headless would become very cumbersome to deal with.

Check out this blog on 'How to decouple Drupal in 2019' and find out if you also need Drupal beheading or not.

React libraries dynamically in Drupal

The target was to implement the React.js libraries in Drupal pages, so React would load withín Drupal and we could use all native Drupal goodies like authentication.

By the way: you can also use Drupal authentication when fully decoupled, check this article

So, the thing with React is: every time you release a new version of your App, you'll have to render a new build, that sort of looks like this:

More specifically, the .js and .css files we need to load in Drupal are defined in asset-manifest.json:

So, those files need to be loaded in Drupal, and change every time you run a new build in your React App for example with npm run build.

But you can't add these React javascript libraries to your theme's YOURTHEME.libraries.yml because with the next build the links be be different.

hook_library_info_build() to the rescue

Aaaah, so Drupal 8 provides us with hook_library_info_build() that will save our day (づ。◕‿‿◕。)づ

Now, how we did this:

Implement the Drupal hook in your .module file (For highlighting's sake, I added .php, loose that. #nobrainer):

As you see, it will read React's asset-manifest.json and registers all .js and .css files of React.js as a library in Drupal.

Next up, you can render this library for example in a Controller like this:

Wrap up

So that's how we integrated React.js within Drupal pages and combined the power of a React frontend with the power of Drupal goodies, in a 'progressively decoupled' way.

Please let me know if you have any questions.

Feb 10 2016
Feb 10
18 Drupal SEO modules - and tools for better findability in Google Search engine optimization (SEO) has always been important, but in recent years its importance seems to have increased significantly. We were more often dealing with Drupal SEO implementations than in previous years. Many of the implementations contained overlapping components. Below we will discuss the most important ones:1. SpeedGoogle Page Speed is a good indicator of how speed is experienced by end users and therefore by Google. Google attaches great importance to speed because end users are simply doing the same.An example of a test of the front page of this site:
Jan 23 2015
Jan 23
Drupal REST Web Services - What, why and how So, here at Lucius HQ we are planning on building a RESTful API (web services) on top on Drupal distribution OpenLucius.We want to do this so all 3rd party programmers, thus 3rd party applications, can integrate with OpenLucius. And not only Drupal developers and Drupal modules. For example: integrate time tracking with Toggle, invoicing with Freshbooks or integrating with other case trackers like Jira, Asana or Basecamp. And there are a lot more apps out there with huge potential you can tap into.So, a brief intro in web services in Drupal:
Sep 08 2014
Sep 08

(Available as freelancer)

Joris Snoek

Business Consultant
/ Drupal Developer

Geen introductie vandaag, let's go! :)

11) Security Review


Bron afbeelding

Voorzorg en veiligheid boven alles, dit zou hoge prio moeten hebben bij elk project. Deze module kan je daar aardig snel mee helpen.

Je kunt hiermee namelijk een checklist genereren die nagaat of alle voor de hand liggende Drupal veiligheidsfouten zijn nagelopen/ge-checkt.

Hij checkt bijvoorbeeld:

  • Is je Drupal bestandsysteem juist ingesteld?
  • Wordt er geen gevaarlijk content toegelaten (tegen bv cross site scripting / XSS)?
  • Of er op een veilige manier fouten worden gerapporteerd?
  • Zijn je 'Drupal private files' wel echt privé?
  • Beveiliging tegen 'brute force attacks' (vele malen achter elkaar kunnen inloggen om wachtwoord te raden)
  • ...en meer (nu ben ik het zat :-) ).

https://www.drupal.org/project/security_review

10) Dynamic Internal Linking

Bron afbeelding

Module die de SEO van je Drupal website kan boosten. We doen het zelf ook te weinig, maar door interne links schijnt het dat zoekmachines je website beter kunnen lezen / structureren. Dus vinden zoekmachine dat leuk en daardoor boost je je SEO.

Deze module kan door jou voorgedefiniëerde woorden automatisch intern laten linken.

https://www.drupal.org/project/dynamic_internal_linking

09) Entity Lister (Drupal Developer module)

Als die hard Drupal developer zal je relatief vaak gebruik maken van de 'EntityFieldQuery' functie. Hierin zag de bouwer van deze module veel herhaaldelijk werk bij verschillende implementaties. En zoals een goede developer betaamt, wordt eenzelfde functie nooit twee maal geschreven.

Deze Drupal API module zorgt er dus voor dat je niet elke keer hetzelfde 'EntityFieldQuery proces' hoeft te coderen. Doorgaans vormen deze stappen dat proces:

  • 1) Entity ID's querien mbt EntityFieldQuery
  • 2) Entity laden m.b.v. entity_load()
  • 3) Elke entity door een view functie (bv node_view() of entity_view() heen halen.
  • 4) Elke entity 'redenderen' m.b.v. drupal_render()

Deze module implementeert een class waarin dit allemaal wordt gefaciliteerd voor je. Het is een 100% Drupal API / Developer module, wat wil zeggen dat er geen grafische interface is maar middels Drupal code functies benut kunnen worden.

Hij heeft een aantal handige tools aan boord:

  • Bepaal hoeveelheid items, bundles, 'view mode', sortering, paginanummering, caching, tabel headers en meer.
  • Je kunt meerdere 'bundles' combineren in een lijst
  • Caching is goed voorbereid, super belangrijk voor performance van je Drupal systeem.
  • AJAX technieken mogelijk
  • Integratie voor 'node view permissies'
  • Ingebouwde 'access control' voor Drupal nodes, gebruikers en reacties.

Je kan het bijna zien als een 'Drupal Views voor developers' :-)

https://www.drupal.org/project/entity_lister

08) Inline registration

Maakt de drempel lager voor mensen om zich te registreren op je Drupal website.

Deze module integreert namelijk het registratieformulier met het 'toevoegen van content formulier'. Waardoor het slechts 1 stap kost voor mensen om content toe te voegen in plaats van 2 stappen.

https://www.drupal.org/project/inline_registration

07) Memory profiler (Drupal Developer module)

Wanneer je Drupal website performance problemen krijgt, kan dit veroorzaakt worden doordat het geheugen van je server te snel vol loopt. Een oorzaak hiervan is meestal niet-geoptimaliseerde code of queries.

Deze lichtgewicht module helpt je bij het zoeken naar pagina's binnen je Drupal site die veel geheugen vreten.

Met behulp van de DrupalDevel module kan je door pagina's klikken en onder aan je website tevens geheugen statistieken zien. Maar deze module logt alles voor je, zodat je achteraf dit log kan analyseren. Handig joh!

Memcache, bij ons geïnstalleerd op alle Drupal systemen, wordt ook ondersteunt sinds kort.

https://www.drupal.org/project/memory_profiler

06) Picture

Bron afbeelding

Dit is een backport van de Drupal 8 'Picture' module.

Deze module kan voor een performance optimalisatie zorgen: hij zorgt ervoor dat een alternatief afbeelding (vooral qua MB's) wordt uit geserveerd, wanneer blijkt dat er weinig bandbreedte is, of wanneer blijkt dat het scherm geen hoog resolutie afbeelding (niet-retina) nodig heeft.

https://www.drupal.org/project/picture

05) Restrict Login or Role Access by IP Address

Drupal veiligheid, wie is er niet groot mee geworden :-)

Deze module biedt extra functies tbv de veiligheid van je Drupal website. Hij kan ervoor zorgen dat bepaalde gebruikers, of gebruikers met een bepaalde role alleen kunnen inloggen vanaf een bepaalde 'gewhitelist' IP-adres

https://www.drupal.org/project/restrict_by_ip

04) Shared Email

Er zijn van die uitzonderlijke situaties waarin je graag wilt dat je meerdere Drupal users kan aanmaken, met hetzelfde e-mail adres.
Bij ons kan dit voornamelijk bij ontwikkel -en testdoeleinden handig zijn.

Deze module doet hierin zijn ding.

https://www.drupal.org/project/sharedemail

03) Node Expire

Soms zou je automatisch, na een bepaalde tijd, een bepaalde handeling op een node willen uitvoeren.

Bijvoorbeeld: depubliceer deze drupal node over twee weken automatisch.

Deze module kan je daarin helpen: je kunt acties uitzetten op nodes die na een bepaalde tijd automatisch worden uitgevoerd.

https://www.drupal.org/project/node_expire

02) Webform steps

Wanneer je webformulier veel velden bevat, is het goed om deze op te delen in stappen.

Je raadt het al: deze module kan dit voor je uitvoeren. En geeft daarom een behoorlijk usability boost, wat het voor je Drupal bezoekers makkelijker maakt om zichzelf te registreren en jij meer conversies behaalt. Iedereen happy!

https://www.drupal.org/project/webform_steps

01) File lock

Sommige geüploade files wil je beschermen, zodat ze niet per ongeluk verwijderd of gewijzigd kunnen worden.

Wanneer je deze module installeert kan je Drupal files 'locken' en weer 'unlocken', zodat ze niet door iemand anders weg gehaald kunnen worden.

https://www.drupal.org/project/file_lock

Wrap up

That's it, vragen of suggesties? Let me know yo!

Aug 28 2014
Aug 28

(Available as freelancer)

Joris Snoek

Business Consultant
/ Drupal Developer

Tijdens controle door de Drupal community van onze Drupal distributie OpenLucius (een Drupal social intranet) liepen we tegen volgende issue aan:

We gebruikte de functie arg(); hier en daar om logica af te vangen. En wat blijkt: "arg() is evil". Dit hadden we kunnen weten, het lijmt argumenten en functies té absoluut aan elkaar vast.

Bericht in een Groep

Een case waar we arg(); gebruikte was: om te bepalen in welke Groep een item toegevoegd wordt. Bijvoorbeeld een Bericht 'Welkom in deze projectgroep' toevoegen in een Groep 'Project nieuwe website'.

*Warning: nerd alarm vanaf hier* :)

Hoe we dit technisch oploste (the evil way)

  • Voeg de group node id toe aan de link om een bericht toe te voegen. Dat werd dus bijvoorbeeld 'node/add/ol-message/34'.
  • We vingen in hook_form_alter() dat argument op met evil arg(); .
  • En zorgde middels code in die hook_form_alter() dat het Bericht middels een Node reference field automatisch werd gekoppeld aan de juiste Groep.

Dat is dus níet goed.

Ok, maar hoe dan?

Collega Thomas heeft hiervoor een oplossing bedacht. Deze is nog wel in alpha fase, we moeten hem dus wel goed testen én de Drupal community moet het met ons eens zijn.

In de basis draait die om het overriden van het standaard Drupal node/add formulier, zodat we het gerefereerde Group node id tot onze beschikking hebben in het formulier. Waarna het ingevoerde Bericht automatisch kan koppelen aan de Groep waar hij toegevoegd wordt.

  1. Voeg een custom hook_menu() toe met een custom callback.
  2. Voeg de custom callback functie toe.
  3. Override het standaard Drupal node/add formulier.
  4. Koppel automatisch, middels code, de Group nid in het node reference field 'Group reference' , zodat het Bericht gekoppeld wordt aan de juiste Groep.

1. Voeg een custom hook_menu() toe

/** * Implements hook_menu() */function openluciuscore_menu() {  $items = array();  $items['node/add/ol-message/%'] = array(    'title'            => t('Message'),    'title callback'   => 'check_plain',    'page callback'    => 'openluciuscore_node_add',    'page arguments'   => array('ol_message', 3),    'access callback'  => 'node_access',    'access arguments' => array(      'create',      'ol_message'    ),    'description'      => t('Facilitates OpenLucius Messages in Groups'),    'type'             => MENU_NORMAL_ITEM  );}
  • Roept de functie 'openluciuscore_node_add' aan
  • En geeft het derde argument uit de URL dynamisch door aan die functie: 'array('ol_message', 3)'

2. De custom callback functie

/** * Custom callback for node add * @param $type * @param $group * @return array */function openluciuscore_node_add($type, $group) {  global $user;  // sanitise group input  $sanatized_group = filter_xss($group);  // check if the user may add content into this group  if (_olcore_user_in_group($sanatized_group, $user -> uid)) {    // load requirements    module_load_include('inc', 'node', 'node.pages');    // fetch form    $form = openluciuscore_node_add_with_group($type, $sanatized_group);  }  return $form;}
  • Vangt de 'Groep variabele' op in het tweede argument van de functie
  • Laadt alle noodzakelijke code uit de core
  • Laad en returnt het 'node/add' formulier

3. Override het standaard Drupal node/add formulier

/** * Custom version of node_add found in the node.pages.inc * @param $type * @param $group * @return array */function openluciuscore_node_add_with_group($type, $group) {  global $user;  $types = node_type_get_types();  $node = (object) array('uid' => $user->uid, 'name' => (isset($user->name) ? $user->name : ''), 'type' => $type, 'language' => LANGUAGE_NONE);  drupal_set_title(t('Create @name', array('@name' => $types[$type]->name)), PASS_THROUGH);  $output = drupal_get_form($type . '_node_form', $node, $group);  return $output;}
  • Laat het standaard Drupal 'node/add' formulier en voegt de extra build info toe om de Groep variabele door te geven.

Wrap up

OK, that's all folks. Vragen of suggesties? Let me know.

About Drupal Sun

Drupal Sun is an Evolving Web project. It allows you to:

  • Do full-text search on all the articles in Drupal Planet (thanks to Apache Solr)
  • Facet based on tags, author, or feed
  • Flip through articles quickly (with j/k or arrow keys) to find what you're interested in
  • View the entire article text inline, or in the context of the site where it was created

See the blog post at Evolving Web

Evolving Web