absolute urls
July 1st, 2008use the url() function like this: url($some_path, array('absolute' => TRUE));
use the url() function like this: url($some_path, array('absolute' => TRUE));
interesting fact: hook_user() hooks aren’t run when the global $user object is loaded. This means that if your module is storing custom data in the user object, it either needs to user_load() the global user itself, or it needs to store its data as part of the user object’s ‘data’ field.
the user var on profile pages refers to the user whose profile it is. how to get access to the current [non-profile] user. via.
menu item title localization - in Drupal 6, menu item titles should be *untranslated*, and you can provide either a translation callback or arguments for the regular translation function [t()]. this is different from Drupal 5, where menu item titles should be translated (usu. the t() function would just be put around the title in the menu item def’n).
so, Image Enhanced Scaling (adds sharpening to resized images) requires that Drupal use Imagemagick as its toolkit, while Image Watermark requires PHP’s GD module… though possibly not as the toolkit? I can’t tell, because GD isn’t in my local PHP install.
Drupal wouldn’t let me change the image toolkit (at admin/settings/image-toolkit) from the built-in GD toolkit because the GD toolkit wasn’t configured correctly and stopped the preference change from saving by throwing an error. I got the pref to set in my install by hacking image.inc so that the function image_gd_settings() never generates an error (and un-hacked it right away afterwards) but didn’t do any sort of general fix. I’d submit a bug report, but right now I don’t feel like figuring out where to do it/if it would be redundant. similar to the issue “Cannot change image toolkit setting after the .inc file is removed.”
Lullabot on Drupal input formats/filters. filters on *output* so data storage isn’t lossy.
Drupal 5: Making forms that display their own results: do $form['#multistep'] = TRUE; and $form['#redirect'] = FALSE;.
Converting 4.7.x modules to 5.x. Posts after this point will refer to Drupal 5 unless otherwise stated.
it was recommended that I run my module through the coder module.
drupal IRC: where it is, guidelines.
vid = Version ID. distinguishes between revisions of nodes (as opposed to nid, which distinguishes between nodes themselves). from the drupal.org forums.
cURL functions in PHP vs. drupal_http_request()? all I can see so far is cURL requiring an optional php extension (ie, not always available on various machines), but I’m more inclined to use it because I’m more used to the PHP documentation than the drupal documentation.
build a cck *field* module in drupal (to add new fields to cck content types)
hooks, options, cck features, api best practices
darrel o’pry (dopry), karen stevenson (karens)
code is online, somewhere.
making a cck module.
karen will make a really simple one.
drupal.org/node/somewhereunreadable
components of a cck module:
give field a type name.
label for type of field
- spaced out -
content_format() you can do this yourself in your theme, and use any of the “formatters” available from the field’s cck module.
darrel will make another one
the code is available in drupal’s cvs… geolocation field
mentions the dprintr() function, what is it?
dopry’s demo module in the drupal cvs: drupal contrib -> head -> geolocation
jeremy epstein
options for structure & hierarchy. strengths and weaknesses.
users see pages, drupal sees menu callbacks
modules define the menu_hook, which lets you define callbacks at urls.
menu callbacks don’t necessarily reflect the structure that your users see on the site; don’t always relate to what users see on the site.
pages: how are they arranged?
traditionally in drupal: open and flexible. has this been a problem?
no “folder” concept in drupal. some other cmses are pretty strongly based on the file/folder metaphor, ie plone.
*nix shell = open sea, no navigational elements
web = city. people are surrounded by environment/context.
currently not built to work together.
drupal’s current navigation api
nav elements and how they work
drupal_set_breadcrumb() and menu_set_location(): “evil hacks,” because they override user [something]all pages linked using a unified relationship api. it would define parents, children, siblings.
(me thinking: possibly also defining relationships like relating user or event nodes to story or page nodes. or a define-your-own-relationship kind of space.)
every page’s content would be customizable
a lot of pages are just menu callbacks, and they’re not editable. one way to go about this: every page as a node, and module output embedded within node pages. note: the “about us” page is a node, and editable, but the “forum” page isn’t, because it’s just a menu callback. developers don’t like this solution.
(audience talking: there should be a way to link the admin page relating to a page that is a menu callback to the callback page thing itself)
navigational elements should consistently reflect the same relationships
if someone builds this, it should be in the next drupal.
session description. the slides for this talk are available at the presenter’s website.
people still hate javascript, but it is
var myHash = { foo: 1, 'bar': 'two'};
// myHash.foo == 1 OR myHash['foo'] == 1
function = primitive type. this enables javascript closures. a method in an object is just a function…
var myObject = {
foo: 1;
bar: function () { ... } (or something?)
}
function as object constructor
var myClass = function (thing) {
this.thing = thing;
this.bar = function () { ... };
return this;
};
// myClass.prototype.foo = function() { ... };
var myObject = new myClass("dork");
myObject.bar();
closure example:
function myFunc() {
var counter = 0;
function closureFunc() {
counter++;
alert(counter);
};
return closureFunction;
};
var closure = myfunction();
closure(); // 1
closure(); // 2
AJAX is making GET and POST requests from JS. you can send xml if you want, but it’s heavyweight. JSON = javascript object notation, simpler/lighter.
jquery doesn’t:
jqueries use css3/xpath selectors to find elements
(me thinking: simon willison had a script that would select elements based on their css selectors… updated version or similar more polished thing: http://bennolan.com/behaviour/
example:
$('table.prices tr:last-of-type td')
jquery methods are chainable: the query obj is stateful. method on method on method.
$('p').addClass('big').wrap('<span></span>')
.filter('.tagged').css('background','red').end()
sensible event handling
$('span.info')
.mouseover(function () { ...})
.mouseout(function () { ...})
...
woah: give jquery some html, and it will convert it to DOM nodes and then act on it.
$('<div></div>').hide().dostuff().appendTo('#elementidorsomething');
so chainable in jquery translates to doing an entire action without an expressed variable. bizzarre but eventually comprehensible.
there are plug-ins for jquery. they provide new chainable methods, more effects. more ui flashy junk.
drupal 5 uses jquery 1.0. you can upgrade drupal 5.0 to use jQuery 1.1, but you have to install a 1.0 compatibility plugin [jQuery plugin, not drupal].
js in a CMS:
specific drupal features that use js: form api widgets, drupal_add_js()
“standard way of passing things from php to js”
client side: namespace your methods (how, precisely?)
drupal 5 js was rewritten with jquery
why jQuery:
caveats:
writing fast and slow jqueries (there are ways to do both. hah.)
live demo using firebug
simple html page with image, text, hidden form
$('p')[0] // dom object
wrap that in $ for jquery obj rather than dom object:
$($('p')[0])
$('#sign-up a').click(funtion() {
$(this).hide();
$('#sign-up form').fadeIn('something');
});
using css3 selectors within jquery:
$('p:nth(0)').fadeOut());
see acko.net for code snippets.
color picker jquery plugin (the one in drupal 5?)
uses “thickbox”. there’s a thickbox module (for jquery). is thickbox a js library thingy? do I care?
some people use jquery to fix browser bugs. that’s dumb.
fyi, firebug is a complete debugger.
jquery is very different from other js libraries because it’s very “intrusive in the way you program” - probably because of the bizarre chaining things
jquery is pretty good at abstracting &c. you can use jquery.(things) the same way $(things) is used in the above snippets.
jquery documentation:
drupal_get_form('form_id')my_form(), spits back htmlmy_form_validate()drupal_get_form('my_form')$_POST datamy_form()my_form_validate(...)my_form_submit(...)drupal_rpocess_form()drupal_build_form()hook_form_alter()_form_builder() - weaves together form and post data. populates defaults, $_POST, builds $form_values, inserts security tokens.$_POST vars come in that don’t match the structure of the form (as it is after hook_form_alter()!), they’re not considered (where?)$form_values global(?). some stupid thing about having too many things that need to talk to and maniuplate $form_values, and having to make it global for that reason.hook_elements()hook_form_alter()drupal_execute()my_form_submit()” etc.<?php print request_uri(); ?>. you have to set the input type on that page to let you use php.or, setting the file system settings to “Private - files are transferred by Drupal.” discussion at drupal.org. the key bit is that anyone can still access the files if they know their url; to prevent that, you either have to put the files directory outside of the web directory, or add something like this in an .htaccess file within the files directory:
ORDER DENY,ALLOW DENY FROM ALL ALLOW FROM XXX.XX.XX.XXX
XXX.XX.XX.XXX is your hosts IP address; 127.0.0.1 should work fine for anyone (it does for me).
devel. mostly it shows all the db queries that are run to create a page, which looks outrageous sometimes: 140 queries for the front page, 60 for a very plain regular page.
so, the caching problem: possibly it’s because the pages are stored as binary blob data and not sent to the browser correctly, as described in this comment. super-helpful debug thread; if that’s not my problem, it might be with having something in hook_init() in a custom(ized) module. anyways, caching is off for now.
I turned on caching at the ccrh dev drupal today, and it started serving blank pages. WHY?!?
Drupal’s file handling is gross. Either it allows direct access to all files via the filesystem (so you can’t apply access rights to files), or it passes every file through some bit of script (more overhead for every file accessed). Theme files aren’t handled through the same mechanism (a good thing). I need some sort of file manager that can manage permissions and file locations but allows files to be attached to nodes the usual way. list of file management modules - drupal.org.
see file_create_url().
I also want something where files aren’t all dumped in the same folder.
in order for a user to create content, they have to have the “access administration pages” privilege (under the system module)
stdClass Object
(
[uid] => 1
[name] => admin
[pass] => **hashed password**
[mail] => **my email address**
[mode] => 0
[sort] => 0
[threshold] => 0
[theme] =>
[signature] =>
[created] => 1161027521
[access] => 1166740122
[login] => 1166410715
[status] => 1
[timezone] => -25200
[language] =>
[picture] =>
[init] => **another email address**
[data] => a:5:{s:6:"submit";s:18:"Create new account";s:7:"form_id";s:13:"user_register";s:7:"contact";i:0;s:10:"form_token";s:32:"**hashed thing**";s:5:"block";a:1:{s:4:"menu";a:1:{i:107;i:1;}}}
[sid] => **hashed thing**
[hostname] => **ip address**
[timestamp] => 1166740122
[cache] => 0
[session] => watchdog_overview_filter|s:3:"all";node_overview_filter|a:1:{i:0;a:2:{i:0;s:4:"type";i:1;s:17:"content_staff_bio";}}file_previews|a:0:{}
[submit] => Create new account
[form_id] => user_register
[contact] => 0
[form_token] => **hashed thing**
[block] => Array
(
[menu] => Array
(
[107] => 1
)
)
[roles] => Array
(
[2] => authenticated user
)
)
I just realized that to a certain extent I’m much more comfortable throwing some php into my theme, and doing work there, than building a module that will generate a block so I can go in and clicky-clicky in drupal’s ui. and that now that I’ve built the first solution, I think it might be good to do it the second way, so *other* people can clicky-clicky.
(specifically this is in re- to “my navigation thing.”)
wanting to restrict access to the board meeting minutes and board packets on our site. possible modules:
conclusion: simple access. I think.
writeup on attaching images to nodes: Image and Image Exact Sizes vs. Imagefield and ImageCache. using an imagefield on a custom cck content type isn’t an option for me… I’m using the standard story type. just trying to figure out how to let people put images in their posts and pages easily. (also, which wysiwyg editor to use?). I feel like these should be ‘duh’ decisions and I have just forgotten/not absorbed the answers.
arg() only gets parts of the internal path. drupal_get_path_alias('some/internal/path') gives you the face you want to show to the world. ex: drupal_get_path_alias('node/'.$node->nid). snippet here: customizing themes by location.
check whether a page is the front page in a template:
<?php if ($is_front) { /* do something */ } ?>
suppressing the redirect that happens after form processing at drupal.org. also, getting to $form_values and $_POST shit. $form_values doesn’t seem to be as global as it pretends to be…
update: apparently, $form_values shouldn’t be a global, and using it is bad. or something.
writing forms in tables. for when I eventually want to clean up the field prefs of cck_search to be themed into a table instead of hacked into one.
extreme drupal theming, a series of tutorials by nick lewis.
inner/left/right joins: what and why. at drupal.org. really basic, really essential, not drupal specific.
wear rubber gloves!
how to handle text in a secure fashion at drupal.org. talks about check_plain() and friends.
watchdog() is good for debugging your code. (how to use watchdog())
<?php
// snippet taken from 4.7 -- includes/bootstrap.inc
/**
* Log a system message.
*
* @param $type
* The category to which this message belongs.
* @param $message
* The message to store in the log.
* @param $severity
* The severity of the message. One of the following values:
* - WATCHDOG_NOTICE
* - WATCHDOG_WARNING
* - WATCHDOG_ERROR
* @param $link
* A link to associate with the message.
*/
function watchdog($type, $message, $severity = WATCHDOG_NOTICE, $link = NULL) { ... }
?>
really useful example: a module with a form. at drupal.org.
so first you do:
drupal_get_form('form_name', $form_variable, 'form_callback');
then you define functions form_name_validate($form_id, $form_values) and form_name_submit($form_id, $form_values) that get called when you use drupal_get_form(). so you have drupal_get_form() generate the form, then you hit submit, then drupal_get_form() uses form_name_validate() to validate the form, and if it’s ok, runs form_name_submit(), which will most likely stow the data in the database.
flow chart of drupal_get_form(). at a blog by a lullabot guy. need more help with this!
interesting: the arg() function doesn’t seem to clean anything out of the url: if you put html in the url, and then the code does something like <?php print arg(4); ?>, then you get that html that was in the 4th (actually 5th, it starts at 0) argument printed out.
forms api quickstart guide, forms api.
the beginning of making a search form for a specific cck content type:
<?php
$form ['quick'] = array (
'#type' => 'fieldset',
'#title' => 'Quick Search',
'#tree' => TRUE,
);
$form['quick'][$field_name] = array(
'#type' => $field_type,
'#title' => $field_label,
// type specific things
);
$form['advanced'] = array (
'#type' => 'fieldset',
'#title' => 'Advanced Search',
'#tree' => TRUE,
);
$form['results'] = array (
'#type' => 'fieldset',
'#title' => 'Results Options',
'#tree' => TRUE,
);
?>
to check wheather someone is logged in inside a theme, use <?php if ($user->uid) {} ?>. also, you have to add global $user in the php somewhere. see this comment at drupal.org.
I find drupal’s profusion of globals unsettling.
lullabot on theming by http header. basically, use this snippet:
<?php
$headers = drupal_set_header();
if (strpos($headers, 'HTTP/1.0 404 Not Found')) {
?>
update: better to use drupal’s built-in 404 setup: 404 pages.
modules currently enabled on a site I’m working on are:
the simplenews module requires that the taxonomy module be enabled.
I installed and enabled the image module, but was getting a message that said, “Make sure you have a working image toolkit installed and enabled, for more information see: the settings page.” The settings page had no info. from various sources I found that in order to get the image module to work, I needed to install gd2 (can do via fink). will this be already installed on our server? if not, can we get it installed? otherwise, have to figure out another solution.
update: php needs to be compiled with gd2 support. I don’t plan on recompiling php right now. it can use imagemagick, too, which supposedly I have installed, but I don’t know where the hell it resides. fuck it, on to othet things.
a little info gleaned from this page on mac os x specific guidelines at drupal.org.
update: my imagemagick is at /sw/bin/convert. you need to move image.imagemagick.inc into drupal’s includes directory, and make sure the path to imagemagick on lines 16 and 68 is correct. so now the image module doesn’t throw an error. this was found at Image module with imagemagick [solution] at drupal.org. image_attatch isn’t working yet though.
is a js wysiwyg editor. to install it in drupal, get both the module (tinymce at drupal.org) and the independant tinymce thing (tinymce javascript content editor). unstuff the the tinymce thing and put it inside the drupal module folder. then put the whole jumble inside drupal’s modules folder. the actual install instructions aren’t prominently linked on the tinymce project page!
for the future when I possibly make a module: Module Builder: “A module which auto-generates a skeleton or “scaffolding” for a module, along with hints on how to fill them in. Useful for newbie developers to learn how hooks work, and seasoned developers who are too lazy to look up what arguments a function has to take.”
themeable functions. see theme.inc for more on the theming framework.
they aren’t available by default. you have to paste this snippet in at the top:
<?php $base_path = base_path(); $directory = path_to_theme(); ?>
from this post at drupal.org: difficulty with image tag inside of block template.
get nodes as an array for greater flexibility - drupal.org. hacking template.php.
update 12/14: this works fine on the front page and on views, but nothing at all (not the headers of the template, not anything) shows up when looking at a single node (like a page node). crap, I liked this. (what is breaking it?)
primary and secondary links are available within page.tpl.php as arrays ($primary_links and $secondary_links). customising how the primary or secondary links are displayed - drupal.org.
display children of current menu node - snippet at drupal.org. slightly more informed than my snippets.
pathauto for the “inclusionary housing policy” type wasn’t working because the ‘name’ field in the ‘variable’ table was only 48 characters–the content type name plus pathauto’s name was too long so had to be truncated to fit in, so when an ih policy was submitted, pathauto wouldn’t find a path pattern for it. solution:
ALTER TABLE variable MODIFY COLUMN `name` varchar(128) NOT NULL default '';
use the drupal function arg(0). 0=1st, 1=2nd args, etc. more info.
to log in, go to [drupal install]/manage/login
for use within node.tpl.php. put this at the top:
<?php $type = (node_invoke($node->type, 'node_info')); ?>
then use the $type variable wherever you want the (human readable) name of the node type. from: Node.tpl.php at drupal.org.
make a template called “node-type.tpl.php”. for cck circa aug 2006, this is ‘node-content_cust_content_name.tpl.php’. then put this in to find out what info is available:
<pre><?php print_r($node); ?></pre>
gleaned from creating a template handbook.
cck fields with ‘multiple’ values result in duplicate nodes showing up in a view. this patch is supposed to fix it: content_views.inc_2.patch. (my first drupal.org comment there! for the same issue, see also: issue discussed first here). not sure if it actually does fix it. cli syntax to patch a file (patches in place, make a backup):
$ patch originalfile patchfile
patched eval, local dev, and ccrh drupal installs.
installed modules and themes are stored in the table ’system’:
mysql> describe system; +----------------+--------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------------+--------------+------+-----+---------+-------+ | filename | varchar(255) | | PRI | | | | name | varchar(255) | | | | | | type | varchar(255) | | | | | | description | varchar(255) | | | | | | status | int(2) | | | 0 | | | throttle | tinyint(1) | | | 0 | | | bootstrap | int(2) | | | 0 | | | schema_version | smallint(3) | | | -1 | | | weight | int(2) | | MUL | 0 | | +----------------+--------------+------+-----+---------+-------+
modules are registered there when they are first installed; if you want to do a fresh install of a module (say, its tables got munged up), you need to drop its tables AND remove its entry from the ’system’ table.
gleaned from this handbook article: resetting the views module completely.
I was reading the tutorial on creating a module for drupla, and started writing this annotated module boilerplate, for a module called “modulename.module”:
<?php
/* $Id */
/**
* HELP HOOK
* $section variable provides context for help: where in Drupal or the module
* are we looking for help?
* - recommended to process this with a switch statement.
* more help hook info: http://api.drupal.org/api/4.7/function/hook_help
*/
function modulename_help($section='') {
$output = '';
switch ($section) {
case "admin/modules#description":
$output = t("module description for modules admin panel");
break;
}
return $output;
} // function modulename_help
/**
* PERMISSIONS HOOK
* valid permissions for this module, returns an array of valid permissions
* more permissions hook info: http://api.drupal.org/api/4.7/function/hook_perm
*/
function modulename_perm() {
return array('access content', 'administer modulename');
} // function modulename_perm
/**
* BLOCK CONTENT
* generate html for the modulename block
* @param op the operation from the URL
* @param delta offset
* @returns block HTML
* more info on the block hook: http://api.drupal.org/api/4.7/function/hook_block
*/
function modulename_block($op='list', $delta=0) {
// listing of blocks, such as on the admin/block page
if ($op == "list") {
$block[0]["info"] = t('module name...');
return $block;
}
else if ($op == 'view') {
// lala... stuff goes here.
}
} // end modulename_block
/* this is only the beginning... */
?>
Content Templates module: “allows modification of Drupal’s teaser and body fields using administrator defined templates. These templates use PHP code and all of the node object variables are available for use in the template. An example node object is displayed and it is as simple as clicking on its properties to add them to the current template.” hah, it’s also called “contemplate.” especially useful with cck, but can be used with any node type.
the workflow module (which requires the actions module) might do the job of archiving (rather than unpublishing, like node expire) items after a certain date. possibly if it doesn’t out-of-the-box, I could also hack node-expire to be ‘node-un-premote-to-front-page’.
sweet! I can use the filters part of the views module to make my custom IH Policy content type searchable! Views module documentation.
Probably half of which I will be using. 10 Drupal Modules You Can’t Live Without | Nick Lewis: The Blog
imagefield.module: “provides an image field to cck content types.” possibly will use it to hold a graph in the IH policy content type.
summary of updating handbook.
cp -r drupal_site/ drupal_bak/
chmod +x drupalsqldump.sh ./drupalsqldump.sh drupal_site/sites/defaolt/settings.php > drupal_bak/backup.sql
enabled: “manage” (same as bluemarine) and “mytemp”, default “mytemp”.
at the moment:
<?php
$i = 1;
$m = Array();
while ($m = menu_primary_links($i)) {
print theme_menu_links($m);
print "rr";
$i++;
}
?>
prints out every bunch of menus down to where you’re currently at in seperate lists.
<?php
print menu_get_active_title(); // name of most local currently active menu item
print menu_get_active_nontask_item(); // menu id of most local currently active menu item
?>
<?php print theme_menu_local_tasks(menu_get_local_tasks()); ?>
“local tasks” are things like view, edit, track. they are usu. styled as tabs. menu_get_local_tasks() gets the menu structure in an array.
<?php print theme_menu_tree($mid); ?>
where $mid is a menu id (look in the table ‘menu’… for menu items pointing to a top level path, try SELECT * FROM drupal.menu WHERE path NOT LIKE '%/%';)
if I set “menu containing secondary links” to my main sections menu (”other sections” right now) in admin/settings/menu, then this prints out a list of the second layer of menu items–the menu items for the section you’re in:
<?php
$section_menu = menu_secondary_links();
print "<ul>r";
foreach ($section_menu as $mi) {
print "<li>$mi</li>r";
}
print "</ul>r";
?>
however, it only goes one layer deep, which is no good. looks like I’ll have to generate and theme my own menu-data-structure. fuck. If I do, I’ll probably hack it together so it will only work with my implementation (sucky way to bother coding something). and I won’t have niceities like caching and themeing… though maybe. fuckity-fuck, why hasn’t someone else written this?
this function may be very useful: menu_secondary_links() (especially if I could figure out how to build a menu from it/theme it). it’s from menu.module. menu system API reference.