system.module 62.1 KB
Newer Older
Dries's avatar
 
Dries committed
1
<?php
2
// $Id$
Dries's avatar
 
Dries committed
3

Dries's avatar
   
Dries committed
4
5
6
7
8
/**
 * @file
 * Configuration system that lets administrators modify the workings of the site.
 */

9
define('VERSION', '6.0-dev');
10
define('DRUPAL_CORE_COMPATIBILITY', '6.x');
11

12
13
14
15
16
define('DRUPAL_MINIMUM_PHP',    '4.3.3');
define('DRUPAL_MINIMUM_MYSQL',  '4.1.0'); // If using MySQL
define('DRUPAL_MINIMUM_PGSQL',  '7.4');   // If using PostgreSQL
define('DRUPAL_MINIMUM_APACHE', '1.3');   // If using Apache

17
18
19
// Maximum age of temporary files in seconds.
define('DRUPAL_MAXIMUM_TEMP_FILE_AGE', 1440);

Dries's avatar
   
Dries committed
20
21
22
/**
 * Implementation of hook_help().
 */
23
function system_help($path, $arg) {
24
25
  global $base_url;

26
  switch ($path) {
27
    case 'admin/help#system':
28
      $output = '<p>'. t('The system module provides system-wide defaults such as running jobs at a particular time, and storing web pages to improve efficiency. The ability to run scheduled jobs makes administering the website more usable, as administrators do not have to manually start jobs. The storing of web pages, or caching, allows the site to efficiently re-use web pages and improve website performance. The system module provides control over preferences, behaviours including visual and operational settings.') .'</p>';
29
      $output .= '<p>'. t('Some modules require regularly scheduled actions, such as cleaning up logfiles. Cron, which stands for chronograph, is a periodic command scheduler executing commands at intervals specified in seconds. It can be used to control the execution of daily, weekly and monthly jobs (or anything with a period measured in seconds). The aggregator module periodically updates feeds using cron. Ping periodically notifies services of new content on your site. Search periodically indexes the content on your site. Automating tasks is one of the best ways to keep a system running smoothly, and if most of your administration does not require your direct involvement, cron is an ideal solution. Cron can, if necessary, also be run manually.') .'</p>';
30
      $output .= '<p>'. t("There is a caching mechanism which stores dynamically generated web pages in a database. By caching a web page, the system module does not have to create the page each time someone wants to view it, instead it takes only one SQL query to display it, reducing response time and the server's load. Only pages requested by <em>anonymous</em> users are cached. In order to reduce server load and save bandwidth, the system module stores and sends cached pages compressed.") .'</p>';
31
      $output .= '<p>'. t('For more information please read the configuration and customization handbook <a href="@system">System page</a>.', array('@system' => 'http://drupal.org/handbook/modules/system/')) .'</p>';
32
      return $output;
33
    case 'admin':
34
      return '<p>'. t('Welcome to the administration section. Here you may control how your site functions.') .'</p>';
35
    case 'admin/by-module':
36
      return '<p>'. t('This page shows you all available administration tasks for each module.') .'</p>';
37
    case 'admin/build/themes':
38
      return '<p>'. t('Select which themes are available to your users and specify the default theme. To configure site-wide display settings, click the "configure" task above. Alternately, to override these settings in a specific theme, click the "configure" link for the corresponding theme. Note that different themes may have different regions available for rendering content like blocks. If you want consistency in what your users see, you may wish to enable only one theme.') .'</p>';
39
40
    case 'admin/build/themes/settings/'. $arg[4]:
      $reference = explode('.', $arg[4], 2);
41
      $theme = array_pop($reference);
42
      return '<p>'. t('These options control the display settings for the <code>%template</code> theme. When your site is displayed using this theme, these settings will be used. By clicking "Reset to defaults," you can choose to use the <a href="@global">global settings</a> for this theme.', array('%template' => $theme, '@global' => url('admin/build/themes/settings'))) .'</p>';
43
44
    case 'admin/build/themes/settings':
      return '<p>'. t('These options control the default display settings for your entire site, across all themes. Unless they have been overridden by a specific theme, these settings will be used.') .'</p>';
45
    case 'admin/build/modules':
46
47
48
49
50
51
52
      $output = '<p>'. t('Modules are plugins for Drupal that extend its core functionality. Here you can select which modules are enabled. Once a module is enabled, new <a href="@permissions">permissions</a> might be made available. Modules can automatically be temporarily disabled to reduce server load when your site becomes extremely busy by enabling the throttle.module and checking throttle.', array('@permissions' => url('admin/user/access')));
      if (module_exists('throttle')) {
        $output .= ' '. t('The auto-throttle functionality must be enabled on the <a href="@throttle">throttle configuration page</a> after having enabled the throttle module.', array('@throttle' => url('admin/settings/throttle')));
      }
      $output .= '</p>';
      $output .= t('<p>It is important that <a href="@update-php">update.php</a> is run every time a module is updated to a newer version.</p><p>You can find all administration tasks belonging to a particular module on the <a href="@by-module">administration by module page</a>.</p>', array('@update-php' => $base_url .'/update.php', '@by-module' => url('admin/by-module')));
      return $output;
53
    case 'admin/build/modules/uninstall':
54
      return '<p>'. t('The uninstall process removes all data related to a module. To uninstall a module, you must first disable it. Not all modules support this feature.') .'</p>';
55
56
57
58
59
60
61
    case 'admin/settings/actions':
    case 'admin/settings/actions/manage':
      $output = '<p>'. t('Actions are individual tasks that the system can do, such as unpublishing a piece of content or banning a user. Modules, such as the trigger module, can fire these actions when certain system events happen; for example, when a new post is added or when a user logs in. Modules may also provide additional actions.') .'</p>';
      $output .= '<p>'. t('There are two types of actions: simple and advanced. Simple actions do not require any additional configuration, and are listed here automatically. Advanced actions can do more than simple actions; for example, send an e-mail to a specified address, or check for certain words within a piece of content. These actions need to be created and configured first before they may be used. To create an advanced action, select the action from the drop-down below and click the <em>Create</em> button.') .'</p>';
      if (module_exists('trigger')) {
        $output .= '<p>'. t('You may proceed to the <a href="@url">Triggers</a> page to assign these actions to system events.', array('@url' => url('admin/build/trigger'))) .'</p>';
      }
62
      return $output;
63
64
    case 'admin/settings/actions/configure':
      return t('An advanced action offers additional configuration options which may be filled out below. Changing the <em>Description</em> field is recommended, in order to better identify the precise action taking place. This description will be displayed in modules such as the trigger module when assigning actions to system events, so it is best if it is as descriptive as possible (for example, "Send e-mail to Moderation Team" rather than simply "Send e-mail").');
65
    case 'admin/logs/status':
66
      return '<p>'. t("Here you can find a short overview of your Drupal site's parameters as well as any problems detected with your installation. It is useful to copy/paste this information when you need support.") .'</p>';
67
  }
Dries's avatar
   
Dries committed
68
69
}

70
71
72
73
function system_theme() {
  return array_merge(drupal_common_themes(), array(
    'system_theme_select_form' => array(
      'arguments' => array('form' => NULL),
74
      'file' => 'system.admin.inc',
75
76
77
    ),
    'system_themes_form' => array(
      'arguments' => array('form' => NULL),
78
      'file' => 'system.admin.inc',
79
80
81
    ),
    'system_modules' => array(
      'arguments' => array('form' => NULL),
82
      'file' => 'system.admin.inc',
83
84
85
    ),
    'system_modules_uninstall' => array(
      'arguments' => array('form' => NULL),
86
      'file' => 'system.admin.inc',
87
88
89
    ),
    'status_report' => array(
      'arguments' => array('requirements' => NULL),
90
      'file' => 'system.admin.inc',
91
92
93
    ),
    'admin_page' => array(
      'arguments' => array('blocks' => NULL),
94
      'file' => 'system.admin.inc',
95
96
97
    ),
    'admin_block' => array(
      'arguments' => array('block' => NULL),
98
      'file' => 'system.admin.inc',
99
100
101
    ),
    'admin_block_content' => array(
      'arguments' => array('content' => NULL),
102
      'file' => 'system.admin.inc',
103
104
105
    ),
    'system_admin_by_module' => array(
      'arguments' => array('menu_items' => NULL),
106
      'file' => 'system.admin.inc',
107
108
109
    ),
  ));
}
Dries's avatar
   
Dries committed
110
111
112
/**
 * Implementation of hook_perm().
 */
Dries's avatar
 
Dries committed
113
function system_perm() {
114
  return array('administer site configuration', 'access administration pages', 'administer actions', 'select different theme', 'administer files');
Dries's avatar
   
Dries committed
115
116
}

117
118
119
120
121
/**
 * Implementation of hook_elements().
 */
function system_elements() {
  // Top level form
122
  $type['form'] = array('#method' => 'post', '#action' => request_uri());
123
124

  // Inputs
125
126
127
128
129
  $type['submit'] = array('#input' => TRUE, '#name' => 'op', '#button_type' => 'submit', '#executes_submit_callback' => TRUE, '#process' => array('form_expand_ahah'));
  $type['button'] = array('#input' => TRUE, '#name' => 'op', '#button_type' => 'submit', '#executes_submit_callback' => FALSE, '#process' => array('form_expand_ahah'));
  $type['image_button'] = array('#input' => TRUE, '#button_type' => 'submit','#executes_submit_callback' => TRUE, '#process' => array('form_expand_ahah'), '#return_value' => TRUE, '#has_garbage_value' => TRUE, '#src' => NULL);
  $type['textfield'] = array('#input' => TRUE, '#size' => 60, '#maxlength' => 128, '#autocomplete_path' => FALSE, '#process' => array('form_expand_ahah'));
  $type['password'] = array('#input' => TRUE, '#size' => 60, '#maxlength' => 128, '#process' => array('form_expand_ahah'));
130
  $type['password_confirm'] = array('#input' => TRUE, '#process' => array('expand_password_confirm'));
131
  $type['textarea'] = array('#input' => TRUE, '#cols' => 60, '#rows' => 5, '#resizable' => TRUE, '#process' => array('form_expand_ahah'));
132
  $type['radios'] = array('#input' => TRUE, '#process' => array('expand_radios'));
133
  $type['radio'] = array('#input' => TRUE, '#default_value' => NULL, '#process' => array('form_expand_ahah'));
134
  $type['checkboxes'] = array('#input' => TRUE, '#process' => array('expand_checkboxes'), '#tree' => TRUE);
135
136
137
  $type['checkbox'] = array('#input' => TRUE, '#return_value' => 1, '#process' => array('form_expand_ahah'));
  $type['select'] = array('#input' => TRUE, '#size' => 0, '#multiple' => FALSE, '#process' => array('form_expand_ahah'));
  $type['weight'] = array('#input' => TRUE, '#delta' => 10, '#default_value' => 0, '#process' => array('process_weight', 'form_expand_ahah'));
138
  $type['date'] = array('#input' => TRUE, '#process' => array('expand_date'), '#element_validate' => array('date_validate'));
139
  $type['file'] = array('#input' => TRUE, '#size' => 60);
140
141

  // Form structure
142
  $type['item'] = array('#value' => '');
143
  $type['hidden'] = array('#input' => TRUE, '#process' => array('expand_ahah'));
144
145
  $type['value'] = array('#input' => TRUE);
  $type['markup'] = array('#prefix' => '', '#suffix' => '');
146
  $type['fieldset'] = array('#collapsible' => FALSE, '#collapsed' => FALSE, '#value' => NULL, '#process' => array('expand_ahah'));
Dries's avatar
Dries committed
147
  $type['token'] = array('#input' => TRUE);
148
149
150
  return $type;
}

Dries's avatar
   
Dries committed
151
/**
Dries's avatar
   
Dries committed
152
 * Implementation of hook_menu().
Dries's avatar
   
Dries committed
153
 */
154
155
function system_menu() {
  $items['system/files'] = array(
156
    'title' => 'File download',
157
158
159
160
161
    'page callback' => 'file_download',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  $items['admin'] = array(
162
    'title' => 'Administer',
163
164
165
    'access arguments' => array('access administration pages'),
    'page callback' => 'system_main_admin_page',
    'weight' => 9,
166
    'file' => 'system.admin.inc',
167
168
  );
  $items['admin/compact'] = array(
169
    'title' => 'Compact mode',
170
171
    'page callback' => 'system_admin_compact_page',
    'type' => MENU_CALLBACK,
172
    'file' => 'system.admin.inc',
173
174
  );
  $items['admin/by-task'] = array(
175
    'title' => 'By task',
176
    'page callback' => 'system_main_admin_page',
177
    'file' => 'system.admin.inc',
178
179
180
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['admin/by-module'] = array(
181
    'title' => 'By module',
182
    'page callback' => 'system_admin_by_module',
183
    'file' => 'system.admin.inc',
184
185
186
    'type' => MENU_LOCAL_TASK,
    'weight' => 2,
  );
187
188
189
190
191
192
193
194
195
196
  $items['admin/content'] = array(
    'title' => 'Content management',
    'description' => "Manage your site's content.",
    'position' => 'left',
    'weight' => -10,
    'page callback' => 'system_admin_menu_block_page',
    'access arguments' => array('access administration pages'),
    'file' => 'system.admin.inc',
  );

197
198
  // menu items that are basically just menu blocks
  $items['admin/settings'] = array(
199
200
    'title' => 'Site configuration',
    'description' => 'Adjust basic site configuration options.',
201
202
203
204
    'position' => 'right',
    'weight' => -5,
    'page callback' => 'system_settings_overview',
    'access arguments' => array('administer site configuration'),
205
    'file' => 'system.admin.inc',
206
207
  );
  $items['admin/build'] = array(
208
209
    'title' => 'Site building',
    'description' => 'Control how your site looks and feels.',
210
211
212
213
    'position' => 'right',
    'weight' => -10,
    'page callback' => 'system_admin_menu_block_page',
    'access arguments' => array('administer site configuration'),
214
    'file' => 'system.admin.inc',
215
216
  );
  $items['admin/settings/admin'] = array(
217
218
    'title' => 'Administration theme',
    'description' => 'Settings for how your administrative pages should look.',
219
220
221
222
    'position' => 'left',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_admin_theme_settings'),
    'block callback' => 'system_admin_theme_settings',
223
    'file' => 'system.admin.inc',
224
225
226
  );
  // Themes:
  $items['admin/build/themes'] = array(
227
228
    'title' => 'Themes',
    'description' => 'Change which theme your site uses or allows users to set.',
229
    'page callback' => 'drupal_get_form',
230
    'page arguments' => array('system_themes_form', NULL),
231
    'file' => 'system.admin.inc',
232
233
  );
  $items['admin/build/themes/select'] = array(
234
235
    'title' => 'List',
    'description' => 'Select the default theme.',
236
237
238
239
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -1,
  );
  $items['admin/build/themes/settings'] = array(
240
    'title' => 'Configure',
241
    'page arguments' => array('system_theme_settings'),
242
243
244
245
    'type' => MENU_LOCAL_TASK,
  );
  // Theme configuration subtabs
  $items['admin/build/themes/settings/global'] = array(
246
    'title' => 'Global settings',
247
248
249
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -1,
  );
Dries's avatar
   
Dries committed
250

251
252
253
  foreach (list_themes() as $theme) {
    if ($theme->status) {
      $items['admin/build/themes/settings/'. $theme->name] = array(
254
        'title' => $theme->info['name'],
255
256
257
        'page arguments' => array('system_theme_settings', $theme->name),
        'type' => MENU_LOCAL_TASK,
      );
Dries's avatar
   
Dries committed
258
    }
Dries's avatar
   
Dries committed
259
  }
drumm's avatar
drumm committed
260

261
262
  // Modules:
  $items['admin/build/modules'] = array(
263
264
    'title' => 'Modules',
    'description' => 'Enable or disable add-on modules for your site.',
265
266
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_modules'),
267
    'file' => 'system.admin.inc',
268
269
  );
  $items['admin/build/modules/list'] = array(
270
    'title' => 'List',
271
272
273
    'type' => MENU_DEFAULT_LOCAL_TASK,
  );
  $items['admin/build/modules/list/confirm'] = array(
274
    'title' => 'List',
275
276
277
    'type' => MENU_CALLBACK,
  );
  $items['admin/build/modules/uninstall'] = array(
278
    'title' => 'Uninstall',
279
280
281
282
    'page arguments' => array('system_modules_uninstall'),
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/build/modules/uninstall/confirm'] = array(
283
    'title' => 'Uninstall',
284
285
    'type' => MENU_CALLBACK,
  );
Dries's avatar
   
Dries committed
286

287
  // Actions:
288
  $items['admin/settings/actions'] = array(
289
290
291
292
293
    'title' => 'Actions',
    'description' => 'Manage the actions defined for your site.',
    'access arguments' => array('administer actions'),
    'page callback' => 'system_actions_manage'
  );
294
  $items['admin/settings/actions/manage'] = array(
295
296
297
298
299
300
    'title' => 'Manage actions',
    'description' => 'Manage the actions defined for your site.',
    'page callback' => 'system_actions_manage',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -2,
  );
301
302
  $items['admin/settings/actions/configure'] = array(
    'title' => 'Configure an advanced action',
303
304
305
306
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_actions_configure'),
    'type' => MENU_CALLBACK,
  );
307
  $items['admin/settings/actions/delete/%actions'] = array(
308
309
310
311
312
313
    'title' => 'Delete action',
    'description' => 'Delete an action.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_actions_delete_form', 4),
    'type' => MENU_CALLBACK,
  );
314
  $items['admin/settings/actions/orphan'] = array(
315
316
317
318
319
    'title' => 'Remove orphans',
    'page callback' => 'system_actions_remove_orphans',
    'type' => MENU_CALLBACK,
  );

320
321
  // Settings:
  $items['admin/settings/site-information'] = array(
322
323
    'title' => 'Site information',
    'description' => 'Change basic site information, such as the site name, slogan, e-mail address, mission, front page and more.',
324
325
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_site_information_settings'),
326
    'file' => 'system.admin.inc',
327
328
  );
  $items['admin/settings/error-reporting'] = array(
329
330
    'title' => 'Error reporting',
    'description' => 'Control how Drupal deals with errors including 403/404 errors as well as PHP error reporting.',
331
332
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_error_reporting_settings'),
333
    'file' => 'system.admin.inc',
334
  );
335
  $items['admin/settings/logging'] = array(
336
337
    'title' => 'Logging and alerts',
    'description' => "Settings for logging and alerts modules. Various modules can route Drupal's system events to different destination, such as syslog, database, email, ...etc.",
338
    'page callback' => 'system_logging_overview',
339
    'file' => 'system.admin.inc',
340
  );
341
  $items['admin/settings/performance'] = array(
342
    'title' => 'Performance',
343
    'description' => 'Enable or disable page caching for anonymous users and set CSS and JS bandwidth optimization options.',
344
345
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_performance_settings'),
346
    'file' => 'system.admin.inc',
347
348
  );
  $items['admin/settings/file-system'] = array(
349
350
    'title' => 'File system',
    'description' => 'Tell Drupal where to store uploaded files and how they are accessed.',
351
352
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_file_system_settings'),
353
    'file' => 'system.admin.inc',
354
355
  );
  $items['admin/settings/image-toolkit'] = array(
356
357
    'title' => 'Image toolkit',
    'description' => 'Choose which image toolkit to use if you have installed optional toolkits.',
358
359
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_image_toolkit_settings'),
360
    'file' => 'system.admin.inc',
361
362
  );
  $items['admin/content/rss-publishing'] = array(
363
364
    'title' => 'RSS publishing',
    'description' => 'Configure the number of items per feed and whether feeds should be titles/teasers/full-text.',
365
366
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_rss_feeds_settings'),
367
    'access arguments' => array('administer site configuration'),
368
    'file' => 'system.admin.inc',
369
370
  );
  $items['admin/settings/date-time'] = array(
371
372
    'title' => 'Date and time',
    'description' => "Settings for how Drupal displays date and time, as well as the system's default timezone.",
373
374
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_date_time_settings'),
375
    'file' => 'system.admin.inc',
376
  );
377
378
379
380
  $items['admin/settings/date-time/lookup'] = array(
    'title' => t('Date and time lookup'),
    'type' => MENU_CALLBACK,
    'page callback' => 'system_date_time_lookup',
381
    'file' => 'system.admin.inc',
382
  );
383
  $items['admin/settings/site-maintenance'] = array(
384
385
    'title' => 'Site maintenance',
    'description' => 'Take the site off-line for maintenance or bring it back online.',
386
387
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_site_maintenance_settings'),
388
    'file' => 'system.admin.inc',
389
390
  );
  $items['admin/settings/clean-urls'] = array(
391
392
    'title' => 'Clean URLs',
    'description' => 'Enable or disable clean URLs for your site.',
393
394
    'page callback' => 'drupal_get_form',
    'page arguments' => array('system_clean_url_settings'),
395
    'file' => 'system.admin.inc',
396
397
398
399
  );

  // Logs:
  $items['admin/logs'] = array(
400
401
    'title' => 'Logs',
    'description' => 'View system logs and other status information.',
402
403
404
    'page callback' => 'system_admin_menu_block_page',
    'weight' => 5,
    'position' => 'left',
405
    'file' => 'system.admin.inc',
406
407
  );
  $items['admin/logs/status'] = array(
408
409
    'title' => 'Status report',
    'description' => "Get a status report about your site's operation and any detected problems.",
410
411
412
    'page callback' => 'system_status',
    'weight' => 10,
    'access arguments' => array('administer site configuration'),
413
    'file' => 'system.admin.inc',
414
415
  );
  $items['admin/logs/status/run-cron'] = array(
416
    'title' => 'Run cron',
417
418
    'page callback' => 'system_run_cron',
    'type' => MENU_CALLBACK,
419
    'file' => 'system.admin.inc',
420
421
  );
  $items['admin/logs/status/php'] = array(
422
    'title' => 'PHP',
423
424
    'page callback' => 'system_php',
    'type' => MENU_CALLBACK,
425
    'file' => 'system.admin.inc',
426
427
  );
  $items['admin/logs/status/sql'] = array(
428
    'title' => 'SQL',
429
430
    'page callback' => 'system_sql',
    'type' => MENU_CALLBACK,
431
    'file' => 'system.admin.inc',
432
  );
433
434
435
436
437
  // Default page for batch operations
  $items['batch'] = array(
    'page callback' => 'system_batch_page',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
438
    'file' => 'system.admin.inc',
439
  );
Dries's avatar
   
Dries committed
440
  return $items;
Dries's avatar
 
Dries committed
441
442
}

443
444
function system_init() {
  // Use the administrative theme if the user is looking at a page in the admin/* path.
445
  if (arg(0) == 'admin' || (variable_get('node_admin_theme', '0') && arg(0) == 'node' && (arg(1) == 'add' || arg(2) == 'edit'))) {
446
447
448
449
450
451
452
453
    global $custom_theme;
    $custom_theme = variable_get('admin_theme', '0');
    drupal_add_css(drupal_get_path('module', 'system') .'/admin.css', 'module');
  }

  // Add the CSS for this module.
  drupal_add_css(drupal_get_path('module', 'system') .'/defaults.css', 'module');
  drupal_add_css(drupal_get_path('module', 'system') .'/system.css', 'module');
454
  drupal_add_css(drupal_get_path('module', 'system') .'/system-menus.css', 'module');
455
456
}

Dries's avatar
   
Dries committed
457
458
459
460
461
/**
 * Implementation of hook_user().
 *
 * Allows users to individually set their theme and time zone.
 */
462
function system_user($type, $edit, &$user, $category = NULL) {
Dries's avatar
Dries committed
463
  if ($type == 'form' && $category == 'account') {
464
    $form['theme_select'] = system_theme_select_form(t('Selecting a different theme will change the look and feel of the site.'), isset($edit['theme']) ? $edit['theme'] : NULL, 2);
Dries's avatar
Dries committed
465

466
    if (variable_get('configurable_timezones', 1)) {
Steven Wittens's avatar
Steven Wittens committed
467
      $zones = _system_zonelist();
468
      $form['timezone'] = array(
469
        '#type' => 'fieldset',
470
471
472
473
        '#title' => t('Locale settings'),
        '#weight' => 6,
        '#collapsible' => TRUE,
      );
474
      $form['timezone']['timezone'] = array(
475
476
477
478
479
        '#type' => 'select',
        '#title' => t('Time zone'),
        '#default_value' => strlen($edit['timezone']) ? $edit['timezone'] : variable_get('date_default_timezone', 0),
        '#options' => $zones,
        '#description' => t('Select your current local time. Dates and times throughout this site will be displayed using this time zone.'),
480
      );
Dries's avatar
   
Dries committed
481
    }
Dries's avatar
Dries committed
482

483
    return $form;
Dries's avatar
   
Dries committed
484
  }
Dries's avatar
   
Dries committed
485
486
}

487
488
489
/**
 * Provide a single block on the administration overview page.
 */
490
function system_admin_menu_block($item) {
491
  $content = array();
492
  if (!isset($item['mlid'])) {
493
    $item += db_fetch_array(db_query("SELECT mlid, menu_name FROM {menu_links} ml WHERE ml.router_path = '%s' AND module = 'system'", $item['path']));
494
  }
495
  $result = db_query("
496
    SELECT m.*, ml.*
497
498
    FROM {menu_links} ml
    INNER JOIN {menu_router} m ON ml.router_path = m.path
499
    WHERE ml.plid = %d AND ml.menu_name = '%s' AND hidden = 0", $item['mlid'], $item['menu_name']);
500
  while ($item = db_fetch_array($result)) {
501
    _menu_link_translate($item);
502
    if (!$item['access']) {
503
      continue;
504
    }
505
506
507
508
509
510
511
512
    // The link 'description' either derived from the hook_menu 'description' or
    // entered by the user via menu module is saved as the title attribute.
    if (!empty($item['options']['attributes']['title'])) {
      $item['description'] = $item['options']['attributes']['title'];
    }
    // Prepare for sorting as in function _menu_tree_check_access().
    // The weight is offset so it is always positive, with a uniform 5-digits.
    $content[(50000 + $item['weight']) .' '. $item['title'] .' '. $item['mlid']] = $item;
513
  }
514
  ksort($content);
515
516
517
518
  return $content;
}


519
function system_admin_theme_submit($form, &$form_state) {
520
  // If we're changing themes, make sure the theme has its blocks initialized.
521
  if ($form_state['values']['admin_theme'] && $form_state['values']['admin_theme'] != variable_get('admin_theme', '0')) {
522
523
    $result = db_result(db_query("SELECT COUNT(*) FROM {blocks} WHERE theme = '%s'", $form_state['values']['admin_theme']));
    if (!$result) {
524
      system_initialize_theme_blocks($form_state['values']['admin_theme']);
525
526
527
528
    }
  }
}

529
/**
530
531
532
533
534
535
536
537
538
539
540
 * Returns a fieldset containing the theme select form.
 *
 * @param $description
 *    description of the fieldset
 * @param $default_value
 *    default value of theme radios
 * @param $weight
 *    weight of the fieldset
 * @return
 *    a form array
 */
541
function system_theme_select_form($description = '', $default_value = '', $weight = 0) {
542
  if (user_access('select different theme')) {
543
    $enabled = array();
544
545
546
    $themes = list_themes();

    foreach ($themes as $theme) {
547
548
549
550
551
552
553
554
555
      if ($theme->status) {
        $enabled[] = $theme;
      }
    }

    if (count($enabled) > 1) {
      ksort($enabled);

      $form['themes'] = array(
Dries's avatar
Dries committed
556
557
558
559
        '#type' => 'fieldset',
        '#title' => t('Theme configuration'),
        '#description' => $description,
        '#collapsible' => TRUE,
560
561
562
563
564
        '#theme' => 'system_theme_select_form'
      );

      foreach ($enabled as $info) {
        // For the default theme, revert to an empty string so the user's theme updates when the site theme is changed.
565
        $info->key = $info->name == variable_get('theme_default', 'garland') ? '' : $info->name;
566

567
568
569
570
571
572
573
574
575
576
577
        $screenshot = NULL;
        $theme_key = $info->name;
        while ($theme_key) {
          if (file_exists($themes[$theme_key]->info['screenshot'])) {
            $screenshot = $themes[$theme_key]->info['screenshot'];
            break;
          }
          $theme_key = isset($themes[$theme_key]->info['base theme']) ? $themes[$theme_key]->info['base theme'] : NULL;
        }

        $screenshot = $screenshot ? theme('image', $screenshot, t('Screenshot for %theme theme', array('%theme' => $info->name)), '', array('class' => 'screenshot'), FALSE) : t('no screenshot');
578

579
        $form['themes'][$info->key]['screenshot'] = array('#value' => $screenshot);
580
        $form['themes'][$info->key]['description'] = array('#type' => 'item', '#title' => $info->name,  '#value' => dirname($info->filename) . ($info->name == variable_get('theme_default', 'garland') ? '<br /> <em>'. t('(site default theme)') .'</em>' : ''));
581
582
583
584
585
586
587
588
589
590
        $options[$info->key] = '';
      }

      $form['themes']['theme'] = array('#type' => 'radios', '#options' => $options, '#default_value' => $default_value ? $default_value : '');
      $form['#weight'] = $weight;
      return $form;
    }
  }
}

591
592
/**
 * Checks the existence of the directory specified in $form_element. This
Dries's avatar
Dries committed
593
 * function is called from the system_settings form to check both the
594
595
596
597
598
599
600
 * file_directory_path and file_directory_temp directories. If validation
 * fails, the form element is flagged with an error from within the
 * file_check_directory function.
 *
 * @param $form_element
 *   The form element containing the name of the directory to check.
 */
601
function system_check_directory($form_element) {
602
603
604
605
  file_check_directory($form_element['#value'], FILE_CREATE_DIRECTORY, $form_element['#parents'][0]);
  return $form_element;
}

Dries's avatar
   
Dries committed
606
607
608
609
/**
 * Retrieves the current status of an array of files in the system table.
 */
function system_get_files_database(&$files, $type) {
Dries's avatar
   
Dries committed
610
  // Extract current files from database.
611
  $result = db_query("SELECT filename, name, type, status, throttle, schema_version FROM {system} WHERE type = '%s'", $type);
Dries's avatar
   
Dries committed
612
  while ($file = db_fetch_object($result)) {
613
    if (isset($files[$file->name]) && is_object($files[$file->name])) {
614
      $file->old_filename = $file->filename;
Dries's avatar
   
Dries committed
615
      foreach ($file as $key => $value) {
616
        if (!isset($files[$file->name]) || !isset($files[$file->name]->$key)) {
Dries's avatar
Dries committed
617
618
          $files[$file->name]->$key = $value;
        }
Dries's avatar
   
Dries committed
619
      }
620
    }
Dries's avatar
 
Dries committed
621
  }
Dries's avatar
   
Dries committed
622
}
Dries's avatar
 
Dries committed
623

624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
function system_theme_default() {
  // Prepare defaults for themes.
  return array(
    'regions' => array(
      'left' => 'Left sidebar',
      'right' => 'Right sidebar',
      'content' => 'Content',
      'header' => 'Header',
      'footer' => 'Footer',
    ),
    'description' => '',
    'features' => array(
      'comment_user_picture',
      'favicon',
      'mission',
      'logo',
      'name',
      'node_user_picture',
      'search',
643
644
645
      'slogan',
      'primary_links',
      'secondary_links',
646
    ),
647
648
649
650
    'stylesheets' => array(
      'all' => array('style.css')
    ),
    'scripts' => array('script.js'),
651
    'screenshot' => 'screenshot.png',
652
    'php' => DRUPAL_MINIMUM_PHP,
653
654
655
  );
}

Dries's avatar
   
Dries committed
656
657
658
/**
 * Collect data about all currently available themes
 */
Dries's avatar
Dries committed
659
660
function system_theme_data() {
  // Find themes
661
  $themes = drupal_system_listing('\.info$', 'themes');
Dries's avatar
Dries committed
662

Dries's avatar
   
Dries committed
663
  // Find theme engines
664
  $engines = drupal_system_listing('\.engine$', 'themes/engines');
Dries's avatar
Dries committed
665
666

  // Remove all theme engines from the system table
667
  db_query("DELETE FROM {system} WHERE type = '%s'", 'theme_engine');
Dries's avatar
   
Dries committed
668
669

  foreach ($engines as $engine) {
Dries's avatar
   
Dries committed
670
    // Insert theme engine into system table
Dries's avatar
Dries committed
671
672
673
    drupal_get_filename('theme_engine', $engine->name, $engine->filename);
    drupal_load('theme_engine', $engine->name);
    db_query("INSERT INTO {system} (name, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', %d, %d, %d)", $engine->name, 'theme_engine', $engine->filename, 1, 0, 0);
674
  }
Dries's avatar
Dries committed
675

676
  $defaults = system_theme_default();
677

678
679
680
681
  $sub_themes = array();
  // Read info files for each theme
  foreach ($themes as $key => $theme) {
    $themes[$key]->info = drupal_parse_info_file($theme->filename) + $defaults;
682
683
684
685
686

    // Invoke hook_system_info_alter() to give installed modules a chance to
    // modify the data in the .info files if necessary.
    drupal_alter('system_info', $themes[$key]->info, $themes[$key]);

687
688
689
690
691
692
693
694
    if (!empty($themes[$key]->info['base theme'])) {
      $sub_themes[] = $key;
    }
    if (empty($themes[$key]->info['engine'])) {
      $filename = dirname($themes[$key]->filename) .'/'. $themes[$key]->name .'.theme';
      if (file_exists($filename)) {
        $themes[$key]->owner = $filename;
        $themes[$key]->prefix = $key;
Dries's avatar
   
Dries committed
695
      }
Dries's avatar
   
Dries committed
696
    }
697
698
699
700
701
702
703
704
705
    else {
      $engine = $themes[$key]->info['engine'];
      if (isset($engines[$engine])) {
        $themes[$key]->owner = $engines[$engine]->filename;
        $themes[$key]->prefix = $engines[$engine]->name;
        $themes[$key]->template = TRUE;
      }
    }

706
707
708
709
710
711
    // Give the stylesheets proper path information.
    $pathed_stylesheets = array();
    foreach ($themes[$key]->info['stylesheets'] as $media => $stylesheets) {
      foreach ($stylesheets as $stylesheet) {
        $pathed_stylesheets[$media][$stylesheet] = dirname($themes[$key]->filename) .'/'. $stylesheet;
      }
712
    }
713
    $themes[$key]->info['stylesheets'] = $pathed_stylesheets;
Dries's avatar
Dries committed
714

715
716
717
718
    // Give the scripts proper path information.
    $scripts = array();
    foreach ($themes[$key]->info['scripts'] as $script) {
      $scripts[$script] = dirname($themes[$key]->filename) .'/'. $script;
719
    }
720
    $themes[$key]->info['scripts'] = $scripts;
721
722
723
724
    // Give the screenshot proper path information.
    if (!empty($themes[$key]->info['screenshot'])) {
      $themes[$key]->info['screenshot'] = dirname($themes[$key]->filename) .'/'. $themes[$key]->info['screenshot'];
    }
Dries's avatar
   
Dries committed
725
726
  }

727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
  // Now that we've established all our master themes, go back and fill in
  // data for subthemes.
  foreach ($sub_themes as $key) {
    $base_key = system_find_base_theme($themes, $key);
    if (!$base_key) {
      continue;
    }
    // Copy the 'owner' and 'engine' over if the top level theme uses a
    // theme engine.
    if (isset($themes[$base_key]->owner)) {
      if (isset($themes[$base_key]->info['engine'])) {
        $themes[$key]->info['engine'] = $themes[$base_key]->info['engine'];
        $themes[$key]->owner = $themes[$base_key]->owner;
        $themes[$key]->prefix = $themes[$base_key]->prefix;
      }
      else {
        $themes[$key]->prefix = $key;
Dries's avatar
   
Dries committed
744
745
      }
    }
Dries's avatar
   
Dries committed
746
  }
Dries's avatar
   
Dries committed
747
748

  // Extract current files from database.
Dries's avatar
Dries committed
749
750
751
  system_get_files_database($themes, 'theme');

  db_query("DELETE FROM {system} WHERE type = 'theme'");
Dries's avatar
   
Dries committed
752

Dries's avatar
Dries committed
753
  foreach ($themes as $theme) {
754
755
756
757
    if (!isset($theme->owner)) {
      $theme->owner = '';
    }

758
    db_query("INSERT INTO {system} (name, owner, info, type, filename, status, throttle, bootstrap) VALUES ('%s', '%s', '%s', '%s', '%s', %d, %d, %d)", $theme->name, $theme->owner, serialize($theme->info), 'theme', $theme->filename, isset($theme->status) ? $theme->status : 0, 0, 0);
Dries's avatar
Dries committed
759
760
761
762
763
  }

  return $themes;
}

764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
/**
 * Recursive function to find the top level base theme. Themes can inherit
 * templates and function implementations from earlier themes; this function
 * finds the top level parent that has no ancestor, or returns NULL if there
 * isn't a valid parent.
 */
function system_find_base_theme($themes, $key, $used_keys = array()) {
  $base_key = $themes[$key]->info['base theme'];
  // Does the base theme exist?
  if (!isset($themes[$base_key])) {
    return NULL;
  }

  // Is the base theme itself a child of another theme?
  if (isset($themes[$base_key]->info['base theme'])) {
    // Prevent loops.
780
    if (!empty($used_keys[$base_key])) {
781
782
783
784
785
786
787
788
789
      return NULL;
    }
    $used_keys[$base_key] = TRUE;
    return system_find_base_theme($themes, $base_key, $used_keys);
  }
  // If we get here, then this is our parent theme.
  return $base_key;
}

790
791
792
/**
 * Get a list of available regions from a specified theme.
 *
793
 * @param $theme_key
794
795
796
797
 *   The name of a theme.
 * @return
 *   An array of regions in the form $region['name'] = 'description'.
 */
798
function system_region_list($theme_key) {
799
800
  static $list = array();

801
  if (!array_key_exists($theme_key, $list)) {
802
803
    $info = unserialize(db_result(db_query("SELECT info FROM {system} WHERE type = 'theme' AND name = '%s'", $theme_key)));
    $list[$theme_key] = array_map('t', $info['regions']);
804
805
  }

806
  return $list[$theme_key];
807
808
809
810
811
812
813
814
815
816
817
818
}

/**
 * Get the name of the default region for a given theme.
 *
 * @param $theme
 *   The name of a theme.
 * @return
 *   A string that is the region name.
 */
function system_default_region($theme) {
  $regions = array_keys(system_region_list($theme));
819
  return isset($regions[0]) ? $regions[0] : '';
820
821
}

Dries's avatar
   
Dries committed
822
/**
823
824
 * Assign an initial, default set of blocks for a theme.
 *
825
 * This function is called the first time a new theme is enabled. The new theme
826
827
828
829
830
831
832
833
834
 * gets a copy of the default theme's blocks, with the difference that if a
 * particular region isn't available in the new theme, the block is assigned
 * to the new theme's default region.
 *
 * @param $theme
 *   The name of a theme.
 */
function system_initialize_theme_blocks($theme) {
  // Initialize theme's blocks if none already registered.
835
  if (!(db_result(db_query("SELECT COUNT(*) FROM {blocks} WHERE theme = '%s'", $theme)))) {
836
    $default_theme = variable_get('theme_default', 'garland');
837
838
    $regions = system_region_list($theme);
    $result = db_query("SELECT * FROM {blocks} WHERE theme = '%s'", $default_theme);
839
    while ($block = db_fetch_array($result)) {
840
841
842
843
      // If the region isn't supported by the theme, assign the block to the theme's default region.
      if (!array_key_exists($block['region'], $regions)) {
        $block['region'] = system_default_region($theme);
      }
844
845
      db_query("INSERT INTO {blocks} (module, delta, theme, status, weight, region, visibility, pages, custom, throttle, cache) VALUES ('%s', '%s', '%s', %d, %d, '%s', %d, '%s', %d, %d, %d)",
          $block['module'], $block['delta'], $theme, $block['status'], $block['weight'], $block['region'], $block['visibility'], $block['pages'], $block['custom'], $block['throttle'], $block['cache']);
846
847
848
849
    }
  }
}

850
851
852
853
/**
 * Add default buttons to a form and set its prefix
 */
function system_settings_form($form) {
854
855
  $form['buttons']['submit'] = array('#type' => 'submit', '#value' => t('Save configuration') );
  $form['buttons']['reset'] = array('#type' => 'submit', '#value' => t('Reset to defaults') );
856

857
  if (!empty($_POST) && form_get_errors()) {
858
    drupal_set_message(t('The settings have not been saved because of the errors.'), 'error');
859
  }
860
861
  $form['#submit'][] = 'system_settings_form_submit';
  $form['#validate'][] = 'system_settings_form_validate';
862
  $form['#theme'] = 'system_settings_form';
863
  return $form;
864
865
}

866

Steven Wittens's avatar
Steven Wittens committed
867

868
869
870
/**
 * Execute the system_settings_form.
 *
871
872
873
 * If you want node type configure style handling of your checkboxes,
 * add an array_filter value to your form.
 *
874
 */
875
876
function system_settings_form_submit($form, &$form_state) {
  $op = isset($form_state['values']['op']) ? $form_state['values']['op'] : '';
877

878
  // Exclude unnecessary elements.
879
  unset($form_state['values']['submit'], $form_state['values']['reset'], $form_state['values']['form_id'], $form_state['values']['op'], $form_state['values']['form_token']);
880

881
  foreach ($form_state['values'] as $key => $value) {
882
883
884
885
    if ($op == t('Reset to defaults')) {
      variable_del($key);
    }
    else {
886
      if (is_array($value) && isset($form_state['values']['array_filter'])) {
887
888
889
890
891
892
893
        $value = array_keys(array_filter($value));
      }
      variable_set($key, $value);
    }
  }
  if ($op == t('Reset to defaults')) {
    drupal_set_message(t('The configuration options have been reset to their default values.'));
894
895
  }
  else {
896
897
    drupal_set_message(t('The configuration options have been saved.'));
  }
898

899
  drupal_rebuild_theme_registry();
900
901
902
}

/**
903
 * Helper function to sort requirements.
904
 */
905
906
907
908
function _system_sort_requirements($a, $b) {
  if (!isset($a['weight'])) {
    if (!isset($b['weight'])) {
      return strcmp($a['title'], $b['title']);
909
    }
910
    return -$b['weight'];
911
  }
912
  return isset($b['weight']) ? $a['weight'] - $b['weight'] : $a['weight'];
913
914
}

915
916
917
918
919
920
921
922
923
/**
 * Implementation of hook_node_type().
 *
 * Updates theme settings after a node type change.
 */
function system_node_type($op, $info) {
  if ($op == 'update' && !empty($info->old_type) && $info->type != $info->old_type) {
    $old = 'toggle_node_info_'. $info->old_type;
    $new = 'toggle_node_