/** connect this module to a node * * this makes the link between the node $node_id in area $area_id and this module. * In this case we simply link a single 'variant' parameter to node $node_id in a * 1-to-1 relation. * * Note that we set the parameter 'variant' to 1. This equates to the variant * where the visitor starts with the title, the optional introductory text and the * thumbnail overview. It is up to the user to configure the node to use other * variants, eg. start at the first picture full-size or display a slide show. * Also note that we start off with an (arbitrary) dimension for the full-size * snapshots. This is a per-node setting (as opposed to the systemwide setting * for thumbnail dimensions). * Finally, we do a little heuristics here by plugging in the current directory * from the filemanager. This is dirty, but we might assume that the user * uploaded the files to a directory just before adding this snapshots node. * In that case there is no need to change anything re: path. * If the user did NOT upload files, we plug in the name of the directory * which is associated with area $area_id. * * @param object &$output collects the html output (if any) * @param int $area_id the area in which $node_id resides * @param int $node_id the node to which we need to connect * @param array $module the module record straight from the database * @return bool TRUE on success, FALSE otherwise */ function snapshots_connect(&$output, $area_id, $node_id, $module) { global $USER; $now = strftime('%Y-%m-%d %T'); $areas = get_area_records(); $path = isset($_SESSION['current_directory']) ? $_SESSION['current_directory'] : (isset($areas[$area_id]) ? '/areas/' . $areas[$area_id]['path'] : ''); unset($areas); $fields = array('node_id' => intval($node_id), 'header' => '', 'introduction' => '', 'snapshots_path' => $path, 'variant' => 1, 'dimension' => 512, 'ctime' => $now, 'cuser_id' => $USER->user_id, 'mtime' => $now, 'muser_id' => $USER->user_id); $retval = db_insert_into('snapshots', $fields); if ($retval !== 1) { logger(sprintf('%s(): cannot connect snapshots to node \'%d\': %s', __FUNCTION__, $node_id, db_errormessage())); $retval = FALSE; } else { $retval = TRUE; } return $retval; }
/** display the content of the sitemap linked to node $node_id * * there are three different variations (depends on configuration parameter 'scope'): * * - 0 (small): only show a map of the tree in the current area $area_id * - 1 (medium): show a list of available areas followed by the map of the current area $area_id * - 2 (large): show the maps of all available areas * * The default is 0 (small). * * @param object &$theme collects the (html) output * @param int $area_id identifies the area where $node_id lives * @param int $node_id the node to which this module is connected * @param array $module the module record straight from the database * @return bool TRUE on success + output via $theme, FALSE otherwise */ function sitemap_view(&$theme, $area_id, $node_id, $module) { global $USER; // // 1 -- determine scope of sitemap: 0=small, 1=medium, 2=large // $table = 'sitemaps'; $fields = array('header', 'introduction', 'scope'); $where = array('node_id' => intval($node_id)); $record = db_select_single_record($table, $fields, $where); if ($record === FALSE) { logger(sprintf('%s(): error retrieving configuration: %s', __FUNCTION__, db_errormessage())); $scope = 0; $header = ''; $introduction = ''; } else { $scope = intval($record['scope']); $header = trim($record['header']); $introduction = trim($record['introduction']); } // // 2 -- compute a list of areas to process (could be just 1) // // 2A -- retrieve all areas, including those out of bounds for this user if (($all_areas = get_area_records()) === FALSE) { logger(sprintf('%s(): huh? cannot get area records: %s', __FUNCTION__, db_errormessage())); return FALSE; // shouldn't happen } // 2B -- narrow down the selection (active, (private) access allowed, within scope) $areas = array(); foreach ($all_areas as $id => $area) { if (db_bool_is(TRUE, $area['is_active']) && (db_bool_is(FALSE, $area['is_private']) || $USER->has_intranet_permissions(ACL_ROLE_INTRANET_ACCESS, $id))) { if ($scope == 2 || $scope == 1 || $scope == 0 && $id == $area_id) { $title = $area['title']; $params = array('area' => $id); $href = was_node_url(NULL, $params, $title, $theme->preview_mode); $areas[$id] = html_a($href, NULL, NULL, $title); } } } unset($all_areas); // $areas now holds all areas that we should to process if (sizeof($areas) <= 0) { logger(sprintf('%s(): weird, no areas to process; bailing out', __FUNCTION__)); return FALSE; // shouldn't happen } // // 3 -- maybe output a header and an introduction // if (!empty($header)) { $theme->add_content('<h2>' . $header . '</h2>'); } if (!empty($introduction)) { $theme->add_content($introduction); } // // 4 - Actually output a sitemap by walking the tree once for every elegible area // foreach ($areas as $id => $area_anchor) { if ($scope == 1 && $area_id != $id) { // 1=medium only shows area map of $area_id (and an area list lateron) continue; } // 4A -- output a clickable area title $theme->add_content('<h2>' . $area_anchor . '</h2>'); // 4B -- fetch the tree for this area... $tree = tree_build($id); tree_visibility($tree[0]['first_child_id'], $tree); // 4C -- ...and walk the tree sitemap_tree_walk($theme, $tree[0]['first_child_id'], $tree); unset($tree); } if ($scope == 1) { $theme->add_content('<h2>' . t('sitemap_available_areas', 'm_sitemap') . '</h2>'); $theme->add_content('<ul>'); foreach ($areas as $id => $area_anchor) { $theme->add_content('<li>' . $area_anchor); } $theme->add_content('</ul>'); } return TRUE; // indicate success }
/** validate and save modified data to database * * this saves data from both the edit and the edit theme dialog if data validates. * If the data does NOT validate, the edit screen is displayed again * otherwise the area overview is displayed again. * * @return void results are returned as output in $this->output * @uses $WAS_SCRIPT_NAME * @uses $CFG * @uses $USER */ function area_save() { global $CFG, $WAS_SCRIPT_NAME, $USER; $area_id = get_parameter_int('area', 0); $areas = get_area_records(); // 0 - basic sanity if ($areas === FALSE || !isset($areas[$area_id])) { // are they trying to trick us, specifying an invalid area? logger("areamanager: weird: user tried to save data to non-existing area '{$area_id}'"); $this->output->add_message(t('invalid_area', 'admin', array('{AREA}' => strval($area_id)))); $this->area_overview(); return; } // 1 -- are we allowed to perform the edit and thus the save operation? if (!$USER->has_area_permissions(PERMISSION_AREA_EDIT_AREA, $area_id)) { logger("areamanager: user attempted to save data to area '{$area_id}' without permission"); $msg = t('icon_area_edit_access_denied', 'admin'); $this->output->add_message($msg); $this->output->add_popup_bottom($msg); $this->area_overview(); return; } // 2 -- if the user cancelled the operation, there is no point in hanging 'round if (isset($_POST['button_cancel'])) { $this->output->add_message(t('cancelled', 'admin')); $this->area_overview(); return; } // 3 -- we need to know which dialog we're dealing with if (!isset($_POST['dialog'])) { logger("areamanager: weird: 'dialog' not set in area_save() (area='{$area_id}')", WLOG_DEBUG); $this->area_overview(); return; } $dialog = intval($_POST['dialog']); if ($dialog == AREAMANAGER_DIALOG_EDIT_THEME) { $theme_id = $areas[$area_id]['theme_id']; $themes = $this->get_theme_records(); $theme_name = $themes[$theme_id]['name']; include_once $CFG->progdir . '/lib/configassistant.class.php'; $table = 'themes_areas_properties'; $keyfield = 'theme_area_property_id'; $prefix = ''; $language_domain = 't_' . $theme_name; $where = array('area_id' => $area_id, 'theme_id' => $theme_id); $hidden_fields = array(array('type' => F_INTEGER, 'name' => 'dialog', 'value' => AREAMANAGER_DIALOG_EDIT_THEME, 'hidden' => TRUE)); $assistant = new ConfigAssistant($table, $keyfield, $prefix, $language_domain, $where, $hidden_fields); if (!$assistant->save_data($this->output)) { $href = href($WAS_SCRIPT_NAME, $this->a_param(AREAMANAGER_CHORE_SAVE, $area_id)); $assistant->show_dialog($this->output, $href); // since they blew it, we will not show the edit menu at this point; // user should concentrate on getting input data right (or use cancel) } else { $this->area_overview(); } } elseif ($dialog == AREAMANAGER_DIALOG_EDIT) { $dialogdef = $this->get_dialogdef_edit_area($area_id); if (!dialog_validate($dialogdef)) { // there were errors, show them to the user and do it again foreach ($dialogdef as $k => $item) { if (isset($item['errors']) && $item['errors'] > 0) { $this->output->add_message($item['error_messages']); } } $this->output->add_content('<h2>' . t('areamanager_edit_area_header', 'admin') . '</h2>'); $this->output->add_content(t('areamanager_edit_area_explanation', 'admin')); $href = href($WAS_SCRIPT_NAME, $this->a_param(AREAMANAGER_CHORE_SAVE, $area_id)); $this->output->add_content(dialog_quickform($href, $dialogdef)); // no edit menu, let user concentrate on task at hand ie errorfree data input return; } $now = strftime('%Y-%m-%d %T'); $fields = array('mtime' => $now, 'muser_id' => $USER->user_id); $theme_id = 0; foreach ($dialogdef as $k => $item) { if (isset($item['name'])) { switch ($item['name']) { case 'area_title': $fields['title'] = $item['value']; break; // This field should not be editable and thus should not be saved //case 'area_is_private': // $fields['is_private'] = ($item['value'] == 1) ? TRUE : FALSE; // break; // This field should not be editable and thus should not be saved //case 'area_is_private': // $fields['is_private'] = ($item['value'] == 1) ? TRUE : FALSE; // break; case 'area_is_active': $fields['is_active'] = $item['value'] == 1 ? TRUE : FALSE; break; case 'area_theme_id': $theme_id = intval($item['value']); $fields['theme_id'] = $theme_id; break; // This field should not be editable and thus should not be saved //case 'area_path': // $fields['path'] = $item['value']; // break; // This field should not be editable and thus should not be saved //case 'area_path': // $fields['path'] = $item['value']; // break; case 'area_metadata': $fields['metadata'] = $item['value']; break; case 'area_sort_order': $fields['sort_order'] = intval($item['value']); break; default: break; } } } $where = array('area_id' => $area_id); $params = array('{AREA}' => $area_id, '{AREA_FULL_NAME}' => $fields['title']); if (db_update('areas', $fields, $where) === FALSE) { logger("areamanager: area data save failed for area '{$area_id}': " . db_errormessage()); $this->output->add_message(t('areamanager_save_area_failure', 'admin', $params)); } elseif (intval($areas[$area_id]['theme_id']) != $theme_id && $this->count_existing_theme_properties($area_id, $theme_id) <= 0) { // If the user changed the theme AND if there is no theme config yet, make sure there is one if ($this->reset_theme_defaults($area_id, $theme_id)) { logger("areamanager: success saving area AND theme properties in area '{$area_id}', theme '{$theme_id}'", WLOG_DEBUG); $this->output->add_message(t('areamanager_save_area_success', 'admin', $params)); } else { logger("areamanager: theme '{$theme_id}' data save failed for area '{$area_id}': " . db_errormessage()); $this->output->add_message(t('areamanager_save_area_failure', 'admin', $params)); } } else { logger("areamanager: success saving changed properties in area '{$area_id}'", WLOG_DEBUG); $this->output->add_message(t('areamanager_save_area_success', 'admin', $params)); } $areas = get_area_records(TRUE); // TRUE means force reread of area records $this->area_overview(); } else { logger("areamanager: weird: invalid dialog '{$dialog}' in area_save (area={$area_id})", WLOG_DEBUG); $this->area_overview(); } }
/** construct a FileManager object (called from /program/main_admin.php) * * This initialises the FileManager, checks user permissions and * finally dispatches the tasks. If the specified task is not * recognised, the default task TASK_LIST_DIRECTORY is executed. * * Note that many commands act on the directory contained in the * SESSION-variable current_directory. * * @param object &$output collects the html output * @param string $job indicates the mode: filemanager, filebrowser (FCKEditor) or imagebrowser (FCKEditor) * @return void results are returned as output in $this->output * @todo a nice filter for JOB_IMAGEBROWSER and also an alternative user interface for browsing/selecting images */ function FileManager(&$output, $job = JOB_FILEMANAGER) { global $USER, $CFG; $this->output =& $output; $this->job = $job; // Prepare lists of allowed filename extensions for browsing/uploading and set show thumbnail flag switch ($this->job) { case JOB_FILEBROWSER: $this->output->add_stylesheet($CFG->progwww_short . '/styles/admin_no_navigation.css'); $this->show_thumbnails = TRUE; $this->ext_allow_upload = $this->ext_allow_browse = $this->allowed_extensions($CFG->filemanager_files); break; case JOB_IMAGEBROWSER: $this->output->add_stylesheet($CFG->progwww_short . '/styles/admin_no_navigation.css'); $this->show_thumbnails = TRUE; $this->ext_allow_upload = $this->ext_allow_browse = $this->allowed_extensions($CFG->filemanager_images); break; case JOB_FLASHBROWSER: $this->output->add_stylesheet($CFG->progwww_short . '/styles/admin_no_navigation.css'); $this->show_thumbnails = TRUE; $this->ext_allow_upload = $this->ext_allow_browse = $this->allowed_extensions($CFG->filemanager_flash); break; case JOB_FILEMANAGER: $allowed_extensions_list = $CFG->filemanager_files; $this->show_thumbnails = FALSE; $this->ext_allow_upload = $this->allowed_extensions($CFG->filemanager_files); $this->ext_allow_browse = TRUE; break; default: logger(sprintf('%s.%s(): weird job \'%s\' so no allowed file extensions at all, sorry about that', __CLASS__, __FUNCTION__, $this->job)); $this->show_thumbnails = FALSE; $this->ext_allow_upload = FALSE; $this->ext_allow_browse = FALSE; break; } $this->output->set_helptopic('filemanager'); $this->areas = get_area_records(); $this->usergroups = get_user_groups($USER->user_id); $this->sort = SORTBY_FILE_ASC; // Make absolutely sure we do have a valid working directory (default to the user's 'My Files') if (!isset($_SESSION['current_directory'])) { $_SESSION['current_directory'] = '/users/' . $USER->path; } elseif (($_SESSION['current_directory'] = $this->valid_path($_SESSION['current_directory'])) === FALSE) { $_SESSION['current_directory'] = '/users/' . $USER->path; } $this->current_directory =& $_SESSION['current_directory']; $task = get_parameter_string('task', TASK_LIST_DIRECTORY); switch ($task) { case TASK_LIST_DIRECTORY: $this->task_list_directory(); break; case TASK_CHANGE_DIRECTORY: $this->task_change_directory(); break; case TASK_PREVIEW_FILE: $this->task_preview_file(); break; case TASK_REMOVE_FILE: $this->task_remove_file(); break; case TASK_REMOVE_DIRECTORY: $this->task_remove_directory(); break; case TASK_REMOVE_MULTIPLE_FILES: $this->task_remove_multiple_files(); break; case TASK_ADD_FILE: $this->task_add_file(); break; case TASK_ADD_DIRECTORY: $this->task_add_directory(); break; default: $s = utf8_strlen($task) <= 50 ? $task : utf8_substr($task, 0, 44) . ' (...)'; $message = t('task_unknown', 'admin', array('{TASK}' => htmlspecialchars($s))); $this->output->add_message($message); logger(__FUNCTION__ . '(): unknown task: ' . htmlspecialchars($s)); $this->task_list_directory(); break; } }
/** retrieve an array with node records straight from the database * * this routine constructs a list of 0, 1 or more node records based * on the $node_id provided by the caller. The node records are * retrieved from the database. * * This routine takes care of the showstoppers like embargo and * expiry and also access permissions to the area. We can not * be sure if the user actually has access to a page until we * are have checked to area in which the node $node_id resides. * This is an extra test compared to * {@link aggregator_view_get_node_from_tree()} above. * * @param int $node_id identifies page or section to evaluate * @param array &$config points to the aggregator configuration * @param array &$modules points to array with supported modules * @return array ordered list of nodes to aggregate (could be empty) */ function aggregator_view_get_node_from_db($node_id, &$config, &$modules) { global $USER; $nodes = array(); $table = 'nodes'; $fields = '*'; $order = $config['reverse_order'] ? 'sort_order DESC' : 'sort_order'; $where = array('node_id' => intval($node_id)); if (($record = db_select_single_record($table, $fields, $where)) === FALSE) { logger(sprintf('%s(): error retrieving node record: %s', __FUNCTION__, db_errormessage())); return $nodes; } $now = strftime("%Y-%m-%d %T"); // don't show expired nodes or nodes under embargo if ($now < $record['embargo'] || $record['expiry'] < $now) { return $nodes; } // don't show private or inactive areas to random strangers $areas = get_area_records(); $area_id = intval($record['area_id']); if (db_bool_is(FALSE, $areas[$area_id]['is_active']) || db_bool_is(TRUE, $areas[$area_id]['is_private']) && !$USER->has_intranet_permissions(ACL_ROLE_INTRANET_ACCESS, $area_id)) { return $nodes; } // if it was but a plain page we're done (even if not htmlpage or snapshots) if (db_bool_is(TRUE, $record['is_page'])) { $module_id = intval($record['module_id']); if (isset($modules[$module_id])) { $nodes[] = $record; } return $nodes; } // mmm, must have been a section (but at least in the correct area) // go get the pages in this section in this area $where = array('parent_id' => $node_id, 'area_id' => $area_id, 'is_page' => TRUE); if (($records = db_select_all_records($table, $fields, $where, $order)) === FALSE) { logger(sprintf('%s(): error retrieving node records: %s', __FUNCTION__, db_errormessage())); return $nodes; } $counter = 0; foreach ($records as $record) { // don't show expired nodes or nodes under embargo if ($now < $record['embargo'] || $record['expiry'] < $now) { continue; } $module_id = intval($record['module_id']); if (isset($modules[$module_id])) { $nodes[] = $record; if (++$counter >= $config['items']) { break; } } } return $nodes; }
/** construct a PageManager object (called from /program/main_admin.php) * * This initialises the PageManager, checks user permissions and * finally dispatches the tasks. If the specified task is not * recognised, the default task TASK_TREEVIEW is executed. * * Note that allmost all commands act on the area contained in the * SESSION-variable current_area_id. Also, we almost always need * the tree of nodes in that area, so we read it once, _before_ * dispatching the task at hand. This means that the current tree * in the current area is ALWAYS available. This means that none of * the other routines should have to worry about which area or * reading the tree; this information is already available in * $this->area_id and $this->tree. * * * @param object &$output collects the html output * @return void results are returned as output in $this->output */ function PageManager(&$output) { global $USER; $this->output =& $output; $this->output->set_helptopic('pagemanager'); $this->areas = get_area_records(); // Do not maintain a 'current area' if it is no longer there (it might have been deleted by us or another admin) if (isset($_SESSION['current_area_id']) && !isset($this->areas[intval($_SESSION['current_area_id'])])) { unset($_SESSION['current_area_id']); } // Do we have a valid working area? If not, try to calculate one if (!isset($_SESSION['current_area_id']) || !isset($_SESSION['tree_mode']) || !isset($_SESSION['expanded_nodes'])) { // 1 -- Try the specified area aaa from command line (admin.php?area=aaa) $area_id = get_parameter_int('area', FALSE); if ($area_id !== FALSE) { if (!$USER->is_admin_pagemanager($area_id) || !isset($this->areas[$area_id])) { logger(__FUNCTION__ . "(): weird: user '{$USER->username}' tried to access area '{$area_id}'"); $message = t('area_admin_access_denied', 'admin', array('{AREA}' => strval($area_id))); $area_id = FALSE; // sentinel } } else { // 2 -- try use the first available area for which the user has permissions... $message = t('no_areas_available', 'admin'); // ... but assume the worst foreach ($this->areas as $id => $area) { if ($USER->is_admin_pagemanager($id)) { $area_id = $id; break; } } } if ($area_id === FALSE) { $this->output->add_message($message); $this->output->add_content($message); $this->show_area_menu(); return; } else { $_SESSION['current_area_id'] = $area_id; $_SESSION['expanded_nodes'] = array(); $_SESSION['tree_mode'] = TREE_VIEW_MINIMAL; } } else { // Do we (still) have enough permissions for the current area? $area_id = intval($_SESSION['current_area_id']); if (!$USER->is_admin_pagemanager($area_id) || !isset($this->areas[$area_id])) { // this is completely weird: the session has an invalid area? tsk tsk tsk logger(__FUNCTION__ . "(): weird: user '{$USER->username}' can no longer access area '{$area_id}'?"); $message = t('area_admin_access_denied', 'admin', array('{AREA}' => strval($area_id))); $this->output->add_message($message); $this->output->add_content($message); $this->show_area_menu(); return; } } // // At this point we have 3 valid variables in $_SESSION indicating // the current working area and the open/closed state of sections. // We now should read the corresponding tree in core and look which // task we need to perform. // $this->build_cached_tree(intval($_SESSION['current_area_id'])); $task = get_parameter_string('task', TASK_TREEVIEW); switch ($task) { case TASK_TREEVIEW: $this->task_treeview(); break; case TASK_TREEVIEW_SET: $this->task_treeview_set(); break; case TASK_SUBTREE_EXPAND: $this->task_subtree_expand(); break; case TASK_SUBTREE_COLLAPSE: $this->task_subtree_collapse(); break; case TASK_SET_DEFAULT: $this->task_set_default(); break; case TASK_ADD_PAGE: case TASK_ADD_SECTION: $this->task_node_add($task); break; case TASK_NODE_DELETE: $this->task_node_delete(); break; case TASK_NODE_EDIT: case TASK_NODE_EDIT_ADVANCED: $this->task_node_edit($task); break; case TASK_NODE_EDIT_CONTENT: $this->task_node_edit_content(); break; case TASK_SAVE_CONTENT: $this->task_save_content(); break; case TASK_PAGE_PREVIEW: $this->task_page_preview(); break; case TASK_SAVE_NODE: $this->task_save_node(); break; case TASK_SAVE_NEWPAGE: case TASK_SAVE_NEWSECTION: $this->task_save_newnode($task); break; default: $s = utf8_strlen($task) <= 50 ? $task : utf8_substr($task, 0, 44) . ' (...)'; $message = t('task_unknown', 'admin', array('{TASK}' => htmlspecialchars($s))); $this->output->add_message($message); logger(__FUNCTION__ . '(): unknown task: ' . htmlspecialchars($s)); $this->task_treeview(); break; } }
/** construct a Theme object * * this stores the information about this theme from the database. * Also, we construct/read the tree of nodes for this area $area_id. This * information will be used lateron when constructing the navigation. * The node to display is $node_id. * * Also, we prepare a list of areas where the current user is allowed to go. * This is handy when constructing a jumpmenu and doing it here saves a trip * to the database lateron in {@link get_jumpmenu()}. * * @param array $theme_record the record straight from the database * @param int $area_id the area of interest * @param int $node_id the node that will be displayed * @return void */ function Theme($theme_record, $area_id, $node_id) { global $USER, $CFG; $charset = 'UTF-8'; $content_type = 'text/html; charset=' . $charset; $this->add_http_header('Content-Type: ' . $content_type); $this->theme_record = $theme_record; $this->theme_id = intval($theme_record['theme_id']); $this->area_id = intval($area_id); $this->jumps = array(); // extract areas information and // - grab a copy of the full area_record 'for future reference', and // - make a list of areas accessible for this user (for the area jumpmenu) if (($areas = get_area_records()) !== FALSE) { $this->area_record = $areas[$this->area_id]; foreach ($areas as $id => $area) { if (db_bool_is(TRUE, $area['is_active']) && (db_bool_is(FALSE, $area['is_private']) || $USER->has_intranet_permissions(ACL_ROLE_INTRANET_ACCESS, $id))) { $this->jumps[$id] = $area['title']; } } } else { $this->area_record = array('area_id' => $this->area_id, 'title' => '?'); logger(sprintf('constructor %s(): cannot get list of areas: %s', __FUNCTION__, db_errormessage()), WLOG_DEBUG); } $this->node_id = intval($node_id); $this->tree = $this->construct_tree($this->area_id); $this->node_record = $this->tree[$node_id]['record']; $this->config = $this->get_properties($this->theme_id, $this->area_id); $this->add_meta_http_equiv(array('Content-Type' => $content_type, 'Content-Script-Type' => 'text/javascript', 'Content-Style-Type' => 'text/css')); $this->title = $this->area_record['title']; $this->add_meta(array('MSSmartTagsPreventParsing' => 'TRUE', 'generator' => 'Website@School', 'description' => 'Website@School Content Management System for schools', 'keywords' => 'Website@School, CMS for schools')); $this->calc_breadcrumb_trail($node_id); // only set markers in tree, don't collect anchors yet $this->domain = 't_' . $this->theme_record['name']; // indicates where to look for translations if (isset($this->config['style_usage_static']) && $this->config['style_usage_static'] && isset($this->config['stylesheet'])) { $this->add_stylesheet($this->config['stylesheet']); } }