I've got a MediaWiki site and I would like to add a tab with a very simple "read article" functionality (without any edit/comment options). I followed the manual and tried to create a namespace for it, but it still doesn't work.
The snippet from LocalSettings.php looks like this:
define("NS_ARTICLE", 500);
$wgExtraNamespaces[NS_ARTICLE] = "Article";
$wgNamespaceProtection[NS_ARTICLE] = array( '' );
$wgNamespacesWithSubpages[NS_ARTICLE] = true;
$wgContentNamespaces[] = NS_ARTICLE;
I created new methods in Title.php:
public function getReadPage() {
return Title::makeTitle( MWNamespace::getRead( NS_ARTICLE ), $this->getDBkey() );
}
In Namespace.php:
public static function getRead( $index ) {
self::isMethodValidFor( $index, __METHOD__ );
return self::isTalk( $index )
? $index
: $index + 1;
}
And in SkinTemplate.php:
$readPage = $title->getReadPage();
$content_navigation['namespaces']['article']['class'] = 'selected';
$content_navigation['namespaces']['article']['text'] = 'Article';
$content_navigation['namespaces']['article']['href'] = $readPage;
$content_navigation['namespaces']['article']['primary'] = true;
$content_navigation['namespaces']['article']['context'] = 'subject';
The Tab appeared, but it links to ":Title" instead of "Article:Title". If I look for "Article:Title" page, the following message appears:
There is currently no text in this page. You can search for this page title in other pages, search the related logs, or edit this page.
Any ideas?
Don't touch the MediaWiki sources or you'll have to redo the same thing each time you upgrade. Tab manipulation is doable with hooks, e.g. SkinTemplateNavigation.
Related
I'm trying to develop a plugin in Moodle. One of the requirements is to add an element to the Settings Menu, in which I was able to achieve with the help of this guide
https://docs.moodle.org/dev/Local_plugins#Adding_an_element_to_the_settings_menu
And this is my code in local/myplugin/lib.php
<?php
function local_myplugin_extends_settings_navigation($settingsnav, $context) {
// question_extend_settings_navigation
global $CFG, $PAGE;
// Only add this settings item on non-site course pages.
if (!$PAGE->course or $PAGE->course->id == 1) {
return;
}
// Only let users with the appropriate capability see this settings item.
/*if (!has_capability('moodle/backup:backupcourse', context_course::instance($PAGE->course->id))) {
return;
}*/
if ($settingnode = $settingsnav->find('courseadmin', navigation_node::TYPE_COURSE)) {
$strfoo = get_string('classrecord', 'local_myplugin');
$url = new moodle_url('/course/classrecord.php', array('id' => $PAGE->course->id));
$foonode = navigation_node::create(
$strfoo,
$url,
navigation_node::NODETYPE_LEAF,
'myplugin',
'myplugin',
new pix_icon('i/grades', $strfoo)
);
if ($PAGE->url->compare($url, URL_MATCH_BASE)) {
$foonode->make_active();
}
$settingnode->add_node($foonode);
}
}
?>
I allowed the students to see the element "Class Record" in the settings menu
My concern is that how can I hide/show Class Record I added?
Any ideas would be great!
If you want only certain users to see the link, then create an appropriate capability in local/myplugin/db/access.php, e.g. 'local/myplugin:viewclassrecord', defaulting to being assigned to the 'student' role. Then check for it in the function you have defined.
e.g.
if (!has_capability('local/myplugin:viewclassrecord', $context)) {
return;
}
I need to implement update for my plugin which is not on wordpress repository.
What I need to know is difference between two filters:
'site_transient_update_plugins' and 'pre_set_site_transient_update_plugins'
I implemented one class for update with 'pre_set_site_transient_update_plugins' filter:
class WPAutoUpdate{
public $current_version;
public $update_path;
public $plugin_slug;
public $slug;
function __construct($current_version, $update_path, $plugin_slug){
$this->current_version = $current_version;
$this->update_path = $update_path;
$this->plugin_slug = $plugin_slug;
list ($t1, $t2) = explode('/', $plugin_slug);
$this->slug = str_replace('.php', '', $t2);
add_filter('pre_set_site_transient_update_plugins', array(&$this, 'check_update'));
}
public function check_update($transient){
if (empty($transient->checked)) {
return $transient;
}
$remote_version = $this->getRemote_version();
if (version_compare($this->current_version, $remote_version, '<')) {
$obj = new stdClass();
$obj->slug = $this->slug;
$obj->new_version = $remote_version;
$obj->url = $this->update_path;
$obj->package = $this->update_path;
$transient->response[$this->plugin_slug] = $obj;
}
return $transient;
}
public function getRemote_version(){
$request = wp_remote_post($this->update_path, array('body' => array('action' => 'version')));
if (!is_wp_error($request) || wp_remote_retrieve_response_code($request) === 200) {
return $request['body'];
}
return false;
}
}
An instance of this class will be created from the main file of plugin:
$pluginData = get_plugin_data(__FILE__);
$plugin_current_version = $pluginData['Version'];
$plugin_remote_path = 'https://mysite.com/myplugin';
$plugin_slug = plugin_basename(__FILE__);
new WPAutoUpdate ($plugin_current_version, $plugin_remote_path, $plugin_slug);
The only problem is when I use 'pre_set_site_transient_update_plugins' filter and when new version of plugin is available, when I visit plugin page for the first time there is no information about new version. And then when I refresh the page there will be update option and each next visit on plugin page there will be update option, just not for the first visit.
And when I use 'site_transient_update_plugins' filter update information will be shown for the first visit and all works fine. Just I am worried because filter 'pre_set_site_transient_update_plugins' will be called just twice and 'site_transient_update_plugins' will be called 11 times.
So if I use 'site_transient_update_plugins' all will works fine but my function on this hook, which contain wp_remote_post() function, will be called 11 times on each visit plugin page.
Is that smart to do, is that to much expensive operation. Does anyone has some advice.
In my custom template tpl file, i am showing two sections (div content) of data, one from each function of my custom module.
The data also has pagination for it, displayed below.
Initially only one block of data will be displayed. Other block of data will be hidden on the page, unless the user clicks on a tab in the page.
Now my question is, how can i show individual paginations for each of my blocks in the same page ?
If i click on a page link in block 1 and go to its page, the pagination links for another block must not be affected.
How to achieve this in Drupal 7?
// my custom module code below
// function one
func one() {
$page = strtolower($page);
$query = db_select('keyword', 'k');
$query->groupBy('k.res');
$stories = $query->extend('PagerDefault')->limit(10)->execute();
return $stories;
}
// function two
func two() {
$page = strtolower($page);
$query = db_select('videos', 'v');
$query->groupBy('v.res');
$videos= $query->extend('PagerDefault')->limit(10)->execute();
return $videos;
}
// in my custom template page
// below is first section in same page
$block_content = fun one(arg(1));
$args = array( 'parameters' => array('pg' => 'one'));
print (theme ('pager',$args));
foreach($block_content as $content)
{
// doing something to display
}
print (theme ('pager',$args));
// below is second section in same page
$block_content = fun two(arg(1));
$args = array( 'parameters' => array('pg' => 'two'));
print (theme ('pager',$args));
foreach($block_content as $content)
{
// doing something to display
}
print (theme ('pager',$args));
You can use the PagerDefault::element() method to set a unique element ID for the pager:
// First one
$stories = $query->extend('PagerDefault')->element(0)->limit(10)->execute();
// Second one
$videos = $query->extend('PagerDefault')->element(1)->limit(10)->execute();
Then use the respective element ID in the theme call:
// First one
$args = array('element' => 0, ...);
print theme('pager', $args);
// Second one
$args = array('element' => 1, ...);
print theme('pager', $args);
In the Header.tpl file there is a hook {$HOOK_TOP} which contains all the header part including menu, search etc... You can check that in this URL
In the FrontController it shows... 'HOOK_TOP' => Hook::exec('displayTop'),
it means in the Hook page there is a function called exec(). But I cannot understand the code properly in the exec() call.
It tells it Execute modules for specified hook. When I searched for "displayTop" I got a module name called blocktopmenu.php.
Execution only goes through 2 functions:
public function hookDisplayTop($param)
{
$this->user_groups = ($this->context->customer->isLogged() ? $this->context->customer->getGroups() : array(Configuration::get('PS_UNIDENTIFIED_GROUP')));
$this->page_name = Dispatcher::getInstance()->getController();
if (!$this->isCached('blocktopmenu.tpl', $this->getCacheId()))
{
$this->makeMenu();
$this->smarty->assign('MENU_SEARCH', Configuration::get('MOD_BLOCKTOPMENU_SEARCH'));
$this->smarty->assign('MENU', $this->_menu);
$this->smarty->assign('this_path', $this->_path);
}
$this->context->controller->addJS($this->_path.'js/hoverIntent.js');
$this->context->controller->addJS($this->_path.'js/superfish-modified.js');
$this->context->controller->addCSS($this->_path.'css/superfish-modified.css');
$html = $this->display(__FILE__, 'blocktopmenu.tpl', $this->getCacheId());
//print_r($html);//exit;
return $html;
}
and
protected function getCacheId($name = null)
{//echo"asdasdsad";exit;
parent::getCacheId($name);
$page_name = in_array($this->page_name, array('category', 'supplier', 'manufacturer', 'cms', 'product')) ? $this->page_name : 'index';
return 'blocktopmenu|'.(int)Tools::usingSecureMode().'|'.$page_name.'|'.(int)$this->context->shop->id.'|'.implode(', ',$this->user_groups).'|'.(int)$this->context->language->id.'|'.(int)Tools::getValue('id_category').'|'.(int)Tools::getValue('id_manufacturer').'|'.(int)Tools::getValue('id_supplier').'|'.(int)Tools::getValue('id_cms').'|'.(int)Tools::getValue('id_product');
}
But this public function hookDisplayTop($param) never gets called in the whole folder anywhere. I searched it but never found it in any file.
The exec() function shows below
public static function exec($hook_name, $hook_args = array(), $id_module = null, $array_return = false, $check_exceptions = true)
{
// Check arguments validity
if (($id_module && !is_numeric($id_module)) || !Validate::isHookName($hook_name))
throw new PrestaShopException('Invalid id_module or hook_name');
// If no modules associated to hook_name or recompatible hook name, we stop the function
if (!$module_list = Hook::getHookModuleExecList($hook_name))
return '';
// Check if hook exists
if (!$id_hook = Hook::getIdByName($hook_name))
return false;
// Store list of executed hooks on this page
Hook::$executed_hooks[$id_hook] = $hook_name;
// print_r(Hook::$executed_hooks);exit;
$live_edit = false;
$context = Context::getContext();
if (!isset($hook_args['cookie']) || !$hook_args['cookie'])
$hook_args['cookie'] = $context->cookie;
if (!isset($hook_args['cart']) || !$hook_args['cart'])
$hook_args['cart'] = $context->cart;
$retro_hook_name = Hook::getRetroHookName($hook_name);
//print_r($hook_name);exit;
// Look on modules list
$altern = 0;
$output = '';
foreach ($module_list as $array)
{
// Check errors
if ($id_module && $id_module != $array['id_module'])
continue;
if (!($moduleInstance = Module::getInstanceByName($array['module'])))
continue;
// Check permissions
if ($check_exceptions)
{
$exceptions = $moduleInstance->getExceptions($array['id_hook']);
$controller = Dispatcher::getInstance()->getController();
if (in_array($controller, $exceptions))
continue;
//retro compat of controller names
$matching_name = array(
'authentication' => 'auth',
'compare' => 'products-comparison',
);
if (isset($matching_name[$controller]) && in_array($matching_name[$controller], $exceptions))
continue;
if (Validate::isLoadedObject($context->employee) && !$moduleInstance->getPermission('view', $context->employee))
continue;
}
// Check which / if method is callable
$hook_callable = is_callable(array($moduleInstance, 'hook'.$hook_name));
$hook_retro_callable = is_callable(array($moduleInstance, 'hook'.$retro_hook_name));
if (($hook_callable || $hook_retro_callable) && Module::preCall($moduleInstance->name))
{
$hook_args['altern'] = ++$altern;
// Call hook method
if ($hook_callable)
$display = $moduleInstance->{'hook'.$hook_name}($hook_args);
else if ($hook_retro_callable)
$display = $moduleInstance->{'hook'.$retro_hook_name}($hook_args);
// Live edit
if (!$array_return && $array['live_edit'] && Tools::isSubmit('live_edit') && Tools::getValue('ad') && Tools::getValue('liveToken') == Tools::getAdminToken('AdminModulesPositions'.(int)Tab::getIdFromClassName('AdminModulesPositions').(int)Tools::getValue('id_employee')))
{
$live_edit = true;
$output .= self::wrapLiveEdit($display, $moduleInstance, $array['id_hook']);
}
else if ($array_return)
$output[] = $display;
else
$output .= $display;
}
}
if ($array_return)
return $output;
else
return ($live_edit ? '<script type="text/javascript">hooks_list.push(\''.$hook_name.'\'); </script>
<div id="'.$hook_name.'" class="dndHook" style="min-height:50px">' : '').$output.($live_edit ? '</div>' : '');// Return html string
}
I am not going to explain you the code line by line here, but i will explain you what the exec static member do.
When ever you call
Hook::exec("HookName");
It performs the following processes for you.
1) First it checks whether the hook is available or not? If it is not available return false;
2) Second it gets the module list for that hook from database. Also narrow down the list by exceptions for the modules for the hooks for the current page.
3) After it gets all the module(s) for the hook called for the current loaded (or called page) page, it calls the hooks function in the module. If you check modules for a specific hook you will find public function for that hook. Lets consider the Top hook. In modules you will have public functions like
public function hookTop // or public function hookDisplayTop for compatibility reasons
Please not that PS performs some other operations also there.
The above details are just giving you the idea that how hooks and modules work in PS.
Also taking the above theory, i implemented the same operations in Codeigniter and Zend Framework for my own projects, and it works like a charm ;) .
If you still have any other questions, let me know and i will provide you as much details as i can.
Thank you
Lines who call the HookDiplayTop are :
// Call hook method
if ($hook_callable)
$display = $moduleInstance->{'hook'.$hook_name}($hook_args);
else if ($hook_retro_callable)
$display = $moduleInstance->{'hook'.$retro_hook_name}($hook_args);
For each member page you have a selection of components (e.g. profile, settings, activity...)
What I am trying to do is add a new component called jobs to each page. I understand how to add the link to the navigation bar. It is just creating the page that is confusing me.
Do I add a new directory, if so how do I let buddypress know.
Having a url structure like:
example.com/member/username/jobs
is important.
Thanks!
The global variable $bp is where you want to insert the new Jobs component. By dumping the global variable $bp, you can see all of the elements contained in it, including all of the components. To easily dump $bp, add the following to the top of member-header.php:
global $bp;
foreach ( (array)$bp as $key => $value ) {
echo '<pre>';
echo '<strong>' . $key . ': </strong><br />';
print_r( $value );
echo '</pre>';
}
The array within $bp that you want to add the component 'Jobs' to is bp_nav.
In functions.php add the following:
add_action( 'bp_setup_nav', 'add_subnav_items', 100 ); //Priority must be higher than 10
function add_subnav_items() {
global $bp;
//Jobs tab
$tab_array['name'] = 'Jobs';
$tab_array['link'] = $bp->displayed_user->domain.'jobs';
$tab_array['slug'] = 'jobs';
$tab_array['parent_url'] = $bp->displayed_user->domain;
$tab_array['parent_slug'] = bp_core_get_userlink(bp_loggedin_user_id());
$tab_array['css_id'] = 'jobs';
$tab_array['position'] = 100;
$tab_array['user_has_access'] = '1';
$tab_array['screen_function'] = 'bp_jobs_screen_general';
$bp->bp_nav['jobs'] = $tab_array; //Add new array element to the 'bp_nav' array
}
The 'screen_function' is a function that handles the screen that is to be shown when 'Jobs' tab is selected so you must add the function 'bp_jobs_screen_general' in functions.php:
function bp_jobs_screen_general() {
bp_core_load_template( apply_filters( 'bp_jobs_screen_general','members/single/jobs' ) );
}
This function looks for a template file named jobs.php in members/single/ so you must create it. For an example on how the screen_function's work, refer to a function for displaying Groups screens within wp-content/plugins/buddypress/bp-groups/bp-groups-screens.php.