Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

610 lines (549 sloc) 23.57 kb
<?php
/**
* @package Habari
*
*/
/**
* Habari AdminHandler Class
* Backbone of the admin area, handles requests and functionality.
*/
class AdminHandler extends ActionHandler
{
/** An instance of the active public theme, which allows plugin hooks to execute */
protected $active_theme = null;
/**
* Verifies user credentials before creating the theme and displaying the request.
*/
public function __construct()
{
$user = User::identify();
if ( !$user->loggedin ) {
Session::add_to_set( 'login', $_SERVER['REQUEST_URI'], 'original' );
if ( URL::get_matched_rule()->action == 'admin_ajax' && isset( $_SERVER['HTTP_REFERER'] ) ) {
$ar = new AjaxResponse(408, _t('Your session has ended, please log in and try again.') );
$ar->out();
}
else {
$post_raw = $_POST->get_array_copy_raw();
if ( !empty( $post_raw ) ) {
Session::add_to_set( 'last_form_data', $post_raw, 'post' );
Session::error( _t( 'We saved the last form you posted. Log back in to continue its submission.' ), 'expired_form_submission' );
}
$get_raw = $_GET->get_array_copy_raw();
if ( !empty( $get_raw ) ) {
Session::add_to_set( 'last_form_data', $get_raw, 'get' );
Session::error( _t( 'We saved the last form you posted. Log back in to continue its submission.' ), 'expired_form_submission' );
}
Utils::redirect( URL::get( 'auth', array( 'page' => 'login' ) ) );
}
exit;
}
$last_form_data = Session::get_set( 'last_form_data' ); // This was saved in the "if ( !$user )" above, UserHandler transferred it properly.
/* At this point, Controller has not created handler_vars, so we have to modify $_POST/$_GET. */
if ( isset( $last_form_data['post'] ) ) {
$_POST = $_POST->merge( $last_form_data['post'] );
$_SERVER['REQUEST_METHOD'] = 'POST'; // This will trigger the proper act_admin switches.
Session::remove_error( 'expired_form_submission' );
}
if ( isset( $last_form_data['get'] ) ) {
$_GET = $_GET->merge( $last_form_data['get'] );
Session::remove_error( 'expired_form_submission' );
// No need to change REQUEST_METHOD since GET is the default.
}
$user->remember();
// Create an instance of the active public theme so that its plugin functions are implemented
$this->active_theme = Themes::create();
// setup the stacks for javascript in the admin - it's a method so a plugin can call it externally
self::setup_stacks();
// on every page load check the plugins currently loaded against the list we last checked for updates and trigger a cron if we need to
Update::check_plugins();
}
/**
* Create the admin theme instance
*
* @param string $page The admin page requested
* @param string $type The content type included in the request
*/
public function setup_admin_theme( $page, $type = '' )
{
if ( !isset( $this->theme ) ) {
$theme_dir = Plugins::filter( 'admin_theme_dir', Site::get_dir( 'admin_theme', true ) );
$this->theme = Themes::create( 'admin', 'RawPHPEngine', $theme_dir );
// Add some default stylesheets
Stack::add( 'admin_stylesheet', array( Site::get_url( 'admin_theme' ) . '/css/admin.css', 'screen' ), 'admin' );
Stack::add( 'admin_stylesheet', array( Site::get_url( 'admin_theme' ) . '/css/jqueryui.css', 'screen' ), 'jqueryui' );
// Add some default template variables
$this->set_admin_template_vars( $this->theme );
$this->theme->admin_type = $type;
$this->theme->admin_page = $page;
$this->theme->admin_page_url = ( $page == 'dashboard' ) ? URL::get( 'admin', 'page=' ) : URL::get( 'admin', 'page=' . $page );
$this->theme->page = $page;
$this->theme->admin_title = MultiByte::ucwords( $page ) . ( $type != '' ? ' ' . MultiByte::ucwords( $type ) : '' );
$this->theme->admin_title =
isset( $this->theme->mainmenu[$this->theme->admin_page]['text'] )
? $this->theme->mainmenu[$this->theme->admin_page]['text']
: MultiByte::ucwords( $page ) . ( $type != '' ? ' ' . MultiByte::ucwords( $type ) : '' );
}
}
/**
* Dispatches the request to the defined method. (ie: post_{page})
*/
public function act_admin()
{
$page = ( isset( $this->handler_vars['page'] ) && !empty( $this->handler_vars['page'] ) ) ? $this->handler_vars['page'] : 'dashboard';
$page = filter_var( $page, FILTER_SANITIZE_STRING );
if ( isset( $this->handler_vars['content_type'] ) ) {
$type = Plugins::filter( 'post_type_display', Post::type_name( $this->handler_vars['content_type'] ), 'singular' );
}
elseif ( $page == 'publish' && isset( $this->handler_vars['id'] ) ) {
$type = Post::type_name( Post::get( array( 'status' => Post::status( 'any' ), 'id' => intval( $this->handler_vars['id'] ) ) )->content_type );
$type = Plugins::filter( 'post_type_display', Post::type_name( Post::get( array( 'status' => Post::status( 'any' ), 'id' => intval( $this->handler_vars['id'] ) ) )->content_type ), 'singular' );
}
else {
$type = '';
}
$this->setup_admin_theme( $page, $type );
// Access check to see if the user is allowed the requested page
Utils::check_request_method( array( 'GET', 'HEAD', 'POST' ) );
if ( !$this->access_allowed( $page, $type ) ) {
Session::error( _t( 'Access to that page has been denied by the administrator.' ) );
$this->get_blank();
}
switch ( $_SERVER['REQUEST_METHOD'] ) {
case 'POST':
// Let plugins try to handle the page
Plugins::act( 'admin_theme_post_' . $page, $this, $this->theme );
// Handle POSTs to the admin pages
$fn = 'post_' . $page;
if ( method_exists( $this, $fn ) ) {
$this->$fn();
}
else {
$classname = get_class( $this );
echo sprintf( _t( '%1$s->%2$s() does not exist.' ), $classname, $fn );
exit;
}
break;
case 'GET':
case 'HEAD':
// Let plugins try to handle the page
Plugins::act( 'admin_theme_get_' . $page, $this, $this->theme );
// Handle GETs of the admin pages
$fn = 'get_' . $page;
if ( method_exists( $this, $fn ) ) {
$this->$fn();
exit;
}
// If a get_ function doesn't exist, just load the template and display it
if ( $this->theme->template_exists( $page ) ) {
$this->display( $page );
}
else {
// The requested console page doesn't exist
header( 'HTTP/1.1 404 Not Found', true, 404 );
$this->get_blank( _t( 'The page you were looking for was not found.' ) );
}
break;
}
}
/**
* Handle incoming requests to /admin_ajax for admin ajax requests
*/
public function act_admin_ajax()
{
header( 'Content-Type: text/javascript;charset=utf-8' );
$context = $this->handler_vars['context'];
if ( method_exists( $this, 'ajax_' . $context ) ) {
$type = ( isset( $this->handler_vars['content_type'] ) && !empty( $this->handler_vars['content_type'] ) ) ? $this->handler_vars['content_type'] : '';
// Access check to see if the user is allowed the requested page
if ( $this->access_allowed( 'ajax_' . $context, $type ) ) {
call_user_func( array( $this, 'ajax_' . $context ), $this->handler_vars );
}
}
else {
header( 'HTTP/1.1 403 Forbidden', true, 403 );
die();
}
}
/**
* Handles get requests for the system information page.
*/
public function get_sysinfo()
{
$sysinfo = array();
$siteinfo = array();
// Assemble Site Info
$siteinfo[ _t( 'Habari Version' ) ] = Version::get_habariversion();
if ( Version::is_devel() ) {
$siteinfo[ _t( 'Habari Version' ) ] .= " r" . Version::get_svn_revision();
}
$siteinfo[ _t( 'Habari API Version' ) ] = Version::get_apiversion();
$siteinfo[ _t( 'Habari DB Version' ) ] = Version::get_dbversion();
$siteinfo[ _t( 'Active Theme' ) ] = Options::get( 'theme_name' );
$siteinfo[ _t( 'Site Language' ) ] = strlen( Options::get( 'system_locale' ) ) ? Options::get( 'system_locale' ) : 'en-us';
$this->theme->siteinfo = $siteinfo;
// Assemble System Info
$sysinfo[ _t( 'PHP Version' ) ] = phpversion();
$sysinfo[ _t( 'Server Software' ) ] = $_SERVER['SERVER_SOFTWARE'];
$sysinfo[ _t( 'Database' ) ] = DB::get_driver_name() . ' - ' . DB::get_driver_version();
$sysinfo[ _t( 'PHP Extensions' ) ] = implode( ', ', get_loaded_extensions() );
$sysinfo[ _t( 'PHP Configuration Settings' ) ] = implode( "<br>", Utils::get_ini_settings() );
if ( defined( 'PCRE_VERSION' ) ) {
$sysinfo[ _t( 'PCRE Version' ) ] = PCRE_VERSION;
}
else {
// probably PHP < 5.2.4
ob_start();
phpinfo( 8 );
$phpinfo = ob_get_contents();
ob_end_clean();
preg_match( '/PCRE Library Version.*class="v">(.*)$/mi', $phpinfo, $matches );
$sysinfo[ _t( 'PCRE Version' ) ] = $matches[ 1 ];
}
$sysinfo[ _t( 'Browser' ) ] = $_SERVER[ 'HTTP_USER_AGENT' ];
$this->theme->sysinfo = $sysinfo;
// Assemble Class Info
$classinfo = Utils::glob( HABARI_PATH . "/user/classes/*.php" );
if ( count( $classinfo ) ) {
$classinfo = array_map( 'realpath', $classinfo );
}
$this->theme->classinfo = $classinfo;
// Assemble Plugin Info
$raw_plugins = Plugins::get_active();
$plugins = array( 'system'=>array(), 'user'=>array(), '3rdparty'=>array(), 'other'=>array() );
foreach ( $raw_plugins as $plugin ) {
$file = $plugin->get_file();
if ( preg_match( '%[\\\\/](system|3rdparty|user)[\\\\/]plugins[\\\\/]%i', $file, $matches ) ) {
// A plugin's info is XML, cast the element to a string. See #1026.
$plugins[strtolower( $matches[1] )][(string)$plugin->info->name] = $file;
}
else {
$plugins['other'][$plugin->info->name] = $file;
}
}
$this->theme->plugins = $plugins;
$this->theme->admin_page = _t( 'System Information' );
$this->display( 'sysinfo' );
}
/**
* Display a blank admin page with appropriate navigation.
* This function terminates execution before returning.
* Useful for displaying errors when permission is denied for viewing.
*
* @param string $content Optional default content to display
*/
public function get_blank( $content = '' )
{
$this->theme->content = Plugins::filter( 'admin_blank_content', $content );
$this->display( 'blank' );
exit();
}
/**
* Assembles the main menu for the admin area.
* @param Theme $theme The theme to add the menu to
*/
protected function get_main_menu( $theme )
{
$page = ( isset( $this->handler_vars['page'] ) && !empty( $this->handler_vars['page'] ) ) ? $this->handler_vars['page'] : 'dashboard';
// These need to be replaced with submenus, but access to them is provided temporarily
$createmenu = array();
$managemenu = array();
$createperms = array();
$manageperms = array();
$i = 1;
foreach ( Post::list_active_post_types() as $type => $typeint ) {
if ( $typeint == 0 ) {
continue;
}
if ( $i == 10 ) {
$hotkey = 0;
}
elseif ( $i > 10 ) {
$hotkey = false;
}
else {
$hotkey = $i;
}
$plural = Plugins::filter( 'post_type_display', $type, 'plural' );
$singular = Plugins::filter( 'post_type_display', $type, 'singular' );
$createperm = array( 'post_' . $type => ACL::get_bitmask( 'create' ), 'post_any' => ACL::get_bitmask( 'create' ) );
$createmenu['create_' . $typeint] = array( 'url' => URL::get( 'admin', 'page=publish&content_type=' . $type ), 'title' => _t( 'Create a new %s', array( $singular ) ), 'text' => $singular, 'access' => $createperm );
$createperms = array_merge( $createperms, $createperm );
$manageperm = array( 'post_' . $type => array( ACL::get_bitmask( 'edit' ), ACL::get_bitmask( 'delete' ) ), 'own_posts'=>array( ACL::get_bitmask( 'edit' ), ACL::get_bitmask( 'delete' ) ), 'post_any'=>array( ACL::get_bitmask( 'edit' ), ACL::get_bitmask( 'delete' ) ) );
$managemenu['manage_' . $typeint] = array( 'url' => URL::get( 'admin', 'page=posts&type=' . $typeint ), 'title' => _t( 'Manage %s', array( $plural ) ), 'text' => $plural, 'access'=> $manageperm );
$manageperms = array_merge( $manageperms, $manageperm );
$createmenu['create_' . $typeint]['hotkey'] = $hotkey;
$managemenu['manage_' . $typeint]['hotkey'] = $hotkey;
if ( $page == 'publish' && isset( $this->handler_vars['content_type'] ) && $this->handler_vars['content_type'] == $type ) {
$createmenu['create_' . $typeint]['selected'] = true;
}
if ( $page == 'posts' && isset( $this->handler_vars['type'] ) && $this->handler_vars['type'] == $typeint ) {
$managemenu['manage_' . $typeint]['selected'] = true;
}
$i++;
}
$createperms = array_merge( $createperms, array( 'own_posts'=>array( ACL::get_bitmask( 'create' ) ) ) );
$manageperms = array_merge( $manageperms, array( 'own_posts'=>array( ACL::get_bitmask( 'edit' ), ACL::get_bitmask( 'delete' ) ) ) );
$adminmenu = array(
'create' => array( 'url' => '', 'title' => _t( 'Create content' ), 'text' => _t( 'New' ), 'hotkey' => 'N', 'submenu' => $createmenu ),
'manage' => array( 'url' => '', 'title' => _t( 'Manage content' ), 'text' => _t( 'Manage' ), 'hotkey' => 'M', 'submenu' => $managemenu ),
'comments' => array( 'url' => URL::get( 'admin', 'page=comments' ), 'title' => _t( 'Manage comments' ), 'text' => _t( 'Comments' ), 'hotkey' => 'C', 'access' => array( 'manage_all_comments' => true, 'manage_own_post_comments' => true ) ),
'tags' => array( 'url' => URL::get( 'admin', 'page=tags' ), 'title' => _t( 'Manage tags' ), 'text' => _t( 'Tags' ), 'hotkey' => 'A', 'access'=>array( 'manage_tags'=>true ) ),
'dashboard' => array( 'url' => URL::get( 'admin', 'page=' ), 'title' => _t( 'View your user dashboard' ), 'text' => _t( 'Dashboard' ), 'hotkey' => 'D' ),
'options' => array( 'url' => URL::get( 'admin', 'page=options' ), 'title' => _t( 'View and configure site options' ), 'text' => _t( 'Options' ), 'hotkey' => 'O', 'access'=>array( 'manage_options'=>true ) ),
'themes' => array( 'url' => URL::get( 'admin', 'page=themes' ), 'title' => _t( 'Preview and activate themes' ), 'text' => _t( 'Themes' ), 'hotkey' => 'T', 'access'=>array( 'manage_theme'=>true ) ),
'plugins' => array( 'url' => URL::get( 'admin', 'page=plugins' ), 'title' => _t( 'Activate, deactivate, and configure plugins' ), 'text' => _t( 'Plugins' ), 'hotkey' => 'P', 'access'=>array( 'manage_plugins'=>true, 'manage_plugins_config' => true ) ),
'import' => array( 'url' => URL::get( 'admin', 'page=import' ), 'title' => _t( 'Import content from another site' ), 'text' => _t( 'Import' ), 'hotkey' => 'I', 'access'=>array( 'manage_import'=>true ) ),
'users' => array( 'url' => URL::get( 'admin', 'page=users' ), 'title' => _t( 'View and manage users' ), 'text' => _t( 'Users' ), 'hotkey' => 'U', 'access'=>array( 'manage_users'=>true ) ),
'profile' => array( 'url' => URL::get( 'admin', 'page=user' ), 'title' => _t( 'Manage your user profile' ), 'text' => _t( 'My Profile' ), 'hotkey' => 'Y', 'access'=>array( 'manage_self'=>true, 'manage_users'=>true ) ),
'groups' => array( 'url' => URL::get( 'admin', 'page=groups' ), 'title' => _t( 'View and manage groups' ), 'text' => _t( 'Groups' ), 'hotkey' => 'G', 'access'=>array( 'manage_groups'=>true ) ),
'logs' => array( 'url' => URL::get( 'admin', 'page=logs' ), 'title' => _t( 'View system log messages' ), 'text' => _t( 'Logs' ), 'hotkey' => 'L', 'access'=>array( 'manage_logs'=>true ) ) ,
'logout' => array( 'url' => URL::get( 'auth', 'page=logout' ), 'title' => _t( 'Log out of the administration interface' ), 'text' => _t( 'Logout' ), 'hotkey' => 'X' ),
);
$mainmenus = array_merge( $adminmenu );
foreach ( $mainmenus as $menu_id => $menu ) {
// Change this to set the correct menu as the active menu
if ( !isset( $mainmenus[$menu_id]['selected'] ) ) {
$mainmenus[$menu_id]['selected'] = false;
}
}
$mainmenus = Plugins::filter( 'adminhandler_post_loadplugins_main_menu', $mainmenus );
foreach ( $mainmenus as $key => $attrs ) {
if ( $page == $key ) {
$mainmenus[$key]['selected'] = true;
}
}
$mainmenus = $this->filter_menus_by_permission( $mainmenus );
// Strip out import if no importers are available
if ( !Plugins::filter( 'import_names', array() ) )
unset( $mainmenus['import'] );
// Make submenu links default to the first available item
foreach ( array_keys( $mainmenus ) as $action ) {
if ( !$mainmenus[$action]['url'] && !empty( $mainmenus[$action]['submenu'] ) ) {
$default = current( $mainmenus[$action]['submenu'] );
$mainmenus[$action]['url'] = $default['url'];
}
}
$theme->assign( 'mainmenu', $mainmenus );
}
/**
* Remove menus for which the user does not have qualifying permissions.
*
* @param array $menuarray The master array of admin menu items
* @return array The modified array of admin menu items
*/
protected function filter_menus_by_permission( $menuarray )
{
$user = User::identify();
foreach ( $menuarray as $key => $attrs ) {
if ( isset( $attrs['access'] ) ) {
$attrs['access'] = Utils::single_array( $attrs['access'] );
$pass = false;
foreach ( $attrs['access'] as $token => $masks ) {
$masks = Utils::single_array( $masks );
foreach ( $masks as $mask ) {
if ( is_bool( $mask ) ) {
if ( $user->can( $token ) ) {
$pass = true;
break;
}
}
else {
if ( $user->cannot( $token ) ) {
break 2;
}
else {
if ( $user->can( $token, $mask ) ) {
$pass = true;
break 2;
}
}
}
}
}
if ( !$pass ) {
unset( $menuarray[$key] );
}
}
if ( isset( $attrs['submenu'] ) && count( $attrs['submenu'] ) > 0 ) {
$menuarray[$key]['submenu'] = $this->filter_menus_by_permission( $attrs['submenu'] );
if ( count( $menuarray[$key]['submenu'] ) == 0 ) {
unset( $menuarray[$key]['submenu'] );
unset( $menuarray[$key] );
}
}
if ( isset( $menuarray[$key] ) && count( $menuarray[$key] ) == 0 ) {
unset( $menuarray[$key] );
}
}
return $menuarray;
}
/**
* Checks if the currently logged in user has access to a page and post type.
*/
private function access_allowed( $page, $type )
{
$user = User::identify();
$require_any = array();
$result = false;
switch ( $page ) {
case 'comment':
case 'comments':
case 'ajax_comments':
case 'ajax_in_edit':
case 'ajax_update_comment':
$require_any = array( 'manage_all_comments' => true, 'manage_own_post_comments' => true );
break;
case 'tags':
case 'ajax_tags':
case 'ajax_get_tags':
$require_any = array( 'manage_tags' => true );
break;
case 'options':
$require_any = array( 'manage_options' => true );
break;
case 'themes':
$require_any = array( 'manage_themes' => true, 'manage_theme_config' => true );
break;
case 'activate_theme':
$require_any = array( 'manage_themes' => true );
break;
case 'preview_theme':
$require_any = array( 'manage_themes' => true );
break;
case 'plugins':
$require_any = array( 'manage_plugins' => true, 'manage_plugins_config' => true );
break;
case 'plugin_toggle':
$require_any = array( 'manage_plugins' => true );
break;
case 'import':
$require_any = array( 'manage_import' => true );
break;
case 'users':
case 'ajax_update_users':
case 'ajax_users':
$require_any = array( 'manage_users' => true );
break;
case 'user':
$require_any = array( 'manage_users' => true, 'manage_self' => true );
break;
case 'groups':
case 'group':
case 'ajax_update_groups':
case 'ajax_groups':
$require_any = array( 'manage_groups' => true );
break;
case 'logs':
case 'ajax_delete_logs':
case 'ajax_logs':
$require_any = array( 'manage_logs' => true );
break;
case 'publish':
case 'ajax_media':
case 'ajax_media_panel':
case 'ajax_media_upload':
$type = Post::type_name( $type );
$require_any = array(
'post_any' => array( ACL::get_bitmask( 'create' ), ACL::get_bitmask( 'edit' ) ),
'post_' . $type => array( ACL::get_bitmask( 'create' ), ACL::get_bitmask( 'edit' ) ),
'own_posts' => array( ACL::get_bitmask( 'create' ), ACL::get_bitmask( 'edit' ) ),
);
break;
case 'delete_post':
$type = Post::type_name( $type );
$require_any = array(
'post_any' => ACL::get_bitmask( 'delete' ),
'post_' . $type => ACL::get_bitmask( 'delete' ),
'own_posts' => ACL::get_bitmask( 'delete' ),
);
break;
case 'posts':
case 'ajax_posts':
case 'ajax_update_posts':
$require_any = array(
'post_any' => array( ACL::get_bitmask( 'delete' ), ACL::get_bitmask( 'edit' ) ),
'own_posts' => array( ACL::get_bitmask( 'delete' ), ACL::get_bitmask( 'edit' ) ),
);
foreach ( Post::list_active_post_types() as $type => $type_id ) {
$require_any['post_' . $type] = array( ACL::get_bitmask( 'delete' ), ACL::get_bitmask( 'edit' ) );
}
break;
case 'sysinfo':
$require_any = array( 'super_user' => true );
break;
case 'dashboard':
case 'ajax_dashboard':
$result = true;
break;
case 'ajax_add_block':
$result = true;
break;
case 'ajax_delete_block':
$result = true;
break;
case 'configure_block':
$result = true;
break;
case 'ajax_save_areas':
$result = true;
break;
default:
break;
}
$require_any = Plugins::filter( 'admin_access_tokens', $require_any, $page, $type );
foreach ( $require_any as $token => $access ) {
$access = Utils::single_array( $access );
foreach ( $access as $mask ) {
if ( is_bool( $mask ) && $user->can( $token ) ) {
$result = true;
break;
}
elseif ( $user->can( $token, $mask ) ) {
$result = true;
break 2;
}
}
}
$result = Plugins::filter( 'admin_access', $result, $page, $type );
return $result;
}
/**
* Assigns the main menu to $mainmenu into the theme.
*/
protected function set_admin_template_vars( $theme )
{
$this->get_main_menu( $theme );
}
/**
* Helper function to assign all handler_vars into the theme and displays a theme template.
* @param template_name Name of template to display (note: not the filename)
*/
protected function display( $template_name )
{
$this->theme->display( $template_name );
}
/**
* Setup the default admin javascript stack here so that it can be called
* from plugins, etc. This is not an ideal solution, but works for now.
*
*/
public static function setup_stacks()
{
Stack::add( 'admin_header_javascript', Site::get_url( 'vendor' ) . "/jquery.js", 'jquery' );
Stack::add( 'admin_header_javascript', Site::get_url( 'vendor' ) . "/jquery-ui.min.js", 'jquery.ui', 'jquery' );
Stack::add( 'admin_header_javascript', Site::get_url( 'vendor' ) . "/jquery.color.js", 'jquery.color', 'jquery' );
Stack::add( 'admin_header_javascript', Site::get_url( 'vendor' ) . "/jquery.ui.nestedSortable.js", 'jquery-nested-sortable', 'jquery.ui' );
Stack::add( 'admin_header_javascript', Site::get_url( 'vendor' ) . "/humanmsg/humanmsg.js", 'humanmsg', 'jquery' );
Stack::add( 'admin_header_javascript', Site::get_url( 'vendor' ) . "/jquery.hotkeys.js", 'jquery.hotkeys', 'jquery' );
Stack::add( 'admin_header_javascript', Site::get_url( 'admin_theme' ) . "/js/media.js", 'media', 'jquery' );
Stack::add( 'admin_header_javascript', Site::get_url( 'admin_theme' ) . "/js/admin.js", 'admin', 'jquery' );
Stack::add( 'admin_header_javascript', Site::get_url( 'vendor' ) . "/crc32.js", 'crc32' );
}
public function create_theme()
{
$theme_dir = Plugins::filter( 'admin_theme_dir', Site::get_dir( 'admin_theme', true ) );
$this->theme = Themes::create( 'admin', 'RawPHPEngine', $theme_dir );
}
}
?>
Jump to Line
Something went wrong with that request. Please try again.