Tuesday, October 30, 2012

Adding menu items to an drupal 7 install profile

using the .install file ( located here: <websitedir>/profiles/<profilename>/<profilename>.install )

You can add menu items by extending the array like in the standard install profile:

adding this will put the block main-menu in the menu_bar region:

array(
      'module' => 'system',
      'delta' => 'main-menu',
      'theme' => $default_theme,
      'status' => 1,
      'weight' => 0,
      'region' => 'menu_bar',
      'pages' => '',
      'cache' => -1,
    ),
The trick was here setting the module to 'system' instead of 'menu' otherwise errors will show up after install. 
You can define the theme you want to apply this for or don't set it to apply on all themes. Since this is a system default location you should be fine not setting the theme.

Then let the following query run ( just like the standard.install file )


 $query = db_insert('block')->fields(array('module', 'delta', 'theme', 'status', 'weight', 'region', 'pages', 'cache'));
  foreach ($values as $record) {
    $query->values($record);
  }
  $query->execute();
Then creation the menu items like so:


// create menu
  $item = array(
    'link_title' => st('Home'),
    'link_path' => '<front>',
    'menu_name' => 'main-menu',
  );
 menu_link_save($item);


Optional you could do a menu_rebuild but I didn't see a difference while installing.
maybe this is only for modules so the menu gets 'cleared' after enabling a module.
since the whole site is just build it might not be necessary doing this in a profile .install file


Update the menu router information.
menu_rebuild();


Monday, October 29, 2012

Setting a different default theme by default in an install profile

For an install profile you can look at the profiles that are included in the drupal install.
They can be found in sitename/profiles
As in an standard Drupal 7 instal there are 2 profiles 'minimal' and 'standard'.

The profiles are somewhat like modules and also work like that.

The profilname.info file can be used to define dependencies and thus enabling the defined modules when this profile is chosen.
again look at the standard.info file for an example.

In the .profile file you can alter the form that is used upon install and predefine values for fields.

but to set an other default theme you need the .install file.

In the .install file you place an hook_install()

at the end of your profilename_install() hook you place the following code:
profilename_install() {
// some other code

  db_update('system')
    ->fields(array('status' => 1))
    ->condition('type', 'theme')
    ->condition('name', 'yourthemename')
    ->execute();
  variable_set('theme_default', 'yourthemename');
}
Just make sure that yourthemename is available in your install directory.


Setting the theme settings.

The next step is setting the theme variables but I haven't figured that out so I will update this post when I get there...

I think you can set the values in the 'system' table WHERE `name` = 'themename'
Best way to do this is click the theme to the point you like it, then go to the database and copy the values of the according `info` field.

Friday, October 26, 2012

adding a city autotagging field to an user by creating a custom drupal 7 module

This posts tells you about how to programmatically create a field, instance, taxonomy library and create an autotagging widget in the form with it.

First in your module.install file create a hook_enable() function.
In the final version this would be hook_install() but while testing the module I find it easier to use hook enable so you can do: drush en mymodule -y and drush dis my module -y to enable and disable the module.

My module is called popover so that's the name I'll be using next.


/**
 * Implements hook_enable
 * runs every time this module is enabled, to run only at install use hook_install
 * Once the module has been enabled ( even only once ) hook_install won't be called anymore.
 */
function popover_enable() {
        // starting with the taxonomy library ( vocabulary ) first:

$vocabulary = (object) array(
'name' => 'City',
'description' => 'Pick your city :)',
'machine_name' => 'city',
);
taxonomy_vocabulary_save($vocabulary);
$terms = array(
'Amsterdam',
'Rotterdam',
'Rosmalen',
'Driebergen',
'Zeist',
'Utrecht',
);
        // I've created a custom function to save multiple terms to one vocabulary:
_popover_taxonomy_terms_save($terms,$vocabulary->vid);

        // building the field
$field = array(
'field_name' => 'field_' .$vocabulary->machine_name,
'type' => 'taxonomy_term_reference',
'settings' => array(
'allowed_values' => array(
array(
'vocabulary' => $vocabulary->machine_name,
'parent' => 0,
),
),
),
);
field_create_field($field);

        // connecting the user to the field I've just created
$instance = array(
'field_name' => 'field_' . $vocabulary->machine_name,
'entity_type' => 'user',
'label' => $vocabulary->name,
'bundle' => 'user',
'required' => TRUE,
'widget' => array(
'type' => 'taxonomy_autocomplete',
'weight' => -4,
),
'display' => array(
'default' => array(
'type' => 'taxonomy_term_reference_link',
'weight' => 10,
),
'teaser' => array(
'type' => 'taxonomy_term_reference_link',
'weight' => 10,
),
),
);
        // another custom field creator function
popover_field_create_update_instance($instance);
}



And the function I'm calling from the code above:

/**
 * save multiple terms to one taxonomy Vocabulary
 * @param  array $terms array of term names
 * @param  int   $vid   Vocabulary id
 */
function _popover_taxonomy_terms_save($terms,$vid) {
foreach($terms as $term) {
taxonomy_term_save(
(object) array(
'name' => $term,
'vid' => $vid,
)
);
}
}

/**
 * field creater helper function checks if field already is in this bundle if so do update instead of create
 */
function popover_field_create_update_instance($instance) {
if( field_info_instance($instance['entity_type'], $instance['field_name'], $instance['bundle']) == NULL) {
return field_create_instance($instance);
}
else{
return field_update_instance($instance);
}
}



Now because the instance is in the user bundle the field should now be showing up on the user edit form.

To delete the instance, field and vocabulary upon uninstall of the module. I've written the following:


/**
 * Implements hook_disable()
 * TODO: needs to be hook_uninstall in the future but again for testing using the hook_disable
 */
function popover_disable() {
// create array with instances/fields/vocabularies to cleanup
  $cleanups = array(
  'city',
  // you can add more fields here...
  );
  foreach($cleanups as $name) {
  _popover_cleanup_instance_field_vocabulary($name);
  }

  // force field purge ( so it is really deleted without waiting for cron )
  // I think I would remove this in the final version as well since your not going to uninstall a
  // module and then reinstall it again immediately after. besides opening the module page 
  // and then the unistall page calls cron if I remember correctly but not sure about that... anyway:
field_purge_batch(5000); // not sure if this is a to high number...
}

/**
 * cleanup helper function
 * @param  String $name machine_name of the vocabulary ( 'field_' is added for the field/instance)
 */
function _popover_cleanup_instance_field_vocabulary($name) {
$instance = field_info_instance('user','field_' . $name,'user');
// removing instance of field_$name in the user bundle
field_delete_instance($instance, true);
// deleting field
field_delete_field('field_' . $name);

// delete city vocabulary
$vid = db_select('taxonomy_vocabulary', 'v')
    ->fields('v', array('vid'))
    ->condition("v.machine_name", $name)
    ->execute()
 ->fetchField();
  taxonomy_vocabulary_delete($vid);
}

You can see the whole module on my github But I'm still working on it so don't expect it to work 100%

Thursday, October 11, 2012

drush make with install profile run from github

keeping installing sites and enabling all those modules you use every time is a pain in the ass.

Well no more!

I discovered that there is an easier way!

To work with this you need to have a basic drupal webserver running or need to install that first.
also drush 5.x needs to be enabled so you can run drush make

To get a quick and dirty solution just for testing or for me to remember how to get the install, you need to run the following command in the folder where you want the drupal install:
drush make https://raw.github.com/scubafly/drupal-make-files/master/d7.make -y

To jump to understanding what I did, here's what I did:

First I made a list of modules that I always use.
Then based on that list I created a .make file which now sits at https://raw.github.com/scubafly/drupal-make-files/master/d7.make 

And looks like this:
core = 7.x
api = 2

; core
projects[] = drupal
; basic drupal 7 install always needed file with devel included
projects[] = admin_menu
projects[] = ctools
projects[] = devel
projects[] = link
projects[] = mail_logger
projects[] = l10n_client
projects[] = l10n_update
projects[] = backup_migrate
projects[] = entity
projects[] = module_filter
projects[] = pathauto
projects[] = profile2
projects[] = token
projects[] = taxonomy_csv
projects[] = wysiwyg
projects[] = views

So now I can run the following command in the terminal while sitting in the folder where I want my drupal install:
drush make https://raw.github.com/scubafly/drupal-make-files/master/d7.make -y
This will download the latest drupal 7 and modules that where included in the make file.

So yeah thats all fun and all, but still you need to click trough the install and use "drush en module, module, module, module" or manually click to enable all the modules you want for every install.

Creating a profile.

The easiest way to create a profile from scratch is to copy the profile from an existing drupal install.
The install profiles can be found in websitefolder/profiles/<profilename>

profiles are somewhat like modules except they are not, they are profiles :)
Now in the .info file you can define which modules should be enabled. If you look at the standard profile ( websitefolder/profiles/standard/standard.info ) you can see that there are dependencies defined.
for example this is how you would define that devel should be enabled upon installation:
dependencies[] = devel

More information how to create profiles can be found here

I've pushed the profile into github so I can include it in my make file. My profile info looks like this at the moment of writing:
name = Jack standaard
description = basic install profile
core = 7.x

;this is used to enable the modules

; d7.make modules
dependencies[] = admin_devel
dependencies[] = admin_menu
dependencies[] = ctools
dependencies[] = block
dependencies[] = color
dependencies[] = contextual
dependencies[] = dashboard
dependencies[] = dblog
dependencies[] = field
dependencies[] = field_sql_storage
dependencies[] = field_ui
dependencies[] = file
dependencies[] = filter
dependencies[] = help
dependencies[] = image
dependencies[] = list
dependencies[] = locale
dependencies[] = menu
dependencies[] = node
dependencies[] = number
dependencies[] = options
dependencies[] = overlay
dependencies[] = path
dependencies[] = rdf
dependencies[] = search
dependencies[] = shortcut
dependencies[] = system
dependencies[] = taxonomy
dependencies[] = text
dependencies[] = trigger
dependencies[] = update
dependencies[] = user
dependencies[] = devel
dependencies[] = link
dependencies[] = mail_logger
dependencies[] = l10n_client
dependencies[] = l10n_update
dependencies[] = backup_migrate
dependencies[] = entity
dependencies[] = module_filter
dependencies[] = pathauto
dependencies[] = profile2
dependencies[] = token
dependencies[] = taxonomy_csv
dependencies[] = wysiwyg
dependencies[] = views
dependencies[] = views_ui


Since I pushed the whole profile to github ( click the link for details ) I can now include the profile to the make file which then ends up looking like this:

core = 7.x
api = 2

; core
projects[] = drupal
; basic drupal 7 install always needed file with devel included
projects[] = admin_menu
projects[] = ctools
projects[] = devel
projects[] = link
projects[] = mail_logger
projects[] = l10n_client
projects[] = l10n_update
projects[] = backup_migrate
projects[] = entity
projects[] = module_filter
projects[] = pathauto
projects[] = profile2
projects[] = token
projects[] = taxonomy_csv
projects[] = wysiwyg
projects[] = views

; add custom profile
projects[jack_standaard][type] = "profile"
projects[jack_standaard][download][type] = "git"
projects[jack_standaard][download][url] = "git://github.com/scubafly/jack_standaard.git"

make sure u use the git read only link as url that works the best without the need of logging in.

now when you run drush make https://raw.github.com/scubafly/drupal-make-files/master/d7.make -y  the drupal, the modules and the profile will be downloaded. And when you open the webpage you should see the 'jack_standaard' profile as option to install.




Wednesday, October 10, 2012

Create a new repository and add ssh login for the command line so you don't have to type your password every time you do a git push


Create a new repository and add ssh login for the command line so you don't have to type your password every time you do a git push

1) Create new repository on github
2) Create a new repository on the command line


touch README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin git@github.com:scubafly/<reponame>.git
git push -u origin master


To create a new ssh rya key pair if needed see https://help.github.com/articles/generating-ssh-keys

after that you can use the following to log in once per terminal without reentering the username and pass all the time...

In the terminal enter:
3) ssh-agent bash
4) ssh-add
5) enter passphrase

Monday, October 8, 2012

Adding a submit function without changing the current

I created a custom table in the database for my module and would like to save a field to that database upon submit of the user_profile_form.

I did this by creating a custom submit handler using the hook_form_alter() function
But instead of just changing the $form['submit'] I added a submit handler as first value of the $form['submit'] array like so:
array_unshift($form['#submit'], 'job_agent_user_profile_form_submit');

Resulting in the following function:

/**
 * Implements hook_form_alter()
 */
function job_agent_form_alter(&$form, $form_state, $form_id) {
if($form_id == 'user_profile_form') {
// get job agent value from db for user that is being edited
$account = $form_state['user'];
$job_agent = db_select('job_agent_searches', 'j')
->fields('j',array('enabled'))
->condition('uid', $account->uid)
->execute()
->fetchField();

// add extra field job agent field to the form
$form['job_agent'] = array(
'#title' => t('Job Agent'),
'#type' => 'checkbox',
// table: job_agent_searches field: enabled where uid = uid
'#default_value' => $job_agent,
'#description' => t('zet hier je job agent op basis van jouw profiel aan of uit.')
);
// add submit handler 'on top' of submit array instead of overwriting it leaving other submit functions there to work as well.
array_unshift($form['#submit'], 'job_agent_user_profile_form_submit');
}
return $form;
}

And finally create the custom submit handler function:

/**
 * Custom submit handler to be added to user_profile_form
 * saves job_agent field to job_agent database for the user that is being edited.
 */
function job_agent_user_profile_form_submit($form, &$form_state) {
$account = $form_state['user'];
// save job agent field to the db here.
db_update('job_agent_searches')
->condition('uid', $account->uid)
->expression('enabled',':enabled', array(':enabled' => $form_state['values']['job_agent']))
->execute();
}