Wiki - table content from an external source - html

Is it possible to have a wiki page with two tables reflecting the data from two different 3rd party sites?
If so, how to get it done? Will page templates be of any help here?

Short answer is no, there's no easy, built-in way to pull external content into a MediaWiki site. Allowing a third party to inject arbitrary content would be massive security risk.
Long answer is that anything is possible with extensions, either existing ones or ones you write yourself. The MediaWiki site has an entire category of listings for "Remote content extensions" that do this kind of thing in one form or another, with External Data looking particularly useful. You will need admin rights to install any of these, and you'll need to trust both the extension code and the data you pull in.

I already wrote exactly what you describe. Might be helpful for you.
# Define a setup function
$wgHooks['ParserFirstCallInit'][] = 'efStackOverflow_Setup';
# Add a hook to initialise the magic word
$wgHooks['LanguageGetMagic'][] = 'efStackOverflow_Magic';
function efStackOverflow_Setup( &$parser ) {
# Set a function hook associating the "example" magic word with our function
$parser->setFunctionHook( 'stag', 'efStackOverflow_Render' );
return true;
}
function efStackOverflow_Magic( &$magicWords, $langCode ) {
# Add the magic word
# The first array element is whether to be case sensitive, in this case (0) it is not case sensitive, 1 would be sensitive
# All remaining elements are synonyms for our parser function
$magicWords['stag'] = array(1, 'stag');
# unless we return true, other parser functions extensions won't get loaded.
return true;
}
function efStackOverflow_Render( $parser, $param1 = '', $param2 = '' ) {
// there was filtering
$modif = 0;
$cache_file_path = "cache/".$param1."_".$param2;
if (file_exists($cache_file_path))
$modif = time() - #filemtime ($cache_file_path);
if (file_exists($cache_file_path) and $modif < 60*60*24) {
return file_get_contents($cache_file_path);
}
$page = file_get_contents("http://www.google.com/rss/".$param1);
$xml = new SimpleXMLElement($page);
foreach ($xml as $key => $value) {
// do some
}
if (!empty($output))
file_put_contents($cache_file_path, $output);
return $output;
}
Mediawiki version was 1.16.

Related

How to change language automatically using user browser language Yii2?

A user can change the language manually from the website. But for better user experience, I would like to change it automatically based on the users' browser language. I have a global Controller and can use init() and then redirect.
Please give me tips to do it right.
You should remember the chosen language for a user, if they had selected one previously, I store this in the database, in a user_preference table.
Then you need to intercept the request, it can be done in the application configuration file, using the on beforeRequest property.
If you don't have stored a preference for the current user, or the user is a guest, use the browser language to set the application language.
Configuration file
use app\models\User;
...
'on beforeRequest' => function ($event) {
$user_lang = '';
if (!Yii::$app->user->isGuest) {
// Check if you have stored a language preference for the user
$user_lang = User::findIdentity(Yii::$app->user->id)->getUserPreference('lang');
}
if (!empty($user_lang)) {
// If you have a stored preference for the user, use it
Yii::$app->language = $user_lang;
} else {
// If you don't have a preference, use the browser language
// Get the browser language from the headers
$browser_lang = Yii::$app->request->headers->get('accept-language');
// Alternatively get the headers from the event
// $event->sender->request->headers->get('accept-language')
// Calculate the language you want to provide based on the browser language
$language_code = LanguageHelper::calculatei18nCode($browser_lang);
Yii::$app->language = $language_code;
}
},
...
If you wanted to keep your configuration file clean, you could use filters instead to intercept the request.
Your LanguageHelper::calculatei18nCode($browser_lang) method would try to find a match for the browser language in the available languages, if it didn't find one it could return the closest match, or the default application language.
LanguageHelper
public static function calculatei18nCode ($browser_lang) {
// For example, if you are offering one translation file for french
if (stripos($browser_lang, 'fr')) {
return 'fr';
}
...
return 'en';
}

Wikimedia function to get all my Templates

I need to get all the pages I have created like Templates in my wikimedia webpage. I have to do this with javascript.
Is this possible?
You can do this with a UserContribs API query, like this:
https://en.wikipedia.org/w/api.php?format=jsonfm&action=query&list=usercontribs&ucuser=Ilmari_Karonen&ucnamespace=10&ucshow=new&continue=
Basically, the parameters you need are:
format=json to get results in JSON format, which is probably what you want for JavaScript. (I've used jsonfm in the example link above to get pretty-printed human readable output.)
action=query to indicate that this is, indeed, a query rather than, say, an edit or a login attempt.
list=usercontribs to indicate that you want a list of a user's contributions (i.e. the stuff you see on the Special:Contributions page).
ucuser=your_username to select which user's contributions you want to see. (The example link above shows mine.)
ucnamespace=10 to select only contributions to templates. (10 is the namespace number for the built-in Template namespace).
ucshow=new to select only contributions that involve creating a new page. (Note that this also includes page moves; I don't see any simple way to filter those out.)
Of course, there are other parameters you may also want to include.
I've also included an empty continue= parameter to indicate that I want to use the new query continuation syntax, and to suppress the warning about it. Obviously, if you actually want to use query continuation, you'll need to implement the client-side part yourself (or use an MW API client that implements it for you). Here's one simplistic way to do that:
function getNewTemplatesForUser( username ) {
var queryURL = 'https://en.wikipedia.org/w/api.php?format=json&action=query&list=usercontribs&ucnamespace=10&ucshow=new';
queryURL += '&ucuser=' + encodeURIComponent( username );
var callback = function( json ) {
// TODO: actually process the results here
if ( json.continue ) {
var continueURL = queryURL;
for ( var attr in json.continue ) {
continueURL += '&' + attr + '=' + encodeURIComponent( json.continue[attr] );
}
doAjaxRequest( continueURL, callback );
}
};
doAjaxRequest( queryURL + '&continue=', callback );
}

Disable "red links" on MediaWiki

I want to make the "red links" (links for uncreated pages) on a MediaWiki site to become plain text, save for people logged. Perhaps also make that them don't appear at all or only appear on different situations. You can "hide" them a bit with CSS, but I prefer to actually don't feature them.
You could use the LinkBegin hook to abort the link creation for page that do not exist. Something like this:
$wgHooks['LinkBegin'][] = 'ExampleExtension::exampleExtensionLinkBegin';
class ExampleExtension {
public static function exampleExtensionLinkBegin( $dummy, $target, &$html, &$customAttribs, $query, &$options, &$ret ) {
if ( $target->exists() ) {
return true;
} else {
$ret = $html;
return false;
}
} //exampleExtensionLinkBegin
}
edit: If you are not familiar with MW extension development, I recommend that you start by reading http://www.mediawiki.org/wiki/Manual:Developing_extensions and http://www.mediawiki.org/wiki/Manual:Hooks
If you know just a little bit of PHP, you should be able to follow that without any problems.

DOMDocument issues: Escaping attributes and removing tags from javascript

I am not fan of DOMDocument because I believe it is not very good for real world usages. Yet in current project I need to replace all texts in a page (which I don't have access to source code) with other strings (some sort of translation); so I need to use it.
I tried doing this with DOMDocument and I didn't received the expected result. Here is the code I use:
function Translate_DoHTML($body, $replaceArray){
if ($replaceArray && is_array($replaceArray) && count($replaceArray) > 0){
$body2 = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8");
$doc = new DOMDocument();
$doc->resolveExternals = false;
$doc->substituteEntities = false;
$doc->strictErrorChecking = false;
if (#$doc->loadHTML($body2)){
Translate_DoHTML_Process($doc, $replaceArray);
$body = $doc->saveHTML();
}
}
return $body;
}
function Translate_DoHTML_Process($node, $replaceRules){
if($node->hasChildNodes()) {
$nodes = array();
foreach ($node->childNodes as $childNode)
$nodes[] = $childNode;
foreach ($nodes as $childNode)
if ($childNode instanceof DOMText) {
if (trim($childNode->wholeText)){
$text = str_ireplace(array_keys($replaceRules), array_values($replaceRules), $childNode->wholeText);
$node->replaceChild(new DOMText($text),$childNode);
}
}else
Translate_DoHTML_Process($childNode, $replaceRules);
}
}
And here are the problems:
Escaping attributes: There are data-X attributes in file that become escaped. This is not a major problem but it would be great if I could disable this behavior.
Before DOM:
data-link-content=" <a class="submenuitem" href=&quot
After DOM:
data-link-content=' <a class="submenuitem" href="
Removing of closing tags in javascript:
This is actually the main problem for me here. I don't know for what reason in the world DOMDocument may see any need to remove these tags. But it do. As you can clearly see in below example it remove closing tags in java-script string. It also removed last part of script. It seems like DOMDocument parse the java-script inside. Maybe because there is no CDATA tag? But any way it is HTML and we don't need CDDATA in HTML. I thought CDATA is for xHTML. Also I have no way to add CDDATA here. So can I ask it to not parse script tags?
Before DOM:
<script type="text/javascript"> document.write('<video src="http://x.webm"><p>You will need to Install the latest Flash plugin to view this page properly.</p></video>'); </script>
After DOM:
<script type="text/javascript"> document.write('<video src="http://x.webm"><p>You will need to <a href="http://www.adobe.com/go/getflashplayer" target="_blank">Install the latest Flash plugin to view this page properly.</script>
If there is no way for me to prevent these things, is there any way that I can port this code to SimpleHTMLDOM?
Thanks you very much.
Try this , and replace line content ;
$body2 = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8");
to ;
$body2 = convertor($body);
and insert in your code ;
function convertor($ToConvert)
{
$FromConvert = html_entity_decode($ToConvert,ENT_QUOTES,'ISO-8859-1');
$Convert = mb_convert_encoding($FromConvert, "ISO-8859-1", "UTF-8");
return ltrim($Convert);
}
But use the right encoding in the context.
Have a nice day.
Based on my search, reason of the second problem is actually what "Alex" told us in this question: DOM parser that allows HTML5-style </ in <script> tag
But based on their research there is no good parser out there capable of understanding today's HTML. Also, html5lib's last update was 2 years ago and it failed to work in real world situations based on my tests.
So I had only one way to solve the second problem. RegEx. Here is the code I use:
function Translate_DoHTML_GetScripts($body){
$res = array();
if (preg_match_all('/<script\b[^>]*>([\s\S]*?)<\/script>/m', $body, $matches) && is_array($matches) && isset($matches[0])){
foreach ($matches[0] as $key => $match)
$res["<!-- __SCRIPTBUGFIXER_PLACEHOLDER".$key."__ -->"] = $match;
$body = str_ireplace(array_values($res), array_keys($res), $body);
}
return array('Body' => $body, 'Scripts' => $res);
}
function Translate_DoHTML_SetScripts($body, $scripts){
return str_ireplace(array_keys($scripts), array_values($scripts), $body);
}
Using above two functions I will remove any script from HTML so I can use DomDocument to do my works. Then again at the end, I will add them back exactly where they were.
Yet I am not sure if regex is fast enough for this.
And don't tell me to not use RegEx for HTML. I know that HTML is not a regular language and so on; but if you read the problem your self, you will suggest the same approach.

Magento: Disable module for any particular store

Suppose, I have 3 stores.
I want to disable a module in Store 2. I only want it to be enabled in Store 1 and Store 3.
I see that I can do it by:-
Going to System -> Configuration -> Advanced
Selecting desired store from Current Configuration Scope dropdown list.
But this does not work fully.
And, I also don't want to check store in the module code itself or create system configuration field for the module to check/uncheck store to enable/disable.
What I am expecting is by adding some code in app/etc/modules/MyNamespace_MyModule.xml. Can we do it this way?
To disable a module on the store scope, I've found it's possible to do it like this:
Move app/code/core/Mage/Core/Model/Config.php to app/code/local/Mage/Core/Model/Config.php
Inside Config.php find the method "loadModulesConfiguration" Don't change anything, but add the following code to make the method look like this.
public function loadModulesConfiguration($fileName, $mergeToObject = null, $mergeModel=null)
{
$disableLocalModules = !$this->_canUseLocalModules();
if ($mergeToObject === null) {
$mergeToObject = clone $this->_prototype;
$mergeToObject->loadString('<config/>');
}
if ($mergeModel === null) {
$mergeModel = clone $this->_prototype;
}
$modules = $this->getNode('modules')->children();
foreach ($modules as $modName=>$module) {
if ($module->is('active')) {
// Begin additional code
if((bool)$module->restricted) {
$restricted = explode(',', (string)$module->restricted);
$runCode = (isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : 'default');
if(in_array($runCode, $restricted)) {
continue;
}
}
// End additional code
if ($disableLocalModules && ('local' === (string)$module->codePool)) {
continue;
}
if (!is_array($fileName)) {
$fileName = array($fileName);
}
foreach ($fileName as $configFile) {
$configFile = $this->getModuleDir('etc', $modName).DS.$configFile;
if ($mergeModel->loadFile($configFile)) {
$mergeToObject->extend($mergeModel, true);
}
}
}
}
return $mergeToObject;
}
The new code will cause the method to also check for a new node in the module xml file, <restricted>. If the node exists, the value would be a comma separated list of store codes that you do NOT want the module to load on. If you have multiple stores, the $_SERVER variable "MAGE_RUN_CODE" should be set with the current store code. If it's not set, the script will fallback to assuming the store code is "default" which is what it is by default unless for some bizarre reason you decide to change that in the backend.
A modules xml file could then look like this:
<?xml version="1.0"?>
<config>
<modules>
<MyPackage_MyModule>
<active>false</active>
<restricted>mystore1,mystore4,mystore5</restricted>
<codePool>local</codePool>
</MyPackage_MyModule>
</modules>
</config>
With this, the module will not even load while on the stores with a store code of mystore1, mystore4, or mystore5. The <restricted> tag is entirely optional, if you omit it the module will load as it normally would.
This configuration just disables module output in layout for frontend, but module controllers, event observers, admin pages, etc still working.
Also don't forget to specify your module name in layout files definition, otherwise all the layout file content will be loaded for a particular store:
<config>
<layout>
<module_alias module="Module_Name">
<file>yourlayoutfile.xml</file>
</module_alias>
</layout>
</config>
If you are developing a module and want to disable full its functionality on the frontent for a particular store, then you should create a configuration field of "Yes/No" type and check its value via Mage::getStoreConfigFlag('config/field/path') in your module code.
I was using Eric solution for a while. In my case I disabled certain module responsible for Layered Navigation in one of my shops - thus returning to default Layered Navigation behaviour.
And it looked like its working, but after a while I've noticed that layered navigation options stopped to appear where they should. Soon I've noticed that in fact the module that should not work on this shop continued to work. Then I realized that when I disable configuration cache Eric's solution works, but after enabling it again it stops.
After a while I realized it had to work that way, with configuration cache enabled, because Eric's solution includes (or not) specified config files in global xml only while this xml is being generated. Then its cached and called from cache only. So when it was generated from site which should use some module it was included, and then used also on site which wasn't suppose to use it.
Anyway I worked out another solution, based on Eric's code (using restricted in modules config). I thought Magento should decide what to load when class is being requested. Then it could check what is current MAGE_RUN_CODE and use it dynamically.
There is a method in Mage_Core_Model_Config which is responsible for getting class name: getGroupedClassName.
Here is the code I used there:
if (strpos($className, 'Pneumatig_') !== false) {
$var = substr($className, 0, strpos($className, '_', strpos($className, '_') + 1));
if (isset($this->_xml->modules->$var)) {
if ((bool)$this->_xml->modules->$var->restricted === true) {
$code = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : 'default';
if (strpos((string)$this->_xml->modules->$var->restricted, $code) !== false) {
$className = '';
}
}
}
}
This Pneumatig condition is because all my modules start from Company name, so i wanted to avoid not necessary processing, but its optional, code should work without it, or you can change it to anything else.
Then I get actual module name [Company]_[Module], and then check if its enabled in _xml (which is current configuration object). If it is restricted I clear $className so it force Magento to load the default in next line.
And this code is added just before is empty condition:
// Second - if entity is not rewritten then use class prefix to form class name
if (empty($className)) {
if (!empty($config)) {
$className = $config->getClassName();
}
if (empty($className)) {
$className = 'mage_'.$group.'_'.$groupType;
}
if (!empty($class)) {
$className .= '_'.$class;
}
$className = uc_words($className);
}
$this->_classNameCache[$groupRootNode][$group][$class] = $className;
return $className;
And for your convenience i paste whole getGroupedClassName code:
public function getGroupedClassName($groupType, $classId, $groupRootNode=null)
{
if (empty($groupRootNode)) {
$groupRootNode = 'global/'.$groupType.'s';
}
$classArr = explode('/', trim($classId));
$group = $classArr[0];
$class = !empty($classArr[1]) ? $classArr[1] : null;
if (isset($this->_classNameCache[$groupRootNode][$group][$class])) {
return $this->_classNameCache[$groupRootNode][$group][$class];
}
$config = $this->_xml->global->{$groupType.'s'}->{$group};
// First - check maybe the entity class was rewritten
$className = null;
if (isset($config->rewrite->$class)) {
$className = (string)$config->rewrite->$class;
} else {
/**
* Backwards compatibility for pre-MMDB extensions.
* In MMDB release resource nodes <..._mysql4> were renamed to <..._resource>. So <deprecatedNode> is left
* to keep name of previously used nodes, that still may be used by non-updated extensions.
*/
if (isset($config->deprecatedNode)) {
$deprecatedNode = $config->deprecatedNode;
$configOld = $this->_xml->global->{$groupType.'s'}->$deprecatedNode;
if (isset($configOld->rewrite->$class)) {
$className = (string) $configOld->rewrite->$class;
}
}
}
//START CHECKING IF CLASS MODULE IS ENABLED
if (strpos($className, 'Pneumatig_') !== false) {
$var = substr($className, 0, strpos($className, '_', strpos($className, '_') + 1));
if (isset($this->_xml->modules->$var)) {
if ((bool)$this->_xml->modules->$var->restricted === true) {
$code = isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : 'default';
if (strpos((string)$this->_xml->modules->$var->restricted, $code) !== false) {
$className = '';
}
}
}
}
//END CHECKING IF CLASS MODULE IS ENABLED
// Second - if entity is not rewritten then use class prefix to form class name
if (empty($className)) {
if (!empty($config)) {
$className = $config->getClassName();
}
if (empty($className)) {
$className = 'mage_'.$group.'_'.$groupType;
}
if (!empty($class)) {
$className .= '_'.$class;
}
$className = uc_words($className);
}
$this->_classNameCache[$groupRootNode][$group][$class] = $className;
return $className;
}
My clients install of Magento 1.8.1.0 has a problematic module that breaks another site's menu on a multi-store setup. The solution above posted by Eric Hainer didn't work for this install, so I altered it slightly:
Instead of using $_SERVER['MAGE_RUN_CODE'], I used $_SERVER['SERVER_NAME']. Worked like a charm. :)
So instead of:
$runCode = (isset($_SERVER['MAGE_RUN_CODE']) ? $_SERVER['MAGE_RUN_CODE'] : 'default');
use:
$runCode = (isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'www.site1.com');
and instead of:
<restricted>mystore1,mystore4,mystore5</restricted>
use:
<restricted>www.site2.com,www.site3.com</restricted>
obviously changing "www.site1.com", "www.site2.com", and "www.site3.com" with your own locations.
Thanks for the idea Eric :)
Also interesting solution ,
http://inchoo.net/ecommerce/magento/how-to-activatedeactivate-magento-module-per-a-website-level/