Session based content access for anonymous users - Session node access module ported to Drupal 8

Posted by Gbyte blog on January 22, 2017 at 7:41pm
Letting users create content without having to register (or going through any other annoying process) is becoming an important customer engagement strategy. When you allow anonymous users to create content on your website, you want this content to go through a moderation process before it becomes publicly available. To implement this in Drupal, the anonymous user has to be given permission to create content and the content type needs to be unpublished by default. The problem with Drupal 7 and Drupal 8 is that as soon as the anonymous user saves new content, they loose access rights to it and get redirected to an 'Access denied' page which is not very user friendly. In addition to the above, you may want the anonymous user to be able to edit or even delete their own content in case they find an error right after submitting it. Users often find typos or other kinds of mistakes right after content submission.
Categories: Planet Drupal

Caching: static cache and database cache

Posted by fluffy.pro. Drupal Developer's blog on January 21, 2017 at 4:51pm
You have to cache results of heavy functions, sql queries and markup if it's possible because it reduces load on a system in general. If you have a block which renders a lot of items shiped from a database - cache it. If you have a function that performs heavy calculations and this function is called many times during a script execution - cache a result of this function.


Static cache


It's recommended to implement static cache for functions that are called many times during a script execution. It's easy to do: just store a function result first time when function is called and skip heavy calculation next time and return saved value from a static variable.

Database cache


If you want to save a function result for some period of time you have to implement database cache. You can specify a cache lifetime (when it will be expired) or invalidate cache manually when do you need.
Manual cache invalidating:
You can also cache a data of a renderable array by specifying #cache key.

Key notes:

Categories: Planet Drupal

Custom Permissions with Node Access Grants in Drupal 8 and Drupal 7

Posted by Aten Design Group on January 20, 2017 at 8:22pm

For many Drupal web sites setting permissions for anonymous, authenticated, and admin users through the GUI is sufficient. For example, all published content should be visible to all users, authenticated users can leave comments, and admin users are allowed to create content. For more advanced use cases the popular contributed module Content Access (beta for Drupal 7, dev for Drupal 8) allows much finer grained control over read and write access to nodes by content type, and can even specify access differently for individual nodes.

When even more complex permissions are needed many choose to implement hook_node_access(). Permissions management with hook_node_access() does have a few disadvantages:

  • Unwieldy implementations can cause considerable performance bottlenecks
  • Node operation links like View or Edit associated with node permissions aren’t automatically added or removed
  • Views queries are unaffected; content could be displayed to a user in a views block which they would otherwise not have access to

Managing permissions with hook_node_access() works fine in many cases, but it’s not the most flexible way to manage access to your nodes.

Custom permissions with node access grants in Drupal 8

A more robust solution to complex permissions is to use the node access system with hook_node_access_records() and hook_node_grants(). Hook_node_access_records() is called when each node is saved. That’s where grants are setup to view, update, and/or delete a node. Hook_node_grants() is called to determine access and is what is used to check the node_access table.

The good news is node access grants work (almost) exactly the same in Drupal 8 as in 7.

When researching how to implement node grants, I had come across relatively simple examples where access was based on a user’s role or organic groups properties. Since the user object is passed to hook_node_grants(), it’s trivial to determine which user should get access. But, what if access to view or edit a node is based on a combination of factors? This was the situation I recently had to deal with.

The implementation below creates a View grant for accounts that meet a specific criteria. The code for the actual criteria has been omitted. It also creates a full access grant for administrators using a zero as the grant id -- not to be confused with the UID associated with anonymous users.

function MODULENAME_node_access_records(NodeInterface $node) {
// code to get accounts that should have read access is not shown
  foreach ($accounts as $account) {
      $grants[] = array(
        'realm' => 'custom_access',
        'gid' => $account->id(),
        'grant_view' => 1,
        'grant_update' => 0,
        'grant_delete' => 0,
        'langcode' => 'en',
      );
  }
 
  $grants[] = array(
    'realm' => 'custom_access',
    'gid' => 0, // This is the admin GID, not the $account->uid associated with anonymous
    'grant_view' => 1,
    'grant_update' => 1,
    'grant_delete' => 1,
    'langcode' => 'en',
  );
 
  return $grants;
}

Above is part of a hook_node_access_records() implementation. The node_access tables store:

  • Node id: The unique node identifier.
  • Realm: A string that can be whatever you want. This can be useful to group different kinds of access; using the modulename is typical.
  • Grant id: An integer value often used to group access. If for example some users can only read the node, and others can read, update, and delete, you might use 0 and 1 for these two sets of users. In our case there are a small number of users who should have read access and this is determined by code based on multiple factors. For this reason we set a grant for each user using the user id.
  • Grant_view, grant_update, grant_delete: Use 0 for no access, 1 for access.
  • Langcode: Language code.

Below is the hook_node_grants() implementation. This is called each time access to a node needs to be determined; so the simpler the code, the better. If the node_access table has an entry for the node id being accessed, permissions with the matching value for realm and grant id will be granted. First the account is checked for the administrator role, and the grant id 0 is returned if there’s a match. If not, and if the user isn’t anonymous, the function returns a grant with the user’s id. If there’s a match in the table, access will be granted based on the values for read, update, or delete. If this grant doesn’t match an entry in the table, access will be denied. Finally, if the user is anonymous an empty array will be returned, denying access.

function MODULENAME_node_grants(AccountInterface $account, $op) {
  $grants = array();
 
  if (in_array('administrator', $account->getRoles())) {
    // gid to view, update, delete
    $grants['custom_access'][] = 0;
    return $grants;
  }
 
  if ($account->id() != 0) {
    // otherwise return uid, might match entry in table
    $grants['custom_access'][] = $account->id();
  }
 
  return $grants;
}
Implications of custom node access grants

One of the limitations of implementing custom node access grants is the effect on database queries. If the current user does not have access to a particular node it won’t be included in query results. This makes sense for Views since you wouldn’t want to display nodes a user shouldn’t have access to. However, if in code you need to query nodes in the background, the query is limited to those the current user can access. If for some reason a view should ignore access checks, that’s configurable with the "Disable SQL rewriting" option in the Views GUI.

For queries in code, starting in Drupal 7.15 the syntax for disabling access checks while performing a query is below:

$query->addTag('DANGEROUS_ACCESS_CHECK_OPT_OUT')

in Drupal 8 the same thing is accomplished with:

$query->accessCheck(FALSE);

Using node access grants isn’t always necessary to manage your permissions, but it allows for more complexity than many contributed modules and is more efficient than many custom hook_node_access() implementations.

Categories: Planet Drupal

Drupal and PHP: Two Parts of the Whole

Posted by DrupalCon News on January 20, 2017 at 7:36pm

Thanks to the release of Drupal 8, PHP and Drupal are forever more two sides of the same coin. DrupalCon Baltimore will have some specific tracks dedicated to all things Drupal, but we also think it is important to showcase the PHP side as well. After all, good developer practices are good regardless of the chosen outlet. These shared experiences and practices help us discover new tools, abilities, and ways of thinking.

Categories: Planet Drupal

Usar composer en Drupal

Posted by rpayanm on January 20, 2017 at 7:34pm
Los endpoints de composer de Drupal habían estado en beta por un tiempo pero desde hace poco pasan a estado estable. En este artículo mostraremos como usar composer en Drupal.

Novedades de Drupal 8.2.x

Posted by rpayanm on January 20, 2017 at 7:34pm

El 3 de agosto pasado salió la versión de Drupal 8.2.0 beta1, y sentí curiosidad de que traería de nuevo esta versión, aquí les comparto que tendrá:

Nuevas características ya estables

Migrate API in Drupal 8 and a glimpse at the migration process

Posted by InternetDevels on January 20, 2017 at 4:05pm
Migrate API in Drupal 8 and a glimpse at the migration process

Drupal 8 is so irresistible in its innovations that it just makes you wanna… pack your things and migrate! ;) To “pack” your website’s content and configuration carefully and move them to Drupal 8, there exists a cool tool called Migrate API. As with any relocation, it's easier to “pack your things” when they, let's say, fit into “standard boxes”. The same applies to websites: the less custom functionality they have, the quicker the upgrade process will go.

Read more
Categories: Planet Drupal

Drupal 8 Migrate esta en Beta

Posted by drupaleros.es on January 20, 2017 at 10:48am
Drupal 8.0.0 reemplazó el procedimiento anterior de actualización in situ para las actualizaciones de versión principal con una solución basada en migración para los módulos principales y contribuidos. El módulo Migrate de Drupal proporciona soporte API para migraciones de Drupal a Drupal y el módulo Drupal Migrate UI ofrece una interfaz de usuario sencilla para ejecutar migraciones de Drupal más antiguas.   Mucho trabajo se ha hecho para que las migraciones sean más completas desde la versión inicial de 8.0.0, incluso para sitios multilingües con varias configuraciones. Las migraciones de Drupal a Drupal todavía no están completamente completas (... Leer mas

testing institute Training in Bangalore

Posted by Flickr on January 20, 2017 at 7:42am

babubala1 posted a photo:

testing institute Training in Bangalore

We are providing Testing Training in Koramangala,Bangalore,Hubli,Belgaum,Mangalore. Today every software that is developed , needs to be tested for bugs . These bugs are identified by testing experts and developer are supposed to fix this bug .
Software testing program at zenrays.com consist of Manual Testing and Automation Testing , selenium with java . The approach is complete hands-on from day one, which means you will be learning software testing by working on live application . After the training program gets over , you will be working on live industry project , performing automation testing. You get Project experience and hands-on training. Our course is designed for both freshers and working professionals which is industry specific.


If you want more details please visit us:

zenrays.com/testing-courses

Categories: Drupal talk

Web design trends 2017

Posted by ADCI Solutions on January 20, 2017 at 6:02am

Good practices are always worth maintaining. Since design is a rather vulnerable area, not everybody keeps up-to-date about trends popping up here and there. We got inspired by some of the Drupal designs we've seen recently and would love to share the trends we'd learned with you. We will learn what's better take to 2017 from previous years’ trends. You'll be taken through design approaches, Material design and Atomic design in particular. Then we will proceed to a design process, content representation tips and other visual web trends. We also will introduce few trends that don’t cover design only, but do affect the Web and how users interact. For your convenience we give design examples implemented on Drupal websites - real case studies practiсe. Read the whole article here.

Web design trends 2017

Categories: Planet Drupal

Webinar: How to Manage Media Assets in Drupal 8

Posted by Web Wash on January 20, 2017 at 1:00am
Yesterday I presented a webinar on how to manage media assets in Drupal 8. The webinar went for just over an hour and we looked at the current state of media management in Drupal 7 and what's new in Drupal 8. I spent the rest of the time demonstrating how to: Store media assets using Media Entity. Embedding assets using Entity Embed. Displaying a browser page to browse and select assets using Entity Browser.
Categories: Planet Drupal

Drupal SEO with Ben Finklea

Posted by Lullabot on January 19, 2017 at 9:00pm
Mike and Matt sit down with Ben Finklea, and talk all things SEO and Drupal, including his new book "Drupal SEO."
Categories: Planet Drupal

Submit a Front End Session for DrupalCon Baltimore!

Posted by Amazee Labs on January 19, 2017 at 5:14pm
Submit a Front End Session for DrupalCon Baltimore!

This is my fourth year as a member of the North American DrupalCon Program Team. Each year, I'm surprised how quickly the submission deadline rolls around. The conference is in late April, but did you realize the submission deadline is less than two short weeks away?

Kathryn McClintock Thu, 01/19/2017 - 18:14 photo of a flip clock

I imagine if the deadline sneaks up on me—a person looped into the event’s planning—how easy it must be for a community member to miss the deadline altogether. That’s why I hope this blog post reaches many of my fellow Front End Drupalers.

The DrupalCon Baltimore Call for Proposals ends Wednesday, February 1st at 11:59pm (EST). Learn about the Front End track and the types of topics and submissions we’re hoping to receive.

There are many reasons you should consider submitting a Front End session: a complimentary ticket to the conference, an opportunity to reach a broad audience, and most importantly, a chance to share your knowledge and passion with like-minded community members.

This is an exciting time in Drupal’s history—there are many appealing and universal reasons to get involved. If you’ve been learning / researching / doing cool things with Drupal’s Front End, we want you!

So, be sure to submit a Front End session today!

Categories: Planet Drupal

DIY Drupal hosting

Posted by lakshminp.com on January 19, 2017 at 12:42pm

The meta stuff

I'll be writing a series of posts exploring DIY drupal hosting options. Many agencies and freelancers need a workflow to manage and maintain their Drupal sites on a budget. Of course, they incur the cost of maintiaining and deploying the system(at least initially) and the additional learning curve involved in using the system, but they get the following advantages:

  • More control over the hosted sites. It is easy to create and deploy new environments to demo sites to clients, triage bugs, run tests etc.

Categories: Planet Drupal

Entity browser feature freeze will happen in two weeks

Posted by Janez Urevc on January 19, 2017 at 8:56am
Entity browser feature freeze will happen in two weeks

Today I released Entity browser 8.x-1.0-beta4. Release includes some nice features; specially Improved MultiStep selection display, which vastly improves editorial experience.

This is also the last release before the feature freeze, which will happen on February 3rd 2017. No new features will be accepted after that day until 8.x-1.0 is released. Feature requests that are not breaking backward compatibility will be accepted after that.

Huge thanks to all contributors. It has been an interesting and very rewarding ride!

slashrsm Thu, 19.01.2017 - 09:56 Tags Drupal Media Enjoyed this post? There is more! Join us at the next Drupal Media sprint at the Mountain camp in Davos! Results of the Drupal 8 media sprint Call for Drupal 8 media ecosystem co-maintainers
Categories: Planet Drupal

Building Views Query Plugins for Drupal 8, Part 3

Posted by Lullabot on January 19, 2017 at 1:39am

Welcome to the third part of our series on writing Views query plugins. In part 1, we talked about the planning work that should precede coding. In part 2, we covered the basics of actually writing a query plugin. In this final chapter, we will investigate some enhancements to make your plugin more polished and flexible.

Exposing configuration options

Allow Site Admins to set their preferred units: metric or imperial.

Most Fitbit endpoints accept an option to set the units the response is returned in. If you are Canadian like me, you know that metric is preferable, but it’s also in our nature to be be nice, so we should expose a configuration option to allow our American friends to show data in their anachronistic imperial units. (I jest, love you guys!)

Exposing configuration options for a query plugin is done in two parts. First, build the UI and, second, make use of the stored configuration. In our query plugin class, we’ll implement two methods to help us create the UI, defineOptions and buildOptionsForm :

/**
 * {@inheritdoc}
 */
protected function defineOptions() {
  $options = parent::defineOptions();
  $options['accept_lang'] = array(
    'default' => NULL,
  );
  return $options;
}
/**
 * {@inheritdoc}
 */
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
  parent::buildOptionsForm($form, $form_state);
  $form['accept_lang'] = [
    '#type' => 'select',
    '#options' => [
      '' => $this->t('Metric'),
      'en_US' => $this->t('US'),
      'en_GB' => $this->t('UK'),
    ],
    '#title' => $this->t('Unit system'),
    '#default_value' => $this->options['accept_lang'],
    '#description' => $this->t('Set the unit system to use for Fitbit API requests.'),
  ];
}

With this done, we should see our configuration options in the Views UI under Advanced > Query settings.

undefined

However, it won’t work because we’re not actually using the stored configuration yet. To do that, we’ll add to our execute method in our query plugin:

/**
 * {@inheritdoc}
 */
public function execute(ViewExecutable $view) {
  // Set the units according to the setting on the view.
  if (!empty($this->options['accept_lang'])) {
    $this->fitbitClient->setAcceptLang($this->options['accept_lang']);
  }
  // Clip...
}

Query plugin options are available via $this->options, which Drupal provides as part of the QueryPluginBase class that our Views plugin is extending. We use the stored value, together with a method on the Fitbit client service to set the preferred units for all subsequent API requests: $this->fitbitClient->setAcceptLang($this->options['accept_lang']); . With that, site admininstrators can set their preferred units, and the result set will reflect that choice. Since this is Views and we’ve exposed height as a numeric field, Views core gives us a nice way to format the data and suffix it with units so we end up with a polished result. Just edit the field options.

undefined Field plugin options

Adding options to customize the appearance of the avatar field.

Views also allows us to have custom options for our field plugins. In the last article, we set up a field plugin for avatar which uses the avatar URI from the API response and renders it as an <img> tag. Fitbit’s API actually provides two avatar size options and it would be great to leave it to the site administrator to decide which size to render. We’ll use field plugin options to do that.

As with query plugins, exposing configuration options for a field plugin follows the same two parts, with one small addition. In our query plugin class, we’ll implement two methods, defineOptions and buildOptionsForm , to build the UI:

/**
 * {@inheritdoc}
 */
protected function defineOptions() {
  $options = parent::defineOptions();
  $options['avatar_size'] = ['default' => 'avatar'];
  return $options;
}
/**
 * {@inheritdoc}
 */
public function buildOptionsForm(&$form, FormStateInterface $form_state) {
  $form['avatar_size'] = [
    '#type' => 'select',
    '#title' => $this->t('Image size'),
    '#options' => [
      'avatar' => $this->t('Default (100px)'),
      'avatar150' => $this->t('Medium (150px)'),
    ],
    '#default_value' => $this->options['avatar_size'],
    '#description' => $this->t('Choose the size avatar you would like to use.'),
  ];
  parent::buildOptionsForm($form, $form_state);
}

This should be fairly self explanatory; we’re defining a form element for the UI and, once saved, the configuration option will be stored in $this->options['avatar_size'] . The small addition I referred to earlier lies within the query plugin. Before, we were only passing along the single value for avatar. Now that the site administrator has the option, we’ll want to make sure both values for avatar are passed along in the Views result. We do that, in the query plugins execute method like so:

$row['avatar'] = [
  'avatar' => $data['avatar'],
  'avatar150' => $data['avatar150'],
];

Instead of a flat value, we’re setting ‘avatar’ to an array with both values for avatar from the API response. Then, back in the field plugin, in the render method, we take care to use the appropriate size avatar according to the option selected:

/**
 * {@inheritdoc}
 */
public function render(ResultRow $values) {
  $avatar = $this->getValue($values);
  if ($avatar) {
    return [
      '#theme' => 'image',
      '#uri' => $avatar[$this->options['avatar_size']],
      '#alt' => $this->t('Avatar'),
    ];
  }
}

We simply call $this->getValue($values), which is able to pull out the value we want from the ResultRow object. The render method receives a ResultRow object that has all of the data for the row. FieldPluginBase has a getValue method which we can access since we are extending FieldPluginBase . With that done, we can now click on the avatar field in the Views UI and set the desired image size:

undefined Filter plugins

Filtering the leaderboard by user id.

What if we wanted to limit the result to only a particular user? Say we wanted to show a user's Fitbit details on their Drupal user profile page. For that, we’d need to filter the result set by a user id. To make that happen, we need a Views filter plugin. The first step is to define the field to filter on in hook_views_data():

/**
 * Implements hook_views_data().
 */
function fitbit_views_example_views_data() {
  // Base data and other field definitions...
  $data['fitbit_profile']['uid'] = [
    'title' => t('User id'),
    'help' => t('Drupal user id, not to be confused with Fitbit profile id.'),
    'field' => [
      'id' => 'standard',
    ],
    'filter' => [
      'id' => 'fitbit_uid',
    ],
  ];
  return $data;
}

The part we are most concerned with here is the ‘filter’ key. Its value is an associative array with one key ‘id’, which we set to the name of the filter plugin we’re going to create. Also, note the ‘field’ key, which makes the Drupal user id available as a field in the Views UI. It doesn’t hurt to add it, and it also illustrates how plugins related to a certain field (e.g. field, filter, and others like relationship and argument) are all defined in the same array in hook_views_data(). So, for the next step, we’ll create this file: fitbit_views_example/src/Plugin/views/filter/Uid.php 

<?php
namespace Drupal\fitbit_views_example\Plugin\views\filter;
/**
 * Simple filter to handle filtering Fitbit results by uid.
 * @ViewsFilter("fitbit_uid")
 */
class Uid extends FilterPluginBase {
}

So far, this is typical Drupal 8 plugin scaffolding code. The file is placed in the right folder for the plugin type. The namespace follows PSR-4 naming. The annotation for the plugin type assigns an id to our plugin. Finally, we extend the base class provided by Views for the plugin type. Now let’s look at the specifics required for our filter plugin implementation:

class Uid extends FilterPluginBase {
  public $no_operator = TRUE;
  /**
   * {@inheritdoc}
   */
  protected function valueForm(&$form, FormStateInterface $form_state) {
    $form['value'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Value'),
      '#size' => 30,
      '#default_value' => $this->value,
    ];
  }
}

$no_operator = TRUE tells Views that we are not interested in the site administrators having an option to select an operator. In our case, we’ll keep things simple and always assume '='. You could, of course, allow for choice of operators if your remote service supports it. The key component here is the valueForm method. In it, we need to set an appropriate Form API element for the ‘value’ key of the $form array passed as the first argument. The name ‘value’ is important as the base class expects this key to work. The form element that you return is used in a couple of places. It’s used in the Views UI for when the site administrator is setting up a filter. It’s also used if the filter is exposed, rendered in the exposed filters form with the view itself. That’s it for the plugin implementation.  At this point we can add the filter in the Views UI:

undefined

The last step adjusts our query plugin to be able to handle and make use of the filter. The first thing we’ll need to do is implement an addWhere method on the query plugin class:

public function addWhere($group, $field, $value = NULL, $operator = NULL) {
  // Ensure all variants of 0 are actually 0. Thus '', 0 and NULL are all
  // the default group.
  if (empty($group)) {
    $group = 0;
  }
  // Check for a group.
  if (!isset($this->where[$group])) {
    $this->setWhereGroup('AND', $group);
  }
  $this->where[$group]['conditions'][] = [
    'field' => $field,
    'value' => $value,
    'operator' => $operator,
  ];
} 

Here, especially, we can see Views’ biases to SQL rear its head. The method name, addWhere, is odd from our perspective of querying a remote service. There is no notion of a WHERE clause present in the Fitbit API. Further, Views supports grouping filters, and logical operators within each group. Here again, the remote service we are using has no notion of this. It’s possible the remote service your implementing does in which case the flexibility Views affords is amazing. In our case it’s overkill, but I’ve copied core Views implementation for the SQL query plugin, so we’ll be able to handle everything that the Views UI allows for setting up filters. The final step is adjusting the execute method on our query plugin to incorporate the filter into the call to the Fitbit API:

/**
 * {@inheritdoc}
 */
public function execute(ViewExecutable $view) {
  // Clip ...
  if (isset($this->where)) {
    foreach ($this->where as $where_group => $where) {
      foreach ($where['conditions'] as $condition) {
        // Remove dot from beginning of the string.
        $field_name = ltrim($condition['field'], '.');
        $filters[$field_name] = $condition['value'];
      }
    }
  }
  // We currently only support uid, ignore any other filters that may be
  // configured.
  $uid = isset($filters['uid']) ? $filters['uid'] : NULL;
  if ($access_tokens = $this->fitbitAccessTokenManager->loadMultipleAccessToken([$uid])) {
    // Query remote API and return results ...
  }
}

Here, we’re looping through any filters that have been configured on the view and grabbing their values. We then ignore any other filter that may have been configured on the view, since we’re only supporting uid for now and pass it along to $this->fitbitAccessTokenManager->loadMultipleAccessToken([$uid]), which will limit the access tokens we get back to just the uid set and only show us results for the corresponding user.

Often, as was the case on a recent client project, the filters that you set up will actually get passed along in the remote API request. The Fitbit API is a bit odd in this regard in that most endpoints only return data for a single user anyway, so there is no filtering that makes sense.

That’s it! After all that work, we can set up a filter by uid to limit the results to a single user.

Wrap up

We did it, at long last, we’ve produced a custom Fitbit leaderboard, which might look something like this:

undefined

Of course this is just stock Drupal 8 with the Fitbit module installed and configured, but it’s Views and we all know how to customize the look and feel of Views, so make it pretty to your heart's content.

While we've looked at a lot of code, I don't think that any of it has been horribly complicated. It's mostly a matter of knowing what to put where, with a healthy dose of planning to make sure our data fits into the Views paradigm properly. In summary, the steps are:

  1. Make a plan of attack, taking into account the data you're retrieving and the way Views expects to use it.

  2. Create field handlers for your data as necessary.

  3. Write remote queries to retrieve your data and store it in rows in the view object.

  4. Write filter plugins as necessary to narrow the result set.

There's a lot of work in those steps, but after running through it a couple times the architecture makes a lot of sense.

Get the code!

The code from this article can be found in the Fitbit module on drupal.org. It consists of a base module to handle application setup, authentication and access token storage and two sub-modules for Views integration. The first is fitbit_views_example, which I created specifically for this article series. You’ll find all the code we went through in there. The other one, fitbit_views is a more fully featured and slightly more complex version, including spanning multiple API endpoints with relationship plugins. You should use fitbit_views if your intending on using this functionality on your Drupal site. Feel free to file issues and patches!

Phew, that was a lot. Thanks for sticking with me through it all. Special thanks to Greg Dunlap for trusting me with the reboot of his original series, which has guided me through my own Views query plugin implementations. Thanks also to the Fitbit module maintainer, Matt Klein, who was kind enough to grant me co-maintainer rights on the project.

Categories: Planet Drupal

Modulos experimentales en Drupal 8

Posted by drupaleros.es on January 18, 2017 at 9:48pm
Una de las muchas novedades que ha traído Drupal 8, ha sido el concepto de módulos experimentales, en cada versión menor van añadiendo nuevos módulos para ampliar las funcionalidades del core, estan disponibles para poder probarlos y testearlos. Siempre que se usen, hay que tener en cuenta que al ser experimentales, estan sujetos a cambios repentinos (como desaparecer el core por ejemplo) y no se recomiendan para sitios en producción; además, todos los módulos experimentales tiene un tiempo para estabilizarse desde que se añaden al core en una versión mayor y otra, si superan 2 versiones menores, el modulo se eliminara del core... Leer mas

Great UX design with Drupal

Posted by Appnovation Technologies on January 18, 2017 at 9:37pm

Drupal is the #1 platform for web content management systems. It powers millions of websites in more than 180 languages, with a massive online community with more than 26,000 constantly building and sharing themes and resources.

Categories: Planet Drupal

Project Management: The Unsung Hero of Project Success

Posted by DrupalCon News on January 18, 2017 at 4:30pm

Project management is often the unsung hero in our work. When a project is completed on-time, on-budget, and in-scope, the wheels of innovation keep moving. However, when poor project management takes hold, the work, creativity, and excitement can come to a screeching halt.

Categories: Planet Drupal

CMI en Drupal 8: Exportar configuraciones entre entornos

Posted by Atenea tech blog on January 18, 2017 at 2:54pm

El pasado 24 de noviembre realizé una charla en el Drupal & Beers sobre gestión de configuración con Drupal. En esta ocasión, comparto en el blog las diapositivas de dicha charla que espero que os sean de utilidad:

 

Cmi en drupal 8 de Atenea tech

Pages

Subscribe with RSS Subscribe to Drupal.org aggregator