Trying to access modules page callback while authenticated I have a module below that will only show "hello world" when I am an administrator. I would also like "hello world" to display when I an authenticate user but right now all I am getting is you are not authorised. I have set  mymenuitem as the home page and I am using Drupal 7.

 function mymenuitem_menu() {
  $items = array();
  $items['mymenuitem'] = array(
    'title' => 'mymodule',
    'description' => 'my menu access issue',
    'page callback' => 'mymodule_homepage',
    'access arguments' => array('access mymodule homepage'),
    'type' => MENU_LOCAL_TASK,
  );

  return $items;
}

function mymodule_homepage(){
  drupal_set_title(t('menu system'));
  return "hello world";
}

How can I achieve this?

Make sure you define your new permission using Drupal 7's hook_permission().
Grant your new permission to authenticated user here: /admin/people/permissions/list

Try this:

function mymodule_permission() {
  return array(
    'access mymodule homepage' => array(
      'title' => t('Access My Module homepage'),
      'description' => t('View My Module homepage.'),
    )
  );
}


How to use [submission:values] in Email template in Webforms I have the Webform 7.x-4.0-alpha6 version module enabled.

I have a Webform node with 20 form components. I added one email in Email Setting and I created the email template where I used the token: [submission:values].

Then I test the webform submitting a message. The problem is that [submission:values] print out the components values in a very plain way, no break line, no semicolon to make a difference between the title and the value for each component. Something like:

Name Jhon
Addresss Myaddress 12
CP 19932
....

Having 20 component make the email completely unreadable

My question is: Is there a way (a token) to print them in a better way, at least adding a semicolon between the title and value, and making the title bold ? or putting the output in a table?

    Name: Jhon
    Addresss: Myaddress 12
    CP: 19932

I know that I can print out the components in a separated way using the tokens:
[webform:{component}-title] for the title
and
[webform:{component}-value] for the value

And then I can style them. But this is time wasting since I need all components to be shown in the email template

Update: I found this module but doesn't help me: http://drupal.org/project/webform_tokens

I haven't such problem, but I know, how to get special values from webform.

  Webform tokens from submitted data. Includes the value and field label. Replace the "?" with the "Field Key". Append ":nolabel" for just the value.

So, you can use [submission:values:?:nolabel], where ? is field key of your component.

 Name: [submission:values:name:nolabel]
 Address: [submission:values:address:nolabel]

For me result is the same as for [submission:values]:

  Name: Kate
  Address: Moscow, Russia :)

Webform version: 7.x-4.0-alpha6 (7404).

Webform Tokens module is not needed.

Update

If you are using HTML mail, labels are outputted via theme_form_element_label and look like <label>Title</label>\n.

You can override webform-submission.tpl.php. Copy this file to the theme for rendering the emails from admin/config/system/mailsystem.
To add : I suggest just to modify render array:

if ($format == 'html') {
  foreach ($renderable as $i => $item) {
    if (is_array($item) && !empty($item['#title'])) {
      $renderable[$i]['#title'] .= ':';
    }
  }
}

print drupal_render_children($renderable);

But you can output substitutions fully yourself.


how can i get path vocabulary based taxonomy term with node title using views? I have created vocabulary called Category and it contains below hierarchy

term1
  term 1.1
     term 1.1.1
     term 1.1.2
     term 1.1.3
  term 1.2
term2

and i have assigned to this category to content type called Product after that i have displayed those product items based on category using views with panels it's working fine.when i click product title the url goes like this

http://www.example.com/content/prodcut-title

but i want path like this

http://www.example.com/category/term1/term1.1/term1.1.1/product-title
category with term based product title using views.

Please suggest possible ways,

Thanks.

Try to change alias pattern for products. Install Entity Token + Pathauto, and on Pattern tab in alias settings (admin/config/search/path/patterns) try to use something like:

[node:field-category:parents:join:/]/[node:field-category:name]/[node:title]


Is it possible to add permissions to a Ctools content type plugin? Is it possible to add permissions to a Ctools content type plugin, similar to a node entity?  I want to be able to check if a user has permission to add a certain content pane to a panels page through the IPE.

It should be possible using a ctools access plugin.  From the linked site:

  Firstly, just like during work with Сtools content type, for the web developer it is necessary to call hook_ctools_plugin_directory() to indicate that we have ctools plugins of specific type in our module:

/*
 * Implements hook_ctools_plugin_directory().
 */
function access_example_ctools_plugin_directory($owner, $plugin_type) {
  if ($owner == 'ctools' && !empty($plugin_type)) {
   return "plugins/{$plugin_type}";
  }
}

  Then in module folder we need to create "plugins" folder and "access" folder inside of “plugins” folder. Create plugin file with the name "access_example_plugin.inc" inside of "access" folder. Write the access rule by array in this file:

/**
 * Plugins are described by creating a $plugin array which will be used
 * by the system that includes this file.
 */
$plugin = array(
  // Plugin user-friendly name.
  'title' => t('Eldership rule'),
  // Plugin description.
  'description' => t('Controls access depends on eldership'),
  // Without required context plugin will now be shown in Panels UI.
  'required context' => array(new ctools_context_required(t('User'), 'user')),
  // Function which will allow or restrict access.
  'callback' => 'access_example_who_elder_access',
  // Plugin settings form.
  'settings form' => 'access_example_who_elder_access_settings_form',
  // Provides a summary descriptions depends on settings selected.
  'summary' => 'access_example_who_elder_access_summary',
);

It goes on to explain how to create the various callbacks but that's beyond the scope of this question I think.


Ubercart/Securepages site breaks overnight!? Can't POST (login/add to cart) This site seemingly broke overnight without any changes being made to the configuration.. this is a production site:

https://www.skinnyboyswagclub.com/cardigan

Add an item to your cart and watch the network activity.. It redirects through a 302. Is this secure pages switching to https? (even though it's submitting from https?)

Nothing gets added, no errors.

Can't login either. Logging in with the correct password (guest/guestpass) doesn't work either.

I did add another dns record the other day to point ".dev." at another server. Could that have broken the production site at www.?

I removed the record just now, in case..

Since this is an issue on a production site and I can't even log in, I'm BEGGING for help! :|

I had a similar issue. You can look at this and this to get a bit more insight as to what my problem ended up being. Here are somethings you may want to try;

Enable your cookies via your settings.php file. (This is something that helps with securepages).
Enable secure pages across all your pages. This will test if its the issue with securepages losing its session values. If it works, then you need to wait till secure pages gets fixed OR just make every page on your site HTTPS.
Turn caching off. For some reason, this was conflicting with my current setup. It wasn't until I did this that ALL my problems went away.

Good luck and I hope this helps.


How to add a extra products fields on ubercart check out pane table? Hi im looking to add some extra fields on the check out pane, i mean fields from the product like some attributes, theres any possibility?

Please if someone how to do this let me know!

Thank's to everyone who can help me!

You can go for Ubercart Webform Integration

This module integrates two other modules: webform and ubercart. It allows you sell
products directly from your webforms. It is particularly suited to be used as part of a
registration system.


How to make a taxonomy term display a field I set up a taxonomy vocabulary (College attended) to be a field in my profile 2 registration form.

When a new user registers, he selects one of the terms of the vocabulary (i.e colleges).

I would like to have the surname of the users (a field in the core registration form) who went to a particular college displayed when a term is selected.

Please how do I achieve this.
P.S.: Presently I get only the notice "There is currently no content classified with this term", when i select a term.

Thanks in advance.

Create a view which shows surname of person given a username. Use https://drupal.org/project/viewfield and add it as field in the taxonomy and it should show surname.

By default linked users are not listed under taxonomy terms (read here : Assigning User's In Taxonomy Terms) and there is another useful post: https://stackoverflow.com/questions/11524357/how-to-link-a-user-with-taxonomy-terms


Tagging people on blog entries and being able to access their profiles from tags I'm trying to create a blog posts where users are able to create challenges and tag other users. I succeeded in creating blog entries, I succeeded in adding tags on blog posts.

But I struggle with making so that clicking on tag would bring me to the user profile. I tried creating taxonomy called users and I specified url alias: /user/* Saddly if I clicked on tagged person, Im being brought to ..../taxonomy/term/4

How can I solve this?

You can achieve that using the Mentions module

  The Mentions module offers Twitter like functionality, recording all references to a user's username - using the [@username] or [@#uid] filter format - from various locations, providing a centralized page to track all mentions (via the Views module).

This module provides a configuration page, through that you can define the mentions pattern, and path (supports tokens)


Open Atrium: How to add an action button on a view node I can add a button on the node edit form using a hook_form_alter and adding a new element to $form['actions'].

However, I would also like to add a button to the node view, next to + Create. I assume there's an api for this but I can't seem to find it in the code or in documentation.

I found the solution. First, some terminology: the links in the dropdown menu on the bottom right are called Contextual Tabs. Second, the buttons with an icon are called Extracted Tabs. These settings are found in two different locations.

First, make your menu item a regular context tab. Go to admin/openatrium/setting and open the Contextual Tabs fieldset. Fill in the link to your page/menu item:

Next, extract the Contextual Tab as a button. Go to admin/config/user-interface/contextual-tabs and fill in the link and/or the label to your page/menu item in the Tabs to extract textarea:

Your link will now be displayed as a button with an icon of your liking.


How do I add a Twig Filter? I made a custom module that extends TwigExtension, where I define all sort of custom twig filters. It worked well until the update to 8.3, where TwigExtension changed slightly:

/**
* Constructs \Drupal\Core\Template\TwigExtension.
*
* @param \Drupal\Core\Render\RendererInterface $renderer
*   The renderer.
* @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator
*   The URL generator.
* @param \Drupal\Core\Theme\ThemeManagerInterface $theme_manager
*   The theme manager.
* @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
*   The date formatter.
*/
public function __construct(RendererInterface $renderer,
  UrlGeneratorInterface $url_generator, ThemeManagerInterface
  $theme_manager, DateFormatterInterface $date_formatter) {
  $this->renderer = $renderer;
  $this->urlGenerator = $url_generator;
  $this->themeManager = $theme_manager;
  $this->dateFormatter = $date_formatter;
}

My service yaml looked like this:

services:
  custom_twig.twig.extension:
    arguments: ['@renderer']
class: Drupal\custom_twig\TwigExtension\LabTwigExtension
tags:
  - { name: twig.extension }

And I changed the services to have the new required ones.

services:
  custom_twig.twig.extension:
    arguments: ['@renderer', '@url_generator', '@theme.manager','@date.formatter']
class: Drupal\custom_twig\TwigExtension\LabTwigExtension
tags:
  - { name: twig.extension }

Although I set the correct arguments, Drupal throws an error:

  Recoverable fatal error: Argument 2 passed to Drupal\Core\Template\TwigExtension::__construct()
      must implement interface Drupal\Core\Routing\UrlGeneratorInterface, none given, called in /A

I am fairly certain that url_generator implement UrlGeneratorInterface. Is there anything else I got wrong?

If you are using Twig Extender , try updating it to version 8.x-2.0-rc1. It worked for me


Suggestion for "Convert line breaks into HTML" and text editor for corporate website Previously when developing my own community website in Drupal 6, I've never know what people like when dealing with text editor. So I simply go with Ckeditor and untick Convert line breaks into HTML in the Text format options.

But now developing corporate website in Drupal 7. Ckeditor is in early stage (lack of visibility option) and I cannot use wysiwyg module because it has many conflict.

One good choice is use Bueditor. It looks clean and perfect but i must tick Convert line breaks into HTML in the Text format options to make it works for paragraphs.

So, should I:

use wysiwyg editor and untick Convert line breaks into HTML ?
or use Bueditor and tick Convert line breaks into HTML ?

You can use Wysiwyg (or CKEditor) along with most editors and use Wysiwyg Linebreaks to make the editor work great with existing content, or when switching between editors, and in other circumstances.

Also, Wysiwyg should be pretty stable (I've been using it on a ton of different sites), especially when using it with CKEditor, TinyMCE, or most other editors.

For most of my sites, I have the Convert line breaks into HTML option checked no matter what, mostly because I like being able to see/edit content without extraneous paragraph and line break tags all over the place, and so paragraphs don't get run together.


Cannot redeclare class Drush error When I go to my site on command line and run a drush command I get the following error:

PHP Fatal error:  Cannot redeclare class Drush in /var/www/xmd8/www/vendor/drush/drush/lib/Drush.php on line 36

If I run which drush I get:

/usr/local/bin/drush

I have the Lightning Distribution installed via composer and they are adding Drush.

Any ideas on how to fix this?

What version of Drush are you using?  Recent versions of Drush will notice that there is a copy of Drush included in your Drupal site, and will redispatch (exec) to use it instead.  If you are using an old, unsupported version of Drush (e.g. Drush 6 or earlier), then it will not do this, and the error you see above would be the likely result.


Problems moving whole project from one directory to another I have Xampp Portable installed on Windows 10.

I run about a dozen Drupal, Wordpress and other CMS on there. I can move the whole stack to different drives and machines and it all works perfectly, only one that can't work is D7/CIVICrm install.

When I move it to another directory I get this error:

 Fatal error: Cannot redeclare class CRM_Core_ClassLoader in C:\Core\XAMPP_2018\htdocs\crm4\sites\all\modules\civicrm\CRM\Core\ClassLoader.php on line 36

I can see that the path in the error is the wrong path.

The correct new path is:

G:\XAMPP_2018\htdocs\crm4

And not:

C:\Core\XAMPP_2018\htdocs\crm4\

As stated in error, where should I go change that setting? In what file/directory?

Had to change the path name in civicrm.settings.php from:

G:\XAMPP_2018\htdocs\crm4

To

C:\Core\XAMPP_2018\htdocs\crm4\

This is around LINE 180:

Code looks like this:

$civicrm_root = 'G:/August25/XAMPP_2018/htdocs/crm4/sites/all/modules/civicrm';
if (!defined('CIVICRM_TEMPLATE_COMPILEDIR')) {
  define( 'CIVICRM_TEMPLATE_COMPILEDIR', 'G:/August25/XAMPP_2018/htdocs/crm4\sites\default\files\civicrm\templates_c\');
}

But the slashes also have to be forward like this "/", I searched from Windows path, that's why I couldn't find the code using find and replace!


Is Migrate module supposed to be used for imports too? I am in need of an entity import functionality so I started to write my own. But then I started to think if I'm not reinventing the wheel and it occurred to me that maybe Migrate module will be used for this(beside it's main purpose)?

I mean, since all entity fields are objects with their own specifications regarding data they work with, Migrate will probably handle all of this. So am I correct to assume this or should I continue to work on my module? Because right now I started to think about the field objects(FieldDefinition for core fields and FieldInstanceConfig for field API fields) and I would need to write a lot of data handlers for each type of field and data-type it's working with(boolean, text, file/image, float,...) which will be a lot of work.

On the other hand Migrate would probably have all this data-handlers already in place so they could be reused?

By entity import I mean creating data from csv, xls, xml... files.

Of course! That's why we split migrate_drupal and migrate. The latter is the API, it has the destinations, like the entities you are asking for. Handbook page is at https://drupal.org/node/2127611 useful article at http://webikon.com/cases/migrating-to-drupal-8


In subtheming Commerce Kickstart, how to load my own background image? I followed the instructions in this drupal.org article to subtheme Commerce Kickstart theme, but one thing I didn't get. I have changed the background logo bg.png to my own. Create directory my_theme/images, and put the new bg.png there. There is a line in MyTheme_style.css,
in section 1. Global:

body {
  background: #ececec url("../images/bg.png") left top; }

I've supposed then that the bg.png charged woul'd be my own, but it doesn't happen.

By the way, I first subthemed Commerce Kickstart theme with drush, and followed the other steps to make changes in MyTheme.info file.

I tried provide full path in url("../images.bg.png"), but still not working.

Am I missing something?

Edit: I will explain in details.

First I made a sub-theme of commerce kickstart with drush.

$ drush dl omega_tools
$ drush en omega_tools
$ drush omega-subtheme "The New Theme Name Here" --base=commerce_kickstart_theme --enable

To change some css attributes I create the file livraria-acervo-theme-alpha-default.css, where livraria-acervo-theme is my theme name. That file overrides the attributes changed from commerce-kickstart-alpha-default.css. Ok, works well.

But I need to change some global attributes that are in global.css. Then, from the drupal.org article cited, I follow some parts, as other was already done by drush. File livraria_acervo_theme.info was created by drush. But the code block

; OPTIONAL STYLESHEETS

css[livraria_acervo_style.css][name] = Livraria Acervo theme global style.
css[livraria_acervo_style.css][description] = This file holds all the globally active custom CSS of Livraria Acervo theme.
css[livraria_acervo_style.css][options][weight] = 12
settings[alpha_css][livraria_acervo_style.css] = 'livraria_acervo_style.css'

except the last line, was added in livraria_acervo_theme.info file

I think including this code block in livraria_acervo_theme.info file and create livraria_acervo_style.css and put it in path livrariaacervo/sites/all/themes/livraria_acervo_theme/ would cause my changed attributes in livraria_acrevo_style.css to take effect. But it doesn't.

I also created livrariaacervo/sites/all/themes/livraria_acervo_theme/images/ directory and put my background image bg.png there, and in

body {
  background: #ececec url("../images/bg.png") left top; }

I change "../images/bg.png" by "livrariaacervo/sites/all/themes/livraria_acervo_theme/images/bg.png", but didn't take effect.

The fact is that the livraria_acervo_style.css isn't used, as inspecting the chanted attribute in DOM, the file that is used is commerce_kickstart_style.css

It's my first time with sub-theme a Drupal theme, so I think is something I'm missing.

It's necessary to go in /admin/appearance/settings for your custom sub-theme and in vertical menu on the left, click "Toogle Styles", uncheck the box for "Commerce kickstart theme global style" and click "Save configuration". Now click again in "Toogle Styles" and there is a new option: "MY THEME NAME theme global style. (all) - MYTHEMENAME_style.css".

Check this option and again click in "Save configuration".
Now changes in attributes in mysite/sites/all/themes/MYTHEMENAME/css/MYTHEMENAME_style.css does work.


Your current logout threshold text box I have added the Automated Logout module, now its working fine but in user edit page "Your current logout threshold text box" is showing up what is it. How to remove this please help me?

Go to YOUR_SITE/admin/people/permissionsand under the Automated Logout section uncheck the Change own logout threshold option for authenticated user.


How to add organisation to the Drupal.org user profile? When posting on the drupal.org, I'd like to attribute the contribution, however when I'm selecting it, the label says:

  X at organization not applicable for customer not applicable

When clicked on not applicable link, I've got tooltip that I should add organization on my user profile. However I already did that (in Edit/Account/Work) and it's set as Current organization. What I'm doing wrong?

As an example, have a look at my profile on D.O., which contains this link.

So make sure you have a similar Organization created there, which you can do via Create Organization, which is the link you can also find on Organizations.

If you're not the current owner (or something like that) of such organization, then you need to think of a way to get that Organization created around there. I don't remember any validation (when I registered the one I refer to), but what I would do:

Check with the organization you want to refer to if they are OK with getting such registration.
Have them complete such registration, or ask permission that you do it for them (and have them QA review it afterwards if needed).

If it's a huge organization, it may be a challenge to get approval from such organization, eg to find the right person to ask, and then get the actual approval. In that case, as an alternative, maybe you create something anyway about that organization, but without mentioning their actual name, and only using information that is considered as not confidential? But keep in mind that some companies may not want the world to know that they use Drupal ... eg for competitive reasons ...

Extra hint (for future occasions): try to make it part of contract negociations, something that they confirm that they are aware (and will not object) that you will register them as a company (if they are not yet registered). Possibly adding an appropriate annex to your contract with the details of that registration. It'll slow down contract negotiations, but that's probably the best moment to get approval. If needed offer them some kind of reduction on your rate to make them accept it. And of course, also explain the added value to them for being listed there (like free advertising?) ...

Note: there is also a Marketplace FAQ which may give you more ideas to get an organization registered correctly.


adding js and css to custom templates i created a custom module, which renderes a custom template.

i followed this tutorial

now basically i want to add, bootstrap, jquery, and some custom stling and scripts,

I read this article,

and i am not able to attach any files to my timplate..

my file structure:

 - product_tree
  - templates
     - products-tree.html.twig
  - src
     - Controller
         - productTreeController.php
  - js
     - bootstrap.min.js
     - customScripts.js
     - ...

  - css
     - customStyles.css
     - bootstrap.min.css
     - ...

  - product_tree.libraries.yml
  - product_tree.info.yml
  - product_tree.module

this is my libraries file:

# producttree.libraries.yml
product-tree-libraries:
 version: 1.x
  css:
   theme:
    css/customStyles.css: {}
  js:
   js/customScripts.js: {}
  dependencies:
   - core/jquery

this is my hook:

function product_tree_theme($existing, $type, $theme, $path) {
  return array(
    'products_tree' => array(
      'variables' => array('items' => array(), 'title' => '')
    )
  );
}

i tried attaching it through the renfer array

$build =  array(
    'page' => array (
        '#theme' => 'products_tree',
        '#items' => $items,
        '#title' => 'products',
        '#attached' => array(
            'library' => array(
              'product_tree/product-tree-libraries',
            ),
        ),
    )
);

and in the twig template:

{{ attach_library('product_tree/product-tree-libraries') }}

but still no luck,

in the twig i call the css and scripts

<link href="css/style.css" rel="stylesheet">

i dont know if that is needed, but i tried with and with out, when i include it, i see in the browser inspector that the css file being uploaded, but then "canceled"

can any one tell me what should i do? or what am i doing wrong ?

EDIT:
in the controller, I am renderiung the page like this:

$items = array(
    array('name' => 'product one'),
    array('name' => 'product two'),
    array('name' => 'product three'),
    array('name' => 'product four')
);
$build =  array(
    'page' => array (
        '#theme' => 'products_tree',
        '#items' => $items,
        '#title' => 'products',
    )
);

$html = \Drupal::service('renderer')->renderRoot($build);
$response = new Response();
$response->setContent($html);

return $response;

i made This according to this answer

because i want it to be separated from drupal.
maybe this is the problem?

when i use BareHtmlPageRenderer to render the page (according to this answer). i see drupal imports and the page looks more alive, but still my custom css and js are not there!

I Found the Solution for this.. and it is by using the BareHtmlPageRenderer (found it here) and then attach the files in the controller php file like this

$build['#attached']['library'][] = 'product_tree/product-tree-libraries';

with out the attachments hook function.

so the controller would look like:

    $build =  array(
        'page' => array (
            '#theme' => 'products_tree',
            '#items' => $term_data,
            '#title' => 'products',
        )
    );

    $build['#attached']['library'][] = 'product_tree/product-tree-libraries';

    $attachments = \Drupal::service('html_response.attachments_processor');
    $renderer = \Drupal::service('renderer');

    $bareHtmlPageRenderer = new BareHtmlPageRenderer($renderer, $attachments);

    $response = $bareHtmlPageRenderer->renderBarePage($build, 'Page Title', 'markup');
    return $response;

it could also be in the $build array it self i think.. but this way its better when looking at it..

and still no need for:

{{ attach_library('product_tree/product-tree-libraries') }}

Or

<link href="css/style.css" rel="stylesheet">


How to rename GCC paths I'm using Groups, Communities and Co (7.x-1.0-beta2) and I'd like to rename the paths that are used. As currently it uses the format:

#node#/gcc
#node#/gcc/members
#node#/gcc/role
#node#/gcc/permissions

and I'd prefer it to be:

#node#/group
#node#/group/members
#node#/group/role
#node#/group/permissions

Can this be done without going into the module code and renaming the variables directly?

There are 2 parts to this question:

How to make Drupal accept second paths? Go to http://example.com/admin/config/search/path and set aliases for them. You can use Pathauto to automate this process, or try one of the modules that allows wildcards in aliases.
How to make Drupal generate proper paths? Well, if above will not assure this, use Global Redirect - it'll make sure only aliases are visible to your users.


Combining a digital and a physical version of the same product (without making 2 different nodes/products) using Ubercart I have been struggling for weeks now to find the best solution for the following problem.

Suppose I am a filmmaker and want to sell my films on DVD, Blu Ray, but also as a digital download. Without having to create 3 different products.

I suppose for the two physical objects (choice between DVD or blu ray), I could use a product option. But how to combine it with something only virtual (so no shipping fees, ..) ? Any thoughts what the best way to tackle this would be?

Thanks kind internet stranger!

I would add the digital download as another product option after the DVD and BluRay. Then alter the option’s weight so it’s zero. Then I would create rules that allow for the access or sending a downloadable link once the checkout is complete. Also have a think about how you want to handle a cart that has both physical and digital products together.


How do I remove the ellipsis button in the pager? I have a view with video and have replaced the links to different pages with a button. However, when there are many videos, an ellipsis (...) appears floating, and I want to remove it. I have the View with full pager but I don't see how to control this to hide it. Thanks!

GO to the menu /admin/config/user-interface/pagerer and edit your pagerer

and in Separators -> Configure separators text. remove the (...)


How to apply patch file to views module in Drupal 7 I have problem with my views module. In some occasions it displays this deterrent warning:

Notice: Undefined property: views_handler_field_field::$original_value in views_handler_field->render_text() (line 1118 of C:\wamp\www\novine\sites\all\modules\views\handlers\views_handler_field.inc).

I think I found the patch that could work and save me from this buggy thing. My problem is how to apply downloaded patch to views module. I placed patch file in views folder, cached site, and  nothing happened. That was obviously naive try.
Can someone help me and tell all applying patch procedure? Thanks in advance!

If it is a standard Drupal patch, you use a program named git (part of ambience in most Gnu/Linux configurations) to apply it.  The correct procedure is to first clone the newest released version of the project, apply the patch, then install the patched version in the views folder.  If the patch file is named views-bugfix.patch you download it, and then:

git clone --recursive --branch 7.x-3.x http://git.drupal.org/project/views.git
git apply -v views-bugfix.patch

In some cases, the patch is not for the released branch, but some other branch (this will be mentioned along with the patch).  In that case you need to clone this branch instead.

Source for this info.

If you're stuck in a Microsoft environment and don't have git here is something that may help you: Patching in Windows (haven't tested this myself - I don't do windows.)


Is it possible to filter by Content Type Variant in Views? I have 3 Variants of a Content Type. On one Variant I am listing nodes of that Content Type with a View. I'd like to control what the View returns by limiting the results to 1 variant of the content type.

I've looked through the filter options but haven't found anything that works. Would anyone know if this is possible?

i agree with Niall comment, if is only one contentype, use only one variant and control what to display in views, use content panes views, set contextual filters, relations, and how to pass parameters between views and panels in views ui middle column, pane views are design to "talk" with panels, make several views as needed, add them all to panel variant, and control wich pane to display in panel rules settings.
If there are more than one contentype, add a variant for each one.


How to get the JWT token via webservice After enabling the JWT module. and following Using JSON Web Tokens (JWT) to Authenticate Requests to REST Resources in Drupal 8 on how to use it, it is working.

I know I can access the user JWT token by visiting /jwt/token. My problem is when I try to log in via web services. It returns me the following.

{
    "current_user": {
        "uid": "4",
        "name": "cravushedal"
    },
    "csrf_token": "OlTb7fak5ZS-r1BRiGtBh4IWLm_Z7F1xMpY3KYTGkrU",
    "logout_token": "5DiupHgr9iDxIDVmhHTI3PMX2-Shd6sjuN8hNHrHv7E"
}

With postman
In postman, after login, I receive a cookie, and with that cookie, I can access the jwt/token route and receive the bearer token.

But, I am using angular 5, and what I want is to access to that rout without the cookie, just by csrf token. Is that possible? I mean, I am trying to include it in the header, but not result. Any idea?

Thanks

You may try to use Get JWT on Login module that I have created for the same purpose.


How to attach variables to drupalSettings with ajax? With the page attachments function, I can easily attach a library or some variables to drupalSettings.
Now however, I want to replace some HTML code with ajax AND attach some variables to drupalSettings. While the ajax call does work in replacing HTML, it does not work in attaching or passing along the variables to drupal Settings.
Is there a way I can do both? Here is my code.
public static function AddAJAXResponseCommands(AjaxResponse $response = NULL, array $params = []) {

  $modalSettings = [
    'id' => 1,
    'status' => true,
  ];

  $sample = [
    '#type' => "html_tag",
    '#tag' => "div",
    '#attributes' => ['class' => ['context-menu']],
    '#value' => "Dashboard",
  ];

  $sample['#attached']['library'][] = 'mylibrary/dashboard-js';
  $sample['#attached']['drupalSettings']['dashboard']['myVariables'] = $modalSettings;

  $response->addCommand(new ReplaceCommand('.context-menu', $sample));
  return $response;
}

When I attempt to access drupalSettings.dashboard.myVariables which I confirmed already works when I use the page attachment function, it does not work when using ajax calls. Instead I get myVariables is undefined.
I console logged drupalSettings and sure enough, my variables are no where to be found in there. How can I get it added? Is page attachment the only way to do this?

Use the SettingsCommand
$settings=['ajax_forms_test' => ['foo' => 42]]; /* An array of key/value pairs of JavaScript settings. */
$merge=TRUE; /* (Optional) Booleen Whether the settings should be merged into the global drupalSettings. */
$response->addCommand(new SettingsCommand($settings,$merge));

So your code would become something like this:
public static function AddAJAXResponseCommands(AjaxResponse $response = NULL, array $params = []) {

  $modalSettings = [
    'id' => 1,
    'status' => true,
  ];

  $sample = [
    '#type' => "html_tag",
    '#tag' => "div",
    '#attributes' => ['class' => ['context-menu']],
    '#value' => "Dashboard",
  ];

  $sample['#attached']['library'][] = 'mylibrary/dashboard-js';
  $merge = TRUE;
  $settings['dashboard']['myVariables'] = $modalSettings;
  $response = new AjaxResponse();
  $response
    ->addCommand(new ReplaceCommand('.context-menu', $sample))
    ->addCommand(new SettingsCommand($settings, $merge));
  return $response;
}


Views pager not rendered for teasers with comments I have a views which displays teasers. Pager is also set.

When comments in teasers is enabled pager doesn't show up, however it does when comments are turned off.

I cannot figure out what the issue might be, please anybody any clue to this?

Thanks.

Have you tried to give your pager another "Pager ID" (in the pager options on the view). Try to enter a number bigger than 0.


jQuery Uncaught TypeError: Object # has no method 'on' I downloaded a jQuery Lightbox2 library (not module, just a raw library) and added the following in my custom module:

drupal_add_js($libpath . '/js/jquery-ui-1.8.18.custom.min.js');
drupal_add_js($libpath . '/js/jquery.smooth-scroll.min.js');
drupal_add_js($libpath . '/js/lightbox.js');

But it causes an error like this (see below debug printscreen):

Could someone tell me, what to do to get rid of the error?

After some googling I installed the JQuery Dollar module but the error is still there.  No clue what else to do.

on() was only added in jQuery v1.7; Drupal 7 ships with jQuery v1.4, and can be updated to 1.5 using the jQuery Update module. The reason you're getting the error is simply that the lightbox library you're using is written for jQuery v1.7 and above.

See How do I update jQuery to the latest version I can download? for some ideas on how to get round this.


How to let Drupal use two databases I want to use an admin specific page to insert or remove new users, instead of using the Drupal administration panel.

How can I prescind from the Drupal default database and insert the users' information in my personal database? Is it possible?

In drupal 7 you can easily connect to 2 or more different databases.
From your question I guess you have a module to handle the users rather than the normal Drupal Way. So you can follow the following,

$databases = array (
  'default' =>  // main drupal db starts from here
  array (
    'default' =>
    array (
      'database' => 'drupaldb', // main drupal db name
      'username' => 'root', // main drupal db username
      'password' => 'password', // main drupal db password
      'host' => 'localhost',
      'port' => '',
      'driver' => 'mysql',
      'prefix' => '',
    ),
  ),'yourcustomdb' =>  // additional database starts here
  array (
    'default' =>
    array (
      'database' => 'database', // additional database name
      'username' => 'root', // additional database username
      'password' => 'password', // additional database password
      'host' => 'localhost',
      'port' => '',
      'driver' => 'mysql',
      'prefix' => '',
    )
  ),
);

Then in time of calling it,

db_set_active('yourcustomdb');
$query = db_query('....');
db_set_active('default'); // We need to call the main (drupal) db back

I hope this one helps you.


How to resolve the problems encountered when moving from local to server? Which things do we need to be aware of and change when moving a site (in Drupal 8) from a local environment to a server?
In Drupal 7 I would just copy the files, change the database settings in settings.php, and import database, clear all caches, and that's it.
2 problems come up with the 'move files, move database' method, which are:

All links on the server-side site use the local url. Where does it get that information?

When I navigate to /user/login I get this error on a white page:

Redirects to external URLs are not allowed by default, use \Drupal\Core\Routing\TrustedRedirectResponse for it.

I'm assuming you're moving the files and database, as you state in your question:

Moving a site from MAMP should be pretty easy.  One thing you may be missing is updating $settings['trusted_host_patterns'] in your settings.php or settings.local.php

$settings['trusted_host_patterns'] = array(
   '^mysite\.com',
   '^.+\.mysite\.com',
   '^mysite\.local',
   '^.+\.mysite\.local',
 );

Another thing you may have forgotten to do is to clear the cache once you move the files and database.

Usually I use the drush command line utility and then from the docroot of the site, or the /sites/default directly run "drush cr".


Dynamic query returns multiple data I have a quite simple query :
(find all nodes, fetch 3 fields from the node table and join the results with some tax.terms)

$query = db_select ( 'node', 'n' );
  $query->fields ( 'n', array(
      'nid',
      'title',
      'type' ));
  $query->fields('b',array('body_value'));
  $query->fields('ttd',array('name'));

  $query->leftJoin ( 'field_data_body', 'b', 'b.entity_id = n.nid');
  $query->leftjoin ( 'taxonomy_index', 'ti', 'ti.nid = n.nid');
  $query->leftjoin ( 'taxonomy_term_data', 'ttd', 'ttd.tid = ti.tid AND ttd.vid = "5"');

  /* $query->condition('ttd',5); */

  $result = $query->execute ()->fetchAll ();

Now the problem is that i want a single object returned form the query for each node.
Like this :

stdClass Object
(
    [nid] => 557
    [title] => Lorem ipsum
    [type] => content_type
    [body_value] => lorem ispum
    [name] => taxonomy_term_value
)

But what i get is multiple objects because of the taxonomy index table (where a node can have anywhere from 12 term id's to none at all) but i only need 1 that corresponds to the condition stated above in the query (vid = 5, from the tax.term data table) if that node has a link to the tax.term, if the node does not have link it should return nothing,null,empty string...

So my results are as follows :

stdClass Object
(
    [nid] => 155
    [title] => lorem ipsum
    [type] => content_type
    [body_value] => lorem ispum
    [name] =>
)
stdClass Object
(
    [nid] => 3411
    [title] => lorem ipsum
    [type] => content_type
    [body_value] => lorem ispum
    [name] => value1
)
stdClass Object
(
    [nid] => 161
    [title] => lorem ipsum
    [type] => content_type
    [body_value] => lorem ispum
    [name] => value4
)
stdClass Object
(
    [nid] => 561
    [title] => lorem ipsum
    [type] => content_type
    [body_value] => lorem ispum
    [name] => value16
)

What you get currently is what you asked for: leftJoin.

To get only the single object you're looking for, you must use join instead (which is default and equivalent to innerJoin).

BTW you may simplify your code using the short notation, like this:

$query = db_select('node', 'n')
  ->fields('n', array('nid', 'title', 'type' ))
  ->fields('b', array('body_value'))
  ->fields('ttd',array('name'))
  ->join('field_data_body', 'b', 'b.entity_id = n.nid')
  ->join('taxonomy_index', 'ti', 'ti.nid = n.nid')
  ->join('taxonomy_term_data', 'ttd', 'ttd.tid = ti.tid AND ttd.vid = "5"');


Is EntityFieldQuery as sophisticated as the Database API? I was wondering if EntityFieldQuery is just a layer of abstraction on top of the database query builder. For example can I use addExpression and isNotNull in an EntityFieldQuery, for example?

Or, is it separate and not as sophisticated.

I was wondering if EntityFieldQuery is just a layer of abstraction on top of the database query builder.

Yes, that's exactly what it is. It's not subclass of SelectQuery or anything higher up the chain, though.

  For example can I use addExpression and isNotNull in an EntityFieldQuery, for example?

No, EFQ doesn't implement those methods. You can see what methods are available by looking at the source.

  Or, is it separate and not as sophisticated.

Yes it's separate, "not as sophisticated" can't really apply since the functional differences between EFQ and a SelectQuery are intentional. They're not supposed to do the same thing, an EFQ is intentionally limited to functionality that makes sense for entities only.

However, an EFQ will eventually run a SelectQuery anyway, which you can alter just like any other query. So you can make it as "sophisticated" as you need to.


Content Profile fields in rules I am using rules and want to access a field in a users content profile. how can I do this?

In Rules, there is a simple action that will allow you access to a user's content profile information.  In your rule, select "Add an action" and choose Load Content Profile:

On the next page, first choose which user to load (ex. logged in user, acting user, content author, etc). This depends on what Event you chose for the rule. Next choose which profile content type you want to load and click "Save".

Now, other actions you add after the first step (loading the content profile) will have access to the fields of the user's content profile. If you have the Token module installed, settings for new actions should have a fieldset titled Token replacement patterns. Expand that fieldset and you should see another fieldset titled Replacement patterns for Content Profile.  Expand that one to see all content profile tokens that can be used however you like.  Ex:


Drupal 7 node form processing cleaner Below is an example of adding an additional submit handler to a node form. I don't like how in the submit handler I have a giant nested structure just to check if a file was uploaded...Is there a better way?

<?php
function rocdocs_polygons_form_polygons_node_form_alter(&$form, &$form_state, $form_id)
{
    $form['#submit'][] = 'rocdocs_polygons_form_polygons_node_form_submit';
}

function rocdocs_polygons_form_polygons_node_form_submit($form, &$form_state)
{
    if ($form_state['values']['field_shapes_file']['und'][0]['fid'])
    {

    }
}

If you want to inspect the values of a submitted form, I'm afraid you'll have to dig in to a nested array.

However, if you need to check if a file has been uploaded, why don't you make it a required field? And if you have a reason to write your own check, why don't you add a validation function instead of a submit handler?


Serving Drupal from within a sub-directory of my web root I need my Drupal 8 website to be served from within a subdirectory of my NGINX_SERVER_ROOT but is doesn't work.

Drupal should be reached at mydomain.com/drupal.

My NGINX_SERVER_ROOT is /var/www/html/web.

When the source code is in /var/www/html/web it works fine. But when moved to /var/www/html/web/drupal and I try to reach mydomain.com/drupal, it doesn't work.

I have edited the .htaccess file within the drupal subfolder and set RewriteBase /drupal as explained in the file itself.

Here is the log when I try to access my Drupal installation.

nginx_1    | 2018/10/09 12:58:38 [error] 42#42: *5 FastCGI sent in stderr: "Primary script unknown" while reading response header from upstream, client: 192.168.160.4, server: default, request: "GET /drupal HTTP/1.1", upstream: "fastcgi://192.168.160.5:9000", host: "d8site.local:8000"
nginx_1    | 192.168.160.4 - - [09/Oct/2018:12:58:38 +0000] "GET /drupal HTTP/1.1" 404 47 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"
nginx_1    | 192.168.160.4 - - [09/Oct/2018:12:58:38 +0000] "GET /favicon.ico HTTP/1.1" 200 43 "http://d8site.local:8000/drupal" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36"

Could someone point me in the right direction?

You have to edit the nginx virtual host file of your website.
You'll usually find it at /etc/nginx/sites-available/yoursitename.vhost.

Open it with write permissions, and edit root directive at the top of server block as following:

server {
    listen x.x.x.x:yyyy; #IP:port
    server_name www.example.com;
    root /var/www/html/web/drupal;

Save the file and reload nginx conf : sudo systemctl reload nginx.service


How to redirect by adding something after pathauto url? I am trying to do a simple thing.
Whenever an anonymous user views a content , I want to redirect the user to

node's-url/#overlay=signup

So, how do I modify the URL to use #overlay=signup at the end for anon users?

I tried to do so by implementing rules.
Event: Content is viewed
Condition: User role is anonymous
Action: Redirect url.

I don't know how to add the pathauto-url/#overlay=signup.

What's what Splash module does. See Thickbox option. More about the module:

  Display any internal path, external URL or text as a splash page before going to the actual frontpage.


Can I pass an argument as ?xxx=arg In Drupal 7, on the home page /home, I have a list of News items in the left column, and want to click on one of the News items in the list, and have the full article for that item show in the right column of the page.

Is there a way to pass an argument that doesn't change the page, like /home?xxx=arg   Everything I read talks about passing arguments in ways that change the page path (i.e., home/news1, or home/news2).

As long as you have something (a custom module, for example) looking for the arguments, yes, you can pass as many arguments as you want.

Depending on the size of the articles, however, instead of requiring a page refresh, I would suggest either an AJAX call (more complicated) or using jQuery (less complicated) to hide the content, and simply show it on demand. If the articles are large though, the jQuery option would be cumbersome and slow the page, since it would load all of the material at page load.


How to alter local tasks menu titles? How can I override link title in the local tasks menu?

I tried like this, but didn't work:

function mymodule_menu_local_tasks_alter(&$data, $route_name) {
  // Override 'Revisions' label menu link
  $data['tabs'][0]['entity.node.version_history']['#link']['localized_options']['attributes']['title'] = t('View history');
}

I have had success with

$data['tabs'][0]['entity.node.canonical']['#link']['title'] = t('Overview');


How to add fields to a form from a custom module I'm working on a custom module that will allow payments through a particular bank API.

The API requires me to do a POST to a certain URL that they have provided me, where the user will enter his credit card information.
To do so, I created a form with the #action set toward the provided URL, and with the mandatory fields asked by the bank (name, address, phone, etc.)

Unfortunatly, the form is in the module, and I don't think that is good practice, since it gets more complicated for a user to add his own custom field (lets say a date of birth for example).

Is there anyway that my module can get a form created by the form API in another module ("my_custom_cart") and add to it the mandatory fields needed for the transaction?

Thank you

I think using the form #action is the wrong approach there.

You should instead use

drupal_http_request

  Performs an HTTP request.

  This is a flexible and powerful HTTP client implementation. Correctly
  handles GET, POST, PUT or any other HTTP requests. Handles redirects.

In your form submit handler, to pass on the required parameters to the payment gateway.

Ensure everything is done under HTTPS.

To get another form, you can simply use

$form = array(); // new form
$defaults = drupal_get_form('my_default_form_builder_function');
$form += $defaults; // add defaults to new form


How to create a block view containing data from another Drupal site? I'm new to Drupal. I'm working on existing Drupal Website. This is a multi-site with single Drupal Setup.

There is a side-bar on the website that contains a view for News of website. I want to create another view like "News" and put it to below the "News" view inside the same block.

The new view will contain events instead of news and those events will come other websites (other websites is the sites from multi-sites, I have total 3 websites in multi-site setup).

Please help me to do this. Please let me know if I need to share more details.

I am assuming that the view that is already in use is of type block.

You can clone the Block using the views admin UI.

1)Go to Structure -> Views

2)Click on the Edit link corresponding to your view

3)Click on the block you are interested in copying and select the option "Clone Block" from the dropdown.

4)A copy of the block gets created. Update the title of the new block , make the necessary changes to the filters etc and save.

oops!Missed out the important piece "

  The view should display the events which are currently available in a
  different site

"

From what I understand the multi-site setup is achieved using the Domain Access module. So the drupal instance and the DB are common for all the sites.

In your case you need to make the events content available in the domain where you are creating the view. To do this
1) Go to Structure -> Content Types

2) Click on the edit link corresponding to the Events content type

3) Click on "Domain Access Settings" at the bottom

4) Select the Domain where the events view is going to be added and save.

5) This domain access setting gets applied to all the new events which get added after the change.

6) The existing events might have to be manually updated to make them accessible in the different domain. Go to the edit page of each specific event and update the Domain Access options accordingly.


Drupal #attached doesn't work with some themes I've written a module which loads CSS and JS files using the #attached property.  This works fine across most themes, but for some themes the files are not loading.

e.g.:

$page['header']['#attached']['css'][] = array(
  'data' => drupal_get_path('module', 'mymodule') . '/css/mymodule_default.css',
  'type' => 'file',
  'options' => array(
    'group' => CSS_THEME,
    'preprocess' => TRUE,
    'every_page' => TRUE,
  ),
);

As there is very little by way of explanation on #attached (most articles repeat the same stuff) I can't figure out where the problem may lie.  Using drupal_add_css() and drupal_add_js() works, but is not recommended for caching reasons, and I prefer to pass settings using attached for this reason.

The #attached properties are showing in the $page array but are not being rendered.

In summary, are there situations when certain themes block the correct rendering of #attached elements that would normally be applied to a render structure by drupal_process_attached()

Any help is appreciated.

The example code you are giving indicates, that you want to have this CSS included on every page. In this case do not bother using #attached at all and just call drupal_add_css from hook_page_build. An even better option is to include the CSS in the module-info file with the following line:

stylesheets[all][] = css/mymodule_default.css

In contrast if the asset is to be added to the page only when a given element is rendered (e.g. a form), then use #attached on that element. This way the path to the asset gets stored along with the render-array if the element is cacheable. On subsequent page requests, the element will be retrieved from the cache and the asset is attached to the page. If you would use drupal_add_css together with cacheable elements, the asset would be missing on subsequent page builds.

Note that even when using #attached, drupal_add_css is called internally from within drupal_process_attached. The responsible code, but actually boils down to this excerpt:

// Add both the JavaScript and the CSS.
// The parameters for drupal_add_js() and drupal_add_css() require special
// handling.
foreach (array('js', 'css') as $type) {
  foreach ($elements['#attached'][$type] as $data => $options) {
    // [...]
    call_user_func('drupal_add_' . $type, $data, $options);
  }
  unset($elements['#attached'][$type]);
}

The call_user_func will invoke either drupal_add_js and drupal_add_css respectively, depending the value of $type. It follows that there is no additional benefit from using #attached unless the asset is used by a render-array which is to be stored in the cache. Assets specified via #attached are guaranteed to be loaded if the associated render-array is rendered. They will not be added to the page when the associated render-array is not rendered.

In your specific situation you are attaching the CSS not to an element but to a page region. However the header-region apparently is not rendered by every theme, probably because it is not widely used. The header-region is rendered in page.tpl.php. If a theme chooses to ignore a region, like the Versatile and the Corporate Clean do, the CSS will not be attached.

To sum up:

Use #attached when adding assets to cacheable render-arrays (especially forms and form elements)
Add stylesheets / scripts to the module-info file or call drupal_add_js and drupal_add_css whenever adding assets globally.


Finding the Machine Name of an Module-based Field Added to $content variable I need to edit a field added to my $content variable by a contrib module called Print, email, and PDF versions. It creates a link at the top of the content region that says 'Print PDF' and prints a PDF of the page. I've looked everywhere in the admin settings for the module for this information but can't find it anywhere.

Note: I've tried looking in my DB and trying what I found in there for the field, with no luck. I also tried using var_dump but that doesn't help me. I looked in the print.module file but wasn't seeing anything in there, although to be fair it's quite voluminous so I might have missed something.

I'm trying to access it and hide it through code in node--resource.tpl.php so I can manipulate it independently of the rest of the vars in $content. This is the code I'm using successfully to hide OTHER items in $content for example:

// #nomarkup is a function defined in template.php
$content['field_body']['#theme'] = "nomarkup";
hide($content['field_body']);

With Firebug, the DOM shows  followed by  for the PRINT PDF link I want to hide, but neither of those seems to be recognized when I try to hide them using a similar format as the other items in $content, like so:

$content['print-link']['#theme']

or

$content['print_pdf']['#theme']

respectively. I even tried removing the ['#theme'] part but that didn't help.

Anyone know a good way to find the machine name of this variable that seems to have been added to $content but is not showing in admin > content type?

Install the devel module and use dpm($content) to inspect the content variable.

A good place to adjust the contents of a page in your theme is in a preprocess function.


db_set_active() and node_save() not working as expected I'm writing a module to use on a multisite setup that enables nodes to be published to another site on the same installation.

Suppose I have Site A and Site B. I want this module to provide the ability to save a given node from Site A to Site B. Naturally, the way I have the database info set up in settings.php for Site A is as follows:

$databases['default']['default'] = array (
    'database'  => $db_name,
    'username'  => $db_user,
    'password'  => $db_pass,
    'host'      => 'localhost',
    'port'      => '',
    'driver'    => 'mysql',
    'prefix'    => $db_tables,
);

$databases['site_b']['default'] = array (
    'database'  => 'site_b',
    'username'  => $db_user,
    'password'  => $db_pass,
    'host'      => 'localhost',
    'port'      => '',
    'driver'    => 'mysql',
    'prefix'    => '',
);

...thus giving Site A the info it needs to access Site B's database.

When I execute the following code in the module via the hook_node_insert and hook_node_update hooks:

// Switch to Site B database
db_set_active('site_b');

// Save the node on Site B
node_save($node);

...it attempts to save the node on the current database instead, resulting in an SQL error (duplicate node ID). (Also, as a side note, I'm utilising a boolean property on the $node object to prevent the hooks and node_save() from throwing each other into an endless loop.)

I tried using drupal_get_schema(NULL, TRUE); directly after db_set_active('site_b'), but that made no difference. I've also cleared the cache in between every code change and test. No luck.

I don't know what's preventing it from working... maybe my $databases array is structured incorrectly?

Here is some help:

The general format for the $databases array is as follows:
 * @code
 * $databases['default']['default'] = $info_array;
 * $databases['default']['slave'][] = $info_array;
 * $databases['default']['slave'][] = $info_array;
 * $databases['extra']['default'] = $info_array;
 * @endcode
 *
 * In the above example, $info_array is an array of settings described above.
 * The first line sets a "default" database that has one master database
 * (the second level default).  The second and third lines create an array
 * of potential slave databases.  Drupal will select one at random for a given
 * request as needed.  The fourth line creates a new database with a name of
 * "extra".

Are you sure Drupal can connect to the second database? Check your login credential, put some dummy table and do a db_query to verify they exist only in the second one.


ajax form link how to call form function with parameters Is there a good way to use ajax link in form, to call ajax callback function?

I have form elements and i would like to add link, that would call form creation function with some paramaters, so i can change the form accordingly.

The same as form select, which on change submit's form and sends values ...

thanks guys!

There is no '#type' => 'link' form element, and markup does not have #ajax property. So you are down to buttons and images. You can style them to look like a links. Problem is, button will trigger form validation no matter you want it or no.


Create a simple module to retrieve record from database? I need to create a simple module to fetch some record from database related to a node.

I have product nodes and users who makes bids in this product. Then at the time I load a product I need to retrieve all bids in this product to show them in a block.

I need some start guide/documentation to do it.

This is my first module attempt and this is the code I start working with: no error yet but it doesn't print out the values I need.

function myModule_load($node){

$result = db_query("SELECT * FROM {uc_auction_bids} WHERE nid = :nid", array(':nid' => 258,));
$record = $result->fetch();

// print the fields/values of $record
print('<pre>');
print_r($record);
print('</pre>');

}

Any help for creating this simple module, please?

I just need to know which is the right function/hook where I can fetch the data from the database, and prepare the data to create the block.

The Creating modules tutorial covers block creation: implementation of hook_block_info() to declare your block, implementation of hook_block_view() to generate the block content, usage of theme() to format retrieved records and usage of user_access() to check user permission before giving him/her access to the information

The only missing information is the menu_get_object() function which you can use to retrieve the currently displayed node (if any).

function myModule_block_view($delta) {
  if (($node = menu_get_object()) && ($node->type === 'product')) {
    $results = db_query("SELECT * FROM {uc_auction_bids} WHERE nid = :nid", array(':nid' => $node->nid));
    $records = $results->fetchAllAssoc('bid');

    $content = ... // Format records here...

    return array(
      'subject' => t('Bids'),
      'content' => $content
    );
  }
}

A more complex solution, but a flexier one, would be to expose the uc_auction_bids table to views using a hook_views_data() implementation. You could then create a block display using a contextual filter to retrieve the current node ID.


Problem with .gitignore I installed Drupal on ubuntu 16.04 via composer and I'm trying to implement continuous integration with Jenkins. So, I would like to be able to work from another location (for example from a Windows 10 PC), and a push of my changes must trigger a build on jenkins that updates the installation on the ubuntu machine.

I verified that the created .gitignore file is this:

# Ignore directories generated by Composer
/drush/contrib/
/vendor/
/web/core/
/web/modules/contrib/
/web/themes/contrib/
/web/profiles/contrib/
/web/libraries/

# Ignore sensitive information
/web/sites/*/settings.php
/web/sites/*/settings.local.php

# Ignore Drupal's file directory
/web/sites/*/files/

# Ignore SimpleTest multi-site environment.
/web/sites/simpletest

# Ignore files generated by PhpStorm
/.idea/

# Ignore .env files as they are personal
/.env

So after having pushed the code into my git repository, I noticed that various folders are missing such as the "core" folder and I do not think that the project can work if the "core" folder is missing.

Do I simply have to update the .gitignore file? Or is there anything I need to understand better about the "modus operandi" in Drupal?

Your core directory is included in your .gitignore. I don't know which strategy you want follow but, like you have vendor, modules/contrib, themes/contrib, etc, you should launch composer install to download your core and contrib modules/themes in your workflow to complete your installation (your composer.lock should be commit).

If you prefer commit your modules, themes, profiles, libraries, core, etc., because some parts of your content are not managed by composer or because you don't want risk a bug of network during the build, you should remove these directories from your .gitignore and add them in your git repository.


How to make a OG private? I want to make an Organic group private,to be seen only from members of this group.
All the other will get an "Access denied" or something like that.
For the time being,I can see the Group but not its content.
I would also want NOT to be able to see the existance of the group,if I am not a member of it.
I am working on Drupal 7.
How to do that?
Thanks

You need to enable og access control module.

see below:

Then navigate to admin/config/group/fields, add an visibility field to your og bundle

Then edit the og bundle content type, there is a new field added to it, make your change for public or private


How can I flag (follow) user by REST API using service resources? I am using flag module to have the following user function. So that the followers will be able to read the blog of the users that they followed.
Now I want to provide api for mobile application, when a userA go to profile of userB, they can follow userB by follow button. Is there any way to return an api by POST method in RESTfull to do like that?

Try the following

Flag

URL: http://example.com/apiauthd/flag/flag

Method: POST

Parameters:-
    flag_name: like
    action: flag
    uid: { uid of the logged in user}
    entity_id: { uid of the other user to be flagged}

Unflag

URL: http://example.com/apiauthd/flag/flag

Method: POST

Parameters:-
    flag_name: like
    action: unflag
    uid: { uid of the logged in user}
    entity_id: { uid of the other user to be unflagged}


How can i maintain pagination with filter using tableselect? I am creating listing of content using tableselect form type like as follow.

function partners_list($form,&$form_state){
        $header = array(
            'name'=>array('data' => t('Name'),'field' => 'ept.name'),
            'location'=>array('data' => t('Location'),'field' => 'ept.location'),
        );

        $form['search_ew_partner'] = array(
            '#type' => 'textfield',
            '#prefix' => '

',
            '#suffix' => '
',
            '#default_value'=> $form_state['values']['search_ew_partner'],
            '#attributes' => array(
                'placeholder' => 'Search by name'
            )
        );

        $form['submit'] = array(
            '#type' => 'submit',
            '#value' => t('Search'),

            '#prefix' => '
',
            '#suffix' => 'Reset

',

            '#attributes' => array(
                'class' => array('btn blueBtn')
            )
        );

        if(empty($form_state['input'])){
            $results = partners_list_submit($form,$form_state);
            $results=$results['filter_result'];
        }else{
            $results=$form_state['filter_result'];
        }

        $options = array();
        if(!empty($results)){
            foreach($results as $result){
                $options[$result->id] = array(
                    'name' => array('data' => array('#type' => 'link', '#title' => $result->name, '#href' => "partner/details/".$result->id)),
                    'location' => ucfirst($result->location),
                );
            }
        }

        $form['ew_partners'] = array(
            '#type' => 'tableselect',
            '#header' => $header,
            '#options' => $options,
            '#empty' => t('No partners.'),
            '#attributes' => array(
                'class' => array('table')
            )
        );

        $form['pager'] = array('#markup' => theme('pager'));
        return $form;
    }

    function partners_list_submit(&$form,&$form_state){
        $form_state['rebuild'] = true;
        $header = array(
            'name'=>array('data' => t('Name'),'field' => 'ept.name'),
            'location'=>array('data' => t('Location'),'field' => 'ept.location'),
        );

        $query = db_select('ew_partners', 'ept');
        if(!empty($form_state['values']['search_ew_partner'])){
            $query->condition('ept.name', '%' . $form_state['values']['search_ew_partner'] . '%', 'LIKE');
        }

        $query = $query->extend('PagerDefault')->extend('TableSort');
        $query->fields('ept',array('id','name','location'));
        $query->limit(2)
            ->orderByHeader($header);

        $results = $query->execute();
        $form_state['filter_result']=$results;
        $form_state['no_cache'] = true;
        return $form_state;
    }

Listing and pagination coming properly when there is no filtration on table. After filtration, pagination is not working.
I think due to form_state values are reset when I clicked on next page.
The page count and the result for first page is coming properly.

How can i maintain pagination with filter using tableselect?

Thank you in advance
Any help appreciated.

The search form method type is post thats why when you are submitting the search form the form values are sending as post therefore the form values are coming properly for  first page. When your are clicking on second page the form state values are reseting with new form state values as form has default value.

So rather than using post method form I will suggest to use get method type form for search so that the search keyword will always persist in url.

So you have to add

$form['#method'] = 'get';

Access all filtered values using $_GET like

$form['search_ew_partner'] = array(
            '#type' => 'textfield',
            '#prefix' => '

',
            '#suffix' => '
',
            '#default_value'=> $_GET['search_ew_partner'],
            '#attributes' => array(
                'placeholder' => 'Search by name'
            )
        );

And change your code like

if(!empty($_GET['search_ew_partner'])){
            $query->condition('ept.name', '%' . $_GET['search_ew_partner'] . '%', 'LIKE');
        }


Duplicate value fields when creating relationships field collection of views I have a problem need help. I created one field collection (unlimited value) for content type. Then I create 1 views to ren value fields in tables. I created relationship field collection for the that views and have a problem that the fields of the node duplicate value by the number of the field collection values. How can I remove duplicate of the field value in that content type.

on right hand others >> query settings of you view there is one distinct checkbox enable it. Which will distinct your result


Change the index structure of fields in a table in database? Wise thing to do? I'm on Drupal 7. The table index structure of users table is shown in the fig below:

As pointed out the table has two unique keys uid(also primary) and name which is the username of the user of the site. The username is displayed on the top of the user's profile.

I want the mail column to be unique, and make it non-nullable.
and remove the unique characteristics of name;

Because username can be same (my use case) and e-mail id shouldn't repeat.
Is it safe to make the change? If not what precautions do I need to take?

If you are even thinking about doing this I have two big key phrases

BACKUPS
DEV SERVER

Here is what you should do

Install MySQL on a DevServer
mysqldump the database and load it on the DevServer
Point your Drupal App at the DevServer and bang on it, and kick the tires

Once you got a good dev environment, now do this on the DevServer

SELECT mail,COUNT(1) MailCount FROM users
GROUP BY mail HAVING COUNT(1) > 1;

If you get any rows coming back, there are multiple users using the same mail value

If nothing comes back, you can proceed as follows:

CREATE TABLE users_new LIKE users;
ALTER TABLE users_new DROP INDEX `name`;
ALTER TABLE users_new DROP INDEX `mail`;
ALTER TABLE users_new ADD INDEX `name`;
ALTER TABLE users_new ADD UNIQUE INDEX `mail`;
INSERT INTO users_new SELECT * FROM users;
SELECT COUNT(1) UsersCount FROM users;
SELECT COUNT(1) UsersNewCount FROM users_new;

If UsersCount = UsersNewCount, CONGRATULATIONS, you can continue.

ALTER TABLE users RENAME users_old;
ALTER TABLE users_new RENAME users;

You drop users_old if you are sure you no longer need.

Give it a Try !!!


Add the Form name to the theme suggestions input field How do I get the form name to the theme a suggestion input in Drupal 8?

function [THEME_NAME]_theme_suggestions_input_alter(array &$suggestions, array $variables) {
  if (isset($variables['element']['#parents'])) {
    $suggestions[] = 'input__'.$variables['element']['#parents'][0] ;
  }
}

In your yourTheme.theme, you could do:

function yourTheme_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {

  foreach (\Drupal\Core\Render\Element::children($form) as $key) {
    $form[$key]['#attributes']['data-twig-suggestion'] = $form['#id'];
  }

  $form['actions']['submit']['#attributes']['data-twig-suggestion'] = $form['#id'];
}

The function \Drupal\Core\Render\Element::children($form) returns an array of all the children elements (for a form) for which the keys don't start with #.

So, this array will have the field names as its elements. Then, you iterate over the array and add the attribute data-twig-suggestion and its corresponding value. Note that the array will have some extra elements that aren't form fields, and those would also get the new attribute and its value. I don't think there is any collateral damage on that.

For the submit button ($form['actions']['submit']) we are adding the attribute "manually", as the field element (submit) is "nested" inside the actions array, so our previous loop won't have added the attribute to the correct element in the array.

Then, you also add this function:

function yourTheme_theme_suggestions_input_alter(&$suggestions, array $variables) {
  $element = $variables['element'];
  if (isset($element['#attributes']['data-twig-suggestion'])) {
    $suggestion_suffix = str_replace(['-'], '_', $element['#attributes']['data-twig-suggestion']);
    $suggestions[] = 'input__' . $element['#type'] . '__' . $suggestion_suffix;
  }
}

Here, each form input field is processed and a template suggestion is added based on the previously created attribute.

PS: this solution is based on this article: Getting granular with Drupal 8 forms.


Using computed field to format phone numbers? I am trying to create a computer field that automatically formats phone numbers like so: xxx.xxx.xxxx

The numbers come from user input, and they will be displayed on each user page (I've added fields to Drupal's user profiles so that they include contact info)

How do I do that? Never used computed fields before, but I believe it's the solution to what I'm trying to do....

Try Masked Input module. It allows you to create a text field with mask that you can setup custom (e.g. 999.999.9999). When user enters info into the field with masked input, the information entered is formatted automatically and stored into database with that exact format. So the output of formatted information becomes that much easier.

One drawback of this module is that it provides formatting only if user has JS enabled in the browser. If JS is disabled, you will rely on user to enter info in the desirable format. You can also ask the user to provide info in specific format by entering field description as a fallback (e.g. "Enter your phone number as follows - xxx.xxx.xxxx).
I've used this module on websites with big user base, and I can tell that users very rarely have JS disabled when they fill up forms.


hook_user_delete not being called I'm trying to invoke hook_user_delete and for some reason it isn't getting called. I have essentially the same function in hook_user_cancel and that gets called correctly. Basically, I go into the user edit form, then down to the bottom to "Cancel Account". From the next page, if I click "Disable the account and keep its content.", the hook_user_cancel function gets called, but if I pick "Delete the account and its content.", neither the hook_user_cancel or the hook_user_delete functions get called. I checked this by placing a dpm at the beginning of each function. My code looks like the following:

function carrier_pigeon_user_delete($account){
$num_deleted = 0;

if(is_numeric($account->uid)) {
  $num_deleted = db_delete('carrier_pigeon_subscription')
      ->condition('uid',account->uid)
      ->execute();
}
dpm($num_deleted);
}

function carrier_pigeon_user_cancel($edit, $account, $method) {
$num_deleted = 0;

if(is_numeric($account->uid)) {
    $num_deleted = db_delete('carrier_pigeon_subscription')
            ->condition('uid', $account->uid)
            ->execute();
}
dpm($num_deleted);
}

Sorry about the formatting. Is there something I'm doing wrong here? My impression is that I need both of these to cover my bases, but I can't seem to get the first one to get called.

I followed below steps and it is working when I cancel account by "delete user and its content"

/**
 * Implements hook_user_delete().
 */
function MYMODULE_user_delete($account) {
  watchdog('MYMODULE', 'hello, user: !username, user id: !uid, has been deleted', array(
    '!username' => $account->name,
    '!uid' => $account->uid
  ));
}

Go to admin/reports/dblog
check if the message displayed there. Mine is showing.


Internal Server Error with Multiple Tags When creating a Drupal view that filters based on multiple tags, I'm getting the following error when I click preview:

  An AJAX HTTP error occurred. HTTP Result Code: 500 Debugging
  information follows. Path:
  /admin/structure/views/view/breakfast_things/preview/page_1/ajax
  StatusText: Internal Server Error ResponseText:

And the following error when I hit save:

  Notice: Undefined property: Drupal\views\ManyToOneHelper::$query in
  Drupal\views\ManyToOneHelper->add_filter() (line 312 of
  core/modules/views/lib/Drupal/views/ManyToOneHelper.php).

Here is a screenshot of my page (this was after I clicked save)

If I keep everything the same but only use one tag, like eggs, then it works perfectly fine. Anyone know what's wrong here? I'm trying to create a view that will show all posts about eggs, spam, and other breakfast items.

SK , When you choose tag field in sort criteria, you will get two options Dropdown and Autocomplete. Choose Dropdown . This should fix your problem.


Creating a ticket system with core only. How to modify fields on full_content view without reloading? I'm trying to create a ticketing system with Drupal 8 core. I know Drupal 8 has quick edit module, but that doesnt seem to be working in D8 core. Below is a very basic ticket I made as it just contains:

ticket subject (title)
ticket body
assigned to
status
priority

When viewing a ticket or node, I want to be able to be able to ajax edit the status, priority, and assigned to fields. These are dropdown options or taxonomy reference fields. Right now one would have to click on "edit" to edit the node itself to make these changes. But how would one edit these on the same page without reloading to a new page?

I was thinking of using views and exposing the edit form for the same node, but that doesnt seem like its doable.

Another approach would be to use a form mode instead of a view mode. Put there the fields you want to make writable and add the read-only information in a form alter hook (or separate view block if you want a UI only solution).

To use the form mode you need a module like Form Mode Control or some custom code,  see this good tutorial https://www.webomelette.com/render-custom-entity-form-modes-programatically-drupal-8.

While quickedit is a single purpose solution for in-place editing of web content, you can now that you have a real form do all kind of tricks to get the behavior you want, for example implement autosave: https://www.urbaninsight.com/2016/08/21/how-implement-ajax-autosave-drupal-8-forms


Change machine name of system block I'm attempting to edit page restrictions on the 'Main Page Content' block, however I'm not able to save any changes to the block because it complains about the machine name having capital letters in it.

The machine name for the block is THEME_content. I'm assuming because the theme name has capital letters in it. However because of this I can't make any changes to it, since it checks the machine name upon saving. There is a text field for the machine name but it does not allow me to edit it.
Is there anyway I can change the machine name? Or make it so that I can save this block despite the name?

1. First of all, The step you are showing, at that step you can easily change the machine-name, See in following image, where I have created the block 'Main Page Content' and it is not allowing me to go ahead, before changing the block machine-name. Hence, you can easily change the machine-name here. Hence there is no problem in editing the machine-name.

Secondly, if system is saying, you can not use capital letter, then simply you can't as system designed in that way.

2. Main Page Content Why you want to give your block name Main Page Content title, Block with same name with machine-name theme_content has already been provided by the default Drupal 8. So, why you wan to create the another block with same title and same kind of machine-name. That block(Main Page Content) is used for displaying the main content which is not supposed to be changed. If you want just create the other custom block and place it in CONTENT region.

3. Once the machine-name is stored in the database, practically you can't change that. please read the accepted answer of this Question How do I change the machine name of a field once it's been created.

4. Till which step you can edit machine-name: After creating the block and before final saving, you can see the edit link in the following image. So at that time you can change the machine-name. And before placing it in the region. Once you places block and it gets enabled, after that you can not change the machine-name.


Popup message showing content from a block I have a block, and I want to display the content of that block into a popup message. This is my code.

function darksite_menu() {
  $items['admin/config/media/darksite'] = array(
    'title' => 'Pop up screen configuration',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('darksite_config_page'),
    'access arguments' => array('adminster pop up dark screen'),
    'type' => MENU_NORMAL_ITEM
  );

  return $items;
}

function darksite_config_page() {
  $form['darksite_status'] = array(
    '#title' => t('Enable pop up screen'),
    '#description' => t('When enabled, a pop up screen will be displayed on the home page.'),
    '#type' => 'checkbox',
    '#default_value' => variable_get('darksite_status', 0)
  );

  return system_settings_form($form);
}

function darksite_block_info() {
  $blocks['popup_dark_screen'] = array(
    'info' => t('Pop up Dark Screen')
  );

  return $blocks;
}

function darksite_block_view($delta = '') {
  switch ($delta) {
    case 'popup_dark_screen':
      $block['subject'] = t('Pop up Dark Screen');
      $block['content'] = get_darksite_popup();
  }

  return $block;
}

function get_darksite_popup() {
  $popup_message_parameters = array(
    'title' => t('Information'),
    'body' => t('You have completed the work'),
    'check_cookie' => TRUE,
  );
  if (variable_get('darksite_status', 0))
   {
  // if the check box is checked.
   popup_message_show_message($popup_message_parameters);
    }
}

The code does not work. I have installed the model of popup message, but it still doesn't work.

You should not be printing popup_message_show_message(); it just includes all the necessary files and show your message. Just remove the print part and try that way.

function popup_message_show_message($popup_message_parameters) {
  drupal_add_js(array(
      'popup_message' => $popup_message_parameters
    ), 'setting');
  drupal_add_js('misc/jquery.cookie.js');
  drupal_add_js(drupal_get_path('module', 'popup_message') . '/js/popup.js');
  $default_style = drupal_get_path('module', 'popup_message') . '/styles/default/' . POPUP_MESSAGE_CSS_NAME;
  $style = variable_get('popup_message_style', $default_style);
  if (!file_exists($style)) {
    $style = $default_style;
  }
  drupal_add_css($style);
}

Also, never use print_r() directly. Either use this:

drupal_set_message('<pre>' . print_r($variable, TRUE) . '</pre>');

Or install Devel module and call the dpm() function this way: dpm($variable). It will use Krumo to display all attributes / elements, which is times better for debugging and will not cause any errors as print_r().


using hook_user() to capture user actions I am trying to create a method to log the actions of users, specifically when they log in and out.  I am using hook_user() method to do this. This is my code.

function mymodule_user($op, &$edit, &$account, $category = NULL) {
     switch ($op) {
        case 'login':
            //log to db
           break;
         case 'logout':
           //log to db
            break;
    }
}

There are two problems with this code, and I can't figure out how to fix them.

When a user password is expired, and they attempt to log in, they are redirected to their profile page to change their password. In this event, $op is never "login" and, as such can never be loaded. Instead, $op = "load" but it is useless to log this as this hook gets called nearly 50 times (storing that much data would be to much). Is there a better way to capture this event?

Second, when a user logs out ($op = 'logout') all the other information about the user is lost: The $account array only has empty values (and I need the user ID). Is there a way to capture the logout event and know the user ID?

hope you are trying for drupal 7, there are hook for login and logout, hook_user_login and hook_user_logout respectively. the user id available for logout hook so you can populate the data you want about user.


How to use Value Objects in Content Entities I have a content entity that contains value objects. How would I go about storing the value objects? What is the best way to do this?

As I see it I have the following options.

Creating a custom TypeData (as described here) to serialize the value objects before persisting.
store the value object properties as map and add computed fields for the getting the hydrated value objects.

I think I understood the motivation behind the entity api.

The entity api is not an orm. It is a dbal. The entity definitions do several things:

define the database schema
define the hydration to a concrete object.
define form handling
routing

What does this do with handling Value Objects?

Storing Value Objects

Let's assume we have the following interface, we want to create an entity for:

<?php
interface Product
{
   public function getId(): int;
   public function setId( int $id );

   public function getTitle(): string;
   public function setTitle( string $title );

   public function getPrice(): Price;
   public function setPrice( Price $price );

}

Which means we got one value object Price, which has a value and a currency.

Store the value objects values as fields

When thinking about storing a value object in a table, you would normally define a table as follows:

+------------------------+-----------+---------------+
|id|title                |priceValue | priceCurrency |
+------------------------+-----------+---------------+
|1 |Hitchhiker           |4200       |USD            |
+------------------------+-----------+---------------+

In drupal you define the schema in the static baseFieldDefinitions method and in the annotation, though that mainly just says which table to use. Please note drupal requires an id and uuid field.

<?php
/**
 * @ContentEntityType(
 *   id = "product",
 *   label = @Translation("Product"),
 *   base_table = "product",
 *   entity_keys = {
 *     "id" = "id",
 *     "uuid" = "uuid",
 *   },
 * )
 */
class Product extends ContentEntityBase implements ContentEntityInterface
{
    ...

    public static function baseFieldDefinitions(EntityTypeInterface $entity_type)
    {

        // Standard field, used as unique if primary index.
        $fields['id'] = BaseFieldDefinition::create('integer')
           ->setLabel(t('ID'))
           ->setDescription(t('The ID of the Product entity.'))
           ->setReadOnly(true);

        // Standard field, unique outside of the scope of the current project.
        $fields['uuid'] = BaseFieldDefinition::create('uuid')
           ->setLabel(t('UUID'))
           ->setDescription(t('The UUID of the Product entity.'))
           ->setReadOnly(true);

        $fields['title'] = BaseFieldDefinition::create('string')
           ->setLabel(t('Title'))
           ->setDescription(t('The title of the Product entity'))
           ->setSettings([
                'default_value' => '',
                'max_length' => 256,
                'text_processing' => 0
            ]);

        // define the necessary fields for our Price object

        $fields['price_value'] = BaseFieldDefinition::create('integer')
           ->setLabel(t('Price Value'))
           ->setDescription(t('How much does the product cost in the currencies smalles unit (e.g.cents)? '));

        $fields['price_currency'] = BaseFieldDefinition::create('string')
           ->setLabel(t('Price Currency'))
           ->setDescription(t('The currency the Price is given in'))
           ->setSettings([
              'default_value'   => 'USD',
              'max_length'      => 3,
              'text_processing' => 0,
           ]);

    }
}

Now that we have defined what the database should look like, let's take care of hydration

<?php
/**
 * @ContentEntityType(
 *   id = "product",
 *   label = @Translation("Product"),
 *   base_table = "product",
 *   entity_keys = {
 *     "id" = "id",
 *     "uuid" = "uuid",
 *   },
 * )
 */
class Product extends ContentEntityBase implements ContentEntityInterface
{

    public function getId()
    {
       return $this->get('id')->get(0)->get('value')->getValue() ;
    }

    public function setId( $id )
    {
       $this->get('id')->setValue($id);
    }

    public function getTitle()
    {
       return $this->get('title')->get(0)->get('value')->getValue() ;
    }

    public function setTitle( $title )
    {
       $this->get('title')->setValue($title);
    }

    public function getPrice()
    {
       return new Price(
            $this->get('price_value')->get(0)->get('value')->getValue(),
            $this->get('price_currency')->get(0)->get('value')->getValue()
        );
    }

    public function setPrice( Price $price )
    {
       $this->get('price_value')->setValue($price->getValue());
       $this->get('price_currency')->setValue($price->getCurrency());
    }

    public static function baseFieldDefinitions(EntityTypeInterface $entity_type)
    {
        ...
    }
}

Storing a list of value objects

Let's say our product comes in different formats (I know no one would actually design it that way, I just can't come up with a better example)

<?php
interface Product
{
   public function getId(): int;
   public function setId( int $id );

   public function getTitle(): string;
   public function setTitle( string $title );

   public function getPrice(): Price;
   public function setPrice( Price $price );

   public function getFormats(): array;
   public function setFormats( Format ..$formatset);

}

For the sake of brevity I will pretend a Format only has one property.

as fields of the product table

If there is a known upper bound to the number of formats I could pretty much design my database as before

+--+---------------------+-----------+---------------+-------------+-------------+
|id|title                |price_value|price_currency |format_title1|format_title2|
+--+---------------------+-----------+---------------+-------------+-------------+
|1 |Hitchhiker           |4200       |USD            |hardcover    |balloon      |
+--+---------------------+-----------+---------------+-------------+-------------+

as a referenced table

It would be nicer to design it as two tables, that way it can easily grow without changing my database

+--+---------------------+-----------+---------------+
|id|title                |price_value|price_currency |
+--+---------------------+-----------+---------------+
|1 |Hitchhiker           |4200       |USD            |
+--+---------------------+-----------+---------------+

+----------+------------+
|product_id|format_title|
+----------+------------+
|1         |hardcover   |
+----------+------------+
|1         |balloon     |
+----------+------------+

And that somehow seems possible, but I didn't dig into that, yet.

serializing

The least nicest, but easiest solution in Drupal is serializing the list of formats

+--+---------------------+-----------+---------------+-----------------------------------+
|id|title                |price_value|price_currency |format_set_serialized              |
+--+---------------------+-----------+---------------+-----------------------------------+
|1 |Hitchhiker           |4200       |USD            | #!gobblediegook%&                 |
+--+---------------------+-----------+---------------+-----------------------------------+

The hydration would then look like the following

<?php
class Product extends ContentEntityBase implements ContentEntityInterface
{

    ...

    public function getFormats()
    {
        return unserialize(
            $this->get('format_set_serialized')->get(0)->get('value')->getValue()
        );
    }

    public function setFormats( format ...$formatSet )
    {
       $this->get('format_set_serialized')->setValue(serialize($formatSet));
    }

    ...
}

What about computed fields, custom type data and custom storage handlers?

These exist to put field specific hydration logic in the dbal part of your entity.

The question is "Will someone access the data through the entity api (dbal layer) instead of your fully hydrated domain class?"

If the anyswer is yes, then consider writing a repository service, that is available everywhere. I imagine most use cases revolve around getting domain specific data into drupal's database. So circumventing the domain logic seems like a very bad idea.

If the answer is still yes, then go for it.

I tried following the process described here. It worked but I had to add functions, that were not mentioned and were not part of the interface (specifically postSave and preSave). Also I encountered some very unhelpful errors on the way. After I had a working solution I scraped it for the simpler process outlined above. Your mileage may vary.


How can I have separate databases for each domain (countries) of my Drupal website? I want to have one Drupal website codebase and one apache server instance, but have each country (domain) have it's own database.

Practical example:

I want all content to be completely separated from each other. One country doesn't have access to another countries database.
I want to avoid having to add a new content type 9 times because I have 9 different databases. How can I fix this problem?

It is pretty simple to set up a multi-site with a single codebase. You could have the following directory structure (source):

-- core

-- modules
   -- contrib
   -- custom

-- themes
   -- contrib
   -- custom

-- sites
   -- site1.com
         -- modules
            -- custom
            -- contrib
         -- themes
            -- custom
            -- contrib
         -- files
         -- settings.php
   -- site2.com
         -- modules
            -- custom
            -- contrib
         -- themes
            -- custom
            -- contrib
         -- files
         -- settings.php
   -- site3.com
         -- modules
            -- custom
            -- contrib
         -- themes
            -- custom
            -- contrib
         -- files
         -- settings.php

The directories

--core

-- modules
   -- contrib
   -- custom

-- themes
   -- contrib
   -- custom

will be available to all your sites.

It is the

-- sites

directory that is responsible for the multisite. Take -- site1 as an example:

The modules, themes, and files for the site1 could stay in this directory. What is not mentioned in the documentation is the use the settings.php file. Each site could have its own settings.php file. This is typically a copy of sites/default/default.settings.php. This also means that each site could have its own database. And the entry for the database is made in the $databases array inside their respective settings.php files.

If you want to share config:

The steps that could be followed:

Point the virtual host (domain) for site1.com to the Drupal root, i.e. the directory which has core, modules, themes, etc.
Visit site1.com and install Drupal normally.
Edit the sites/site1.com/settings.php to add the location of the directory where you wish to save the configuration yml files using the variable $config_directories[CONFIG_SYNC_DIRECTORY] = '<RELATIVE_PATH_TO_DIRECTORY>';
Export configuration using Drush - drush cex. This will export complete configuration in the configured sync directory.

For site2.com and more subsites:

Dump the database of site1.com and clone it to a new database to use as a database for site2.com. Cloning the exact same database is important as the configuration management works on cloned sites and not freshly installed ones. This is because the site's UUID needs to be the same.
Have the value of the cloned database in sites/site2.com/settings.php. This means you do not have to install Drupal again. Just using the database of an already installed Drupal site.
Copy the variable $config_directories[CONFIG_SYNC_DIRECTORY] along with its value from sites/site1.com/settings.php to sites/site2.com/settings.php. This will let you use the same configuration for site2.com as well.
Follow steps 1-3 above to create more multi-sites.