MySkin: select, create and edit your favorite stylesheet


Theme support available in 1.2!

This page refers to beta functionality supported until Wikka 1.1.x. As of version 1.2 Wikka introduces support for 100%-modular themes: check this page for more information or this tutorial to learn how to design custom themes.
 

Following the suggestions of JsnX and JavaWoman, and using code I had written for the WikkaSkinEditor action, I've created a new action that allows registered users to create their own custom skin and modify it to their taste. Feel free to test it and give your feedback.

Current version: 2.2


2.2
2.1

To do

How to use it


After installing the code (see below), just add to one of your pages {{myskin}} and start playing

How to install it


1. Create the action (actions/myskin.php)

  1. <?php
  2.  
  3. /**
  4.  * Allows users to select alternate skins and to edit their custom skins.
  5.  *
  6.  * This action allows the user to select a skin among those available in
  7.  * the Wikka css folder. A form allows to display the markup of each skin.
  8.  * Registered user can create it and modify their own custom skin. The
  9.  * first creation of a custom user skin consists in the generation of a new
  10.  * css stylesheet containing the default wikka CSS settings (as specified
  11.  * in the Wikka config file) and stored with the name of the user. Once a
  12.  * custom user skin exists, the owner of the skin can modify it, overwrite
  13.  * it with an existing skin, or restore the default settings. Wikka
  14.  * administrators have write access to all the skins.
  15.  *
  16.  * Cookies must be enabled for the selector to work and the css folder must
  17.  * be write-accessible to the script in order to read, edit and save skins.
  18.  *
  19.  * @package     Actions
  20.  * @name        MySkin
  21.  *
  22.  * @author       {@link http://wikka.jsnx.com/DarTar DarTar}
  23.  * @version      2.2
  24.  * @since         Wikka 1.1.X
  25.  *
  26.  * @output       displays a form for selecting alternate skins and edit
  27.  *              custom user skins.
  28.  * @todo       -integrate with UserSettings.
  29.  */
  30.  
  31.  
  32. // get skin names
  33. $defaultskin = $this->config['stylesheet'];
  34. $currentskin = (!$this->GetCookie('wikiskin')) ? $defaultskin : $this->GetCookie('wikiskin'); # JW 2005-07-08 FIX possibly undefined cookie
  35. $postedskin = $_POST["skin"];
  36. $myskin = strtolower($this->GetUserName().".css");
  37.  
  38. // build form chunks
  39. $setskin = '<input type="submit" name="action" value="Set skin" />';
  40. $showsource = '<input type="submit" name="action" value="Show source" />';
  41. $hidesource = '<input type="submit" name="action" value="Hide source" />';
  42. $editsource = '<input type="submit" name="action" value="Edit source" />';
  43. $savesource = '<input type="submit" name="action" value="Save modified source" />';
  44. $createskin = '<input type="submit" name="action" value="Create my skin" />';
  45. $importskin = '<input type="submit" name="action" value="Save current skin as my skin" />';
  46. $restoreskin = '<input type="submit" name="action" value="Restore to default settings" />';
  47.  
  48. // functions
  49.  
  50. function WriteSkin($file, $content){
  51.     $css_file = fopen("css/".$file, "w+");
  52.     fwrite($css_file, $content);
  53.     fclose($css_file);
  54. }
  55.  
  56. function ReadSkin($file){
  57.     $source = fopen("css/".$file, "r");
  58.     $css_content = fread($source, filesize("css/".$file));
  59.     fclose($source);
  60.     return $css_content;
  61. }
  62.  
  63.  
  64. echo $this->Format("=== Select a Wikka skin:  === --- ");
  65. switch ($_POST["action"]) {
  66.  
  67.     case "Save modified source":
  68.     // saves modified skin to file
  69.     WriteSkin($currentskin, $_POST["mod_css_content"]);
  70.     // no break - skin is automatically updated
  71.  
  72.     case "Set skin":
  73.     // change current skin and reload page
  74.     // begin change by AlexRust - May 28 2009
  75.     //$this->SetPersistentCookie("wikiskin", $postedskin);
  76.     $this->SetSkin($postedskin);
  77.     // end change by AlexRust - May 28 2009
  78.     $this->Redirect($this->href());
  79.     break;
  80.  
  81.     case "Save current skin as my skin":
  82.     // import and save current skin as user skin
  83.     if ($this->GetUser() && file_exists("css/".$myskin)) {
  84.         $css_content = ReadSkin($currentskin);
  85.         WriteSkin($myskin, $css_content);
  86.         $this->SetPersistentCookie("wikiskin", $myskin);
  87.         $this->Redirect($this->href());
  88.  
  89.     }
  90.     break;
  91.  
  92.     case "Create my skin":
  93.     // first time user skin creation
  94.     if ($this->GetUser() && !file_exists("css/".$myskin)) {
  95.         $css_content = ReadSkin($defaultskin);
  96.         WriteSkin($myskin, $css_content);
  97.         $this->SetPersistentCookie("wikiskin", $myskin);
  98.         $this->Redirect($this->href());
  99.     }
  100.     break;
  101.  
  102.     case "Restore to default settings":
  103.     // restore user skin to default settings
  104.     if ($this->GetUser() && file_exists("css/".$myskin)) {
  105.         $css_content = ReadSkin($defaultskin);
  106.         WriteSkin($myskin, $css_content);
  107.         $this->SetPersistentCookie("wikiskin", $myskin);
  108.         $this->Redirect($this->href());
  109.     }
  110.     break;
  111.  
  112.     case "Show source":
  113.     // open a readonly textarea with skin source
  114.     $css_contents = ReadSkin($currentskin);
  115.     $showskin = '<textarea id="skinedit" name="display_css_content" cols="80" rows="15" readonly="readonly">'.$css_contents.'</textarea><br />';
  116.     $submit = $hidesource;
  117.     break;
  118.  
  119.     case "Edit source":
  120.     // open an editable textarea with skin source
  121.     $css_contents = ReadSkin($currentskin);
  122.     $showskin = '<textarea id="skinedit" name="mod_css_content" cols="80" rows="15">'.$css_contents.'</textarea><br />';
  123.     $submit = $savesource;
  124.     break;
  125.  
  126. }
  127.  
  128. $handle = opendir('css/');
  129.  
  130. // retrieve skin list
  131. $skinlist = '<select name="skin">';
  132. // put on top of the list the default and custom skin
  133. $defaultselected = ($defaultskin == $currentskin)? " selected=\"selected\"" : "";
  134. $myselected = ($myskin == $currentskin)? " selected=\"selected\"" : "";
  135. $skinlist .= '<option value="'.$defaultskin.'"'.$defaultselected.'>(Default skin: '.$defaultskin.')</option>';
  136.  
  137. if ($this->GetUser() && file_exists("css/".$myskin)) $skinlist .= '<option value="'.$myskin.'"'.$myselected.'>(My skin: '.$myskin.')</option>';
  138.  
  139. // get other skins
  140. $noskinmask = '^('.$defaultskin.'|'.$myskin.'|xml.css|print.css|\.(.*))$';
  141. while (false !== ($file = readdir($handle))) {
  142.     if (!preg_match('/'.$noskinmask.'/', $file)) {
  143.         $selected = ($file == $currentskin)? " selected=\"selected\"" : "";
  144.         $skinlist .= '<option value="'.$file.'"'.$selected.'>'.$file.'</option>';
  145.     }
  146. }
  147. $skinlist .= '</select>';
  148.  
  149. // give write access to the skin owner and to admins
  150. if (!isset($submit)) {
  151.     $submit = ($this->IsAdmin() || $currentskin == $myskin)? $editsource : $showsource;
  152. }
  153.  
  154. // create form
  155. print $this->FormOpen("","","post");
  156. print $skinlist.$setskin."<br /><br />".$showskin.$submit."<br /><br />\n";
  157.  
  158. // show user skin options
  159. if ($this->GetUser()) {
  160.     if  (!file_exists("css/".$myskin)) {
  161.         $mysubmit = $createskin;
  162.     } else {
  163.         $myskinname = "(".$myskin.")";
  164.         $mysubmit = ($currentskin == $myskin)? $restoreskin : $importskin.$restoreskin;
  165.     }
  166.     print $this->Format(" ---- === My skin ".$myskinname." === --- ");
  167.     print $mysubmit;
  168. }
  169.  
  170. // close form
  171. print $this->FormClose();
  172. closedir($handle);
  173. ?>


2. Modify the wikka core (wikka.php)

Add the following code in ./wikka.php immediately after the //COOKIES section.

Note: This section has moved to ./libs/Wakka.class.php, and the following can be placed after the GetCookie($name) function.

Updated 5/5/2009 by PezHore: Corrected the reference of cookie 'skin' to 'wikiskin', and changed the cookie retrieval from $skin = $_COOKIE['wikiskin] to use GetCookie function. Also removed the duplicate functions

    // SKINS
    function GetSkin()
    {
        if ($this->GetUser())
        {
            $skin = $_SESSION['wikiskin'];
        } else
        {
            if ($_COOKIE['wikiskin'])
            {
                $skin = $this->GetCookie('wikiskin');
            } else
            {
                $skin = $this->GetConfigValue("stylesheet");
            }
        }
        return $skin;
    }

    function SetSkin($skin)
    {
        if ($this->GetUser())
        {
            $_SESSION['wikiskin'] = $skin;
        } else
        {
            $this->SetPersistentCookie('wikiskin', $skin);
        }  
    }


3. Modify the Wikka Header (actions/header.php)

To allow skin selection a small modification of the header is needed:

original actions/header.php
<link rel="stylesheet" type="text/css" href="css/<?php echo $this->GetConfigValue("stylesheet") ?>" />


modified actions/header.php
<link rel="stylesheet" type="text/css" href="css/<?php echo $this->GetSkin() ?>" media="screen" />


4. Add the following system options

original wikka.config.php
      "stylesheet" => "wikka.css",


modified wikka.config.php
      "stylesheet" => "wikka.css",
      "allow_select_skin" => "1",
      "display_custom_skins" => "1",
      "allow_create_custom_skin" => "1",
      "allow_display_skin_source" => "1",



Understanding the system options




CategoryUserContributions CategoryLayout
Comments
Comment by JavaWoman
2005-07-14 16:02:16
This page is referred to from the WikkaBetaFeatures page as a development page - but I could not find the actual code presented here on the server - particularly the core functions referred to. There is a myskin action - but the code is different.

What exactly is the status of this page / code?

I'm asking because I ran into a bug with the beta code as present on this site (actually caused by the GetCookie() method but turning up as a problem with skins), and fixed it - this involves (mostly small) changes to:
wikka.php (GetCookie() method)
actions/editskin.php
actions/header.php
actions/myskin.php
actions/selectskin.php
actions/skin.php

I am not sure whether code on this page needs to be changed accordingly.
Comment by DarTar
2005-07-15 10:32:36
The code on this page is actually an improved version of myskin.php (version 2.1), which I have never uploaded to the server (especially after the issues on the skin test server), whereas the original code, which is running on this server and which you fixed, was version 1.0 (as announced in the link at the top of this page). The original code is still available here: http://wikka.jsnx.com/MySkin/show?time=2004-12-09+12%3A05%3A37
Comment by JavaWoman
2005-07-15 11:31:42
Hmm - glancing over the code it looks as though the GetSkin() method will need the same type of fix as it doesn't check whether a cookie named 'skin' exists. Same for a session variable as well.

In case the session variable doesn't exist, it will also have to default to the config setting.

Possibly superfluous explanation:
if ($somevar) assumes $somevar exists and you can evaluate its value as a boolean.
if (isset($somevar)) evaluates whether $somevar exists - which one needs to verify (or be absolutely certain of) before evaluating something that may not exist.
Comment by DarTar
2005-07-15 22:59:42
Yes, I'll take a look at the code and fix it, thanks.
Comment by GiorgosKontopoulos
2005-10-07 23:22:10
Maybe I've encountered the same problem as JW.
But when changing the default_stylesheet in wikka.config.php from the CPANEL in my shared server and then running the site, I get different skin from each of IE,OPERA and FF browsers on my computer, (in all the cases I am not being logged in - viewing site as a visitor) I don't get it ?
Comment by DarTar
2005-10-11 08:19:55
Giorgos, thanks for pointing this out. I'll take a look at the code in the next days.
Comment by cpe-68-174-164-241.nyc.res.rr.com
2005-10-19 13:54:24
Added the code changes for Myskin, but something is wrong - Getskin() is not being run properly for some reason, resultinging in a null css skin being inserted into the header, i.e.

<link rel="stylesheet" type="text/css" href="css/" media="screen" />

- Rich S
Comment by DarTar
2005-10-20 08:45:05
Rich, please make sure:
- you have a line for "stylesheet" in wikka.config.php (it was called "default_stilesheet" in version 2.1)
- the value for "stylesheet" is the name of an existing stylesheet in your css/ folder which the server can access.

Once you've checked these points, please tell me whether you are having this issue as a logged-in or anonymous user (in case you are logged-in, make sure your browser is set to accept cookies).
Comment by c220-237-177-122.lowrp1.vic.optusnet.com.au
2005-10-23 14:33:22
Hi guys, I have followed the above instruction but have been unable to get skins to work, as far as 'setting' a skin is concerned. Everything seemed to work ok but no visual changes were made. The cookies were being set correctly but nothing was happening. The html contained a reference to 'css/' , ie blank.
It looked to me as if most of the code was relying on setting a cookie but the GetSkin() function was actually accessing the $_SESSION var instead of the cookies. My quick fix was to add
$_SESSION['wikiskin'] = $postedskin;
after line 74 of myskin.php.
Please note that this is the 1st time ever i've looked at PHP
(though I've been developing software for far too long :-)
)
It is quite possible I've missed something obvious. It would be great if someone could help me out. Cheers, Nick Damoulakis
Comment by 218.185.0.4
2005-10-24 09:43:35
...also, there appear to be 2 copies of the ReadSkin() and WriteSkin() functions; one in myskin.php and one in wikka.php.
Is that correct?
Cheers, Nick Damoulakis
Comment by DarTar
2005-10-26 08:16:30
Nope, it's not. :)
Thanks for pointing this out. I'll try to fix the above issues (which seem to be reported by several users) asap.
Comment by DarTar
2005-10-26 08:17:07
BTW if you register on this website, I can give you further feedback on how to get skins to work.
Comment by NickDamoulakis
2005-10-26 16:35:05
Hi DarTar, I've now registered, so you can contact me if you wish, regarding the skin issues I raised. Cheers,Nick Damoulakis
Comment by GiorgosKontopoulos
2005-10-27 03:20:25
Installed it again and now it seems to have other issues:

1)Set skin button does not seem to actually change the skin!!

I am running two Wikka's on my server. (A and B lets say)
On A I am not able to change skins but on B it could be done
but now any skin I change on the B installation is reflected on the A.

I don't think its a matter of the installations being on the same server but ruther the fact that both look for the same cookie in my PC.

For more info look on WikkaBugs.
Comment by DarTar
2005-10-27 08:43:26
Giorgos, your explanation of the bug looks to me the right one.

For the time being (waiting for an actual "CSS release") you might want to take a look at this unofficial development package, that issues a (woking) skin editor/selector based on the new template:

http://dartar.free.fr/code/
Comment by GiorgosKontopoulos
2005-10-27 17:45:29
DarTar, tried your dev install, it behaves better but still the session is leaking from one installation to the other (if I change css in one install it gets reflected in the other - the simple revelation of the bug)

I was wondering if you create cookies with something unique in them so it would be different in each install, I am looking at something like this, but I am still new to the code and I am not sure how to implement it yet.
Comment by NickDamoulakis
2005-11-01 15:16:20
After a lot of pain (through no fault of the authors!!!), I've finally nailed why it hasn't been working consistently for me. I'd make some changes and it'd work when not-logged-in. Some others would make it work when actually logged-in. To start with, it took me a while to realise that it behaved differently (I was always logged in).
In any case, the fault appeared to always be with setting/getting session info.
I finaly clicked and looked at my PHP INI file, which had a line in it specifying the sessions dir as './session', which doesn't work. It looks like relative paths are not supported, so I changed it to 'H:/PHP5/sessions' and all is now well.

I hope this may help anyone else tripping over this.
btw, I used the SKIN.PHP file from the 1.1.6dev version with the appropriate mods in WIKKA.PHP.
Comment by MonstoBrukes
2005-11-14 08:50:07
it's recently been outed that ie will be stupid (surprise) and accept javascript buried in css files. I don't know if you are or not already doing so, but you might want to process the css file before save to make sure tht isn't happening.
Comment by DarTar
2005-11-14 10:57:50
Thanks, noted.
Comment by dsl-203-113-234-164.ACT.netspace.net.au
2005-11-27 00:03:04
I fixed the problems I was having with Getskin() by changing referrals to the cookie to "wikiskin" rather than just "skin" - as "wikiskin" is created by the myskin.php action.
Comment by MikeBev
2005-12-31 06:22:42
I have same basic issue as described above, even after three times going through each change described in the instruction. I did not attempt any of the user fixes listed in the comments. If I don't log in, the page grabs the wikka.css skin and looks fine. If I log in, I basically revert to no skin at all and the Set Skin feature does nothing.

Running this on a test site http://mbev.net/melissa
My main site http://mbev.net/wikka (I love the Wikka Wakka Wiki software - THANKS)
Comment by DarTar
2005-12-31 13:27:56
Mike, the hack in the previous comment should fix your issue. Apologies for the annoying bugs in the code, as soon as I have time I'll completely rewrite this action.
Comment by MikeBev
2005-12-31 21:54:36
DarTar, I tried every combination of changing "skin" to "wikiskin", even changing single quotes (') to double quotes (") in the //Skin section under step 2 above. It works great untill I log on. I can confirm the cookie "wikiskin" is getting set. When I log on the code disconnects me from the chosen skin and cant find a style sheet to set me to.

I tried setting every occurance of "skin" to "wikiskin" (shown in red under step 2) and tried setting every combination of changing only some of them.

Sorry for being so ignorant about coding... see http://mbev.net/melissa/MikeBevington
Comment by NickDamoulakis
2006-01-01 13:22:11
Hi MikeBev, have you checked the session_dir setting in your PHP.INI? I found that unless the dir it points to exists *and* I have r/w access to it, I get problems similar to yours.
Cheers,
Nick
Comment by MikeBev
2006-01-03 01:08:30
Thanks for trying to help Nick, but I can't find a file by that name on my server. I have an INI.PHP but no joy there. If I did find it, I am not aware of how to change write access to it within the server itself.
Comment by BrianKoontz
2006-02-11 22:23:33
MikeBev, I had the same problem as yours. Besides the inconsistent cookie naming convention (either make them all 'skin' or 'wikiskin'), this fix from earlier fixed the problem for me:

=====
It looked to me as if most of the code was relying on setting a cookie but the GetSkin() function was actually accessing the $_SESSION var instead of the cookies. My quick fix was to add
$_SESSION['wikiskin'] = $postedskin;
after line 74 of myskin.php.
=====

If your sessions have been working up to this point, I doubt it's a php.ini config issue...
Comment by BrianKoontz
2006-02-11 22:48:58
If you want to populate your css/ dir with the latest stylesheets from wikkawiki, this will do the trick:

wget -r -l1 -nd --no-parent -A.css http://wikkawiki.org/css/

Maybe a nightly tarball of .css files might be a more bandwidth-friendly alternative...

Also, I would suggest adding the following to about line 140 of myskin.php to ensure that only .css files are make available in the skins dropdown box:

if (!preg_match('/'.$noskinmask.'/', $file) &&
preg_match('/^.*\.css$/', $file)) {

(There's probably a more graceful way to do this with only one regexp, but I didn't spend a lot of time on this.)
Comment by 24.1.211.91
2006-02-12 19:24:16
It appears that with these changes, the fonts that are specified in wikka.css are ignored when printing (and presumably, using the print.css stylesheet). You can demonstrate it by doing a print preview of this page: The sans serif font in wikka.css is replaced by a serif font when you attempt to print this page. I'm not a CSS expert, but it appears to have something to do with the added "media='screen'" attribute in the header.php change.
Comment by DarTar
2006-02-13 06:35:17
It's correct: "media='screen'" should be dropped if print.css is to make use of css selectors specified in wikka.css.
Comment by 59.167.6.55
2006-05-23 12:05:06
To get it to work for me, I changed all occurances of $_SESSION['skin'] and $_COOKIE['skin'] in wikka.php to $_SESSION['wikiskin'] and $_COOKIE['wikiskin'].
And change this:
if ($this->GetUser())
{
//$skin = $_SESSION['wikiskin'];
$skin = $_COOKIE['wikiskin'];
}

-- fatcop
Comment by LarryR
2006-08-18 10:27:24
I was trying to run this on a Wikka installation I am playing with and have some questions. Step 2 says "Add the following code in ./wikka.php immediately after the //COOKIES section" however, I do not find a section with this name. Am I missing something? Is this extension stable enough to install on my Wikka site?
Comment by NilsLindenberg
2006-08-18 16:38:24
LarryR, if you are using the latest version (i.e. 1.1.6.2), there is a file called Wakka.class.php in the /libs dir in which you should find the //COOKIES section.
Stable? It is always a good idea to backup your tables :) I am not sure if the last open issue with users creating their own skin was resolved so perhaps it is better to disable this for the moment?
Comment by YodaHome
2006-08-18 16:39:48
If you use the latest version of Wikka (1.1.6.2) then this code has in fact been moved to /libs/Wakka.class.php. As to your question regarding stability: it works well (I use it on my site for about a year now) but the more extensions you apply to WikkaWiki the more you should watch out what you change. It's good to know exactly what your doing.
Comment by DuK
2006-11-05 08:08:20
what about security? allowing users to edit their own style should stripp some tags
(like: expression, moz-binding, content, behavior, include-source,..)
thanks a lot for the great contribution!!
Comment by DaC
2007-01-04 13:02:30
Thanks for the extension although I had some trouble installing it (inconsistend cookies, had to remove cookie-suffic etc.) but in the long run it works as advertised.

One thing: Are the system options are already evaluated? I want my users to be able to select a skin but not change anything. I set all options except "allow_select_skin" to 0 but it seems to have no effect. I can't find any reference to those options in the source code.

I helped myself and commented out the write function of myskin.php, but this is a pretty "dumb" workaround.

Any hints?
Comment by GrahamKelly
2009-05-13 10:58:52
Thanks for providing code to break my wiki....now all my pages are displaying blank!
Comment by MasinAlDujaili
2009-05-13 11:56:31
What do you mean by 'blank'? There's absolutely nothing besides white color in the window? If that's the case, there might be missing some closing braces or semi-colon somewhere.

I cannot test it right now. But maybe in section 3 of the modification there has to be a semi-colon right before '?>'. Section 2 looks correct. I cannot test section 1 right here.
Comment by BlueGray
2010-09-15 02:36:12
I am following the "how to install" steps above. Steps 1 & 2, no problem, believe I have it correct. Step 3, I did not find a header file in the actions folder only in the "Templates/(template name)" directories. Inside the header file, I did not find an exact "stylesheet" match for step 3. There were four stylesheet commands in the file. Step 4, found the file but did not find a "stylesheet.." command inside the file. Only command was "'stylesheet_hash' => '2cbab');".
Please let me know if I am in the right files and/or what I should do to complete steps 3 & 4. My objective is to create a custom skin so the wiki pages have a simialr look and feel to my HTML pages. "thank you" in advance for your time and help.
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki