Archive for the 'Programming' Category

jQuery Cookie Pluging Extended With HTML5 localStorage And Chunked Cookies

Is there a web developer that never used cookies to save some information in a user’s browser? There may be, but they should be legion. As you probably know, the problem with cookies is that their implementation in browsers is random: some will limit the size of the cookie to 4096 bytes, others will limit the number of cookies from a specific domain to 50, others will have no perceivable limits, etc.


In any case, if one of these limits is reached, the cookie is simply not created the browser. This is fine, because web developer expects cookies to fail from time to time, and the system they develop has to cope with this unreliableness. However, this situation can sometimes become frustrating, and it is why I wanted to extend the default behavior of the jQuery Cookie plugin with a few more capabilities.

This extension to the jQuery Cookie plugin adds the capability to save content that is bigger than 4096 bytes long using two different mechanism: the usage of HTML5′s localStorage, or the usage of a series of cookies where the content is chunked and saved. This extension is backward compatible with the jQuery Cookie plugin and its usage should be transparent to the users. Even if existing cookies have been created with the normal Cookie plugin, they will still be usable by this new extension. The usage syntax is the same, but 3 new options have been created.

Now, let’s see how this plugin works, how developers should use it, what are its limitations, etc.

You can immediately download the jQuery Extended Cookie plugin from here:

Limitations Of Cookies

First, let’s see what the RFC 2109 says about the limitations of cookies in web browsers. Browsers should normally have these implementation limits (see section 6.3):

   Practical user agent implementations have limits on the number and
   size of cookies that they can store.  In general, user agents' cookie
   support should have no fixed limits.  They should strive to store as
   many frequently-used cookies as possible.  Furthermore, general-use
   user agents should provide each of the following minimum capabilities
   individually, although not necessarily simultaneously:

      * at least 300 cookies
      * at least 4096 bytes per cookie (as measured by the size of the
        characters that comprise the cookie non-terminal in the syntax
        description of the Set-Cookie header)
      * at least 20 cookies per unique host or domain name

   User agents created for specific purposes or for limited-capacity
   devices should provide at least 20 cookies of 4096 bytes, to ensure
   that the user can interact with a session-based origin server.

   The information in a Set-Cookie response header must be retained in
   its entirety.  If for some reason there is inadequate space to store
   the cookie, it must be discarded, not truncated.

   Applications should use as few and as small cookies as possible, and
   they should cope gracefully with the loss of a cookie.

New Options

Before I explains how this extension works, let me introduce three new options that have been added to the Cookie plugin. These new options will be put into context, and properly defined later in this blog post.

  • maxChunkSize - This defines the maximum number of bytes that can be saved in a single cookie. (default: 3000)
  • maxNumberOfCookies - This is the maximum number of cookies that can be created for a single domain name. (default: 20)
  • useLocalStorage - This tells the extended Cookie plugin to use the HTML5′s localStorage capabilities of the browser instead of a cookie to save that value. (default: true)

How Does This Extension Works?

As I said in the introduction of this blog post, this extension to the jQuery Cookie plugin does two things:

  1. It uses the HTML5 localStorage capabilities of the browser if this feature is available instead of relying on the cookies. However, if cookies are needed by the developer, this feature can be turned off with the useLocalStorage = false option
  2. If the localStorage option is disable, or simply not available on a browser, and if the content is bigger than the limit of the size of a cookie, then this extension will chunk the input content, and save it in multiple cookies

If the useLocalStorage is true, then the plugin will try to see if the HTML5 localStorage mechanism is available on the browser. If it is, then it will use that local storage to save and retrieve content to the browser. If it is not, then the plugin will act like if useLocalStorage is false and the process will continue by using cookies to save and read that content from the browser.

If useLocalStorage is false, or if the HTML5 localStorage mechanism is not available on the browser, then the plugin will check if the content is bigger than the maxChunkSize option, than all the chunks will be saved in different cookies until it reaches the limit imposed by the maxNumberOfCookies option.

If cookies are used, then two use-cases can happen:

  1. The content is smaller than or equal to maxChunkSize
  2. The content is bigger than maxChunkSize

If the content is smaller than or equal to maxChunkSize than only one cookie will be created by the browser. The name of the cookie will be the value provided to the key parameter.

If the content is bigger than maxChunkSize than multiple cookies will be created, one per chunk. The convention is that the name of the first cookie is the value provided to the key parameter. The name of the other chunks is the value provided to the key parameter with the chunk indicator ---ChunkNum append to it. For example, if we have a cookie with a content of 10000 bytes that has maxChunkSize defined to 4000 bytes, then these three cookies would be created:

  • cookie-name
  • cookie-name---1
  • cookie-name---2

Usage

Now, let’s see how this extended jQuery Cookie plugin should be used in your code. The usage of the extension is no different from the usage of the normal jQuery Cookie plugin. However, I am showing how to use the new options along with how to use the plugin in general.

Create a Cookie

Let’s create a cookie that expires in 365 days and where the path is the root:

$.cookie('my-cookie', "the-content-of-my-cookie", { expires: 365, path: "/" });

By default, this value will be persisted in the localStorage if the browser supports it, and not in a cookie. So, let’s see how to force the plugin to save the content in a cookie by using the useLocalStorage option:

$.cookie('my-cookie', "the-content-of-my-cookie", {useLocalStorage: false, expires: 365, path: "/" });

Delete a Cookie

Let’s see how a cookie can be deleted. The method is simply to put null as the value of the cookie. This will instruct the plugin to remove the cookie.

$.cookie('my-cookie', null);

With that call, the plugin will try to remove my-cookie both in the localStorage and in the cookies.

Read a Cookie

Let’s see how we can read the content of a cookie:

var value = $.cookie('my-cookie');

With this call, value will get the content that has been saved in the localStorage, or the cookies. This will depend if the localStorage was available in the browser.

Now, let’s see how to force reading the cookies by bypassing the localStorage mechanism:

var value = $.cookie('my-cookie', {useLocalStorage: false});

Note that if the cookie is not existing for a key, then the $.cookie() function will return null.

Using Limitations

Let’s see how to use the maxNumberOfCookies and maxChunkSize options to limit the size and the number of cookies to be created.

With this example, the content will be saved in multiple cookies of 1000 bytes each up to 30 cookies:

var value = $.cookie('my-cookie', "the-content-of-my-cookie-is-10000-bytes-long...", {useLocalStorage: false, maxChunkSize  = 1000, maxNumberOfCookies = 30, expires: 365, path: "/" });

Limitations

Users have to be aware of the limitations of this enhanced plugin. Depending on the browser, the values of the maxChunkSize and the maxNumberOfCookies options should be different. In the worse case, some cookies (or cookies chunks) may simply not be created by the browser. As stated in the RFC 2109, the web applications have to take that fact into account, and be able to gracefully cope with this.

Future Enhancements

In the future, this extension should detect the browser where it runs, and setup the maxChunkSize and the maxNumberOfCookies parameters automatically depending on the cookies limitation of each browser.

Conclusion

I had to create this extension to the jQuery Cookie plugin to be able to store the resultsets returned by some web service endpoints. It is only used to limit the number of queries sent to these endpoints. Since the values returned by the endpoints are nearly static, that they are loaded at each page view and that they are a few kilobytes big, I had to find a way to save that information in the browser, and to overcome the size limitation of the cookies if possible. I also needed to be able to cope with older versions of browsers that only supports cookies. In the worse case scenario, the browser will simply send the request to the endpoints at each page load for the special use-cases where nothing works: not the cookies and not the localStorage. But at least, my application will benefit of this enhancement from the 95% of the users were one of these solutions works.

Moving Projects from Google Code to GitHub

Last week we slowly migrated Structured Dynamics‘ Google Code Projects to GitHub.We have been thinking about moving to GitHub for some time now, but we only wanted to move projects to it if no prior history and commits were dropped in the process. One motivation for the possible change has been the seeming lack of support by Google for certain long-standing services: we are seeing disturbing trends across a number of existing services. We also needed a migration process that would work with all of our various projects, without losing a trunk, branch, tag or commits (and their related comments).

It was not until recently that I found a workable process. Other people have successfully migrated Google Code SVN projects to GitHub, but I had yet to find a consolidated guide to do it. It is for this last reason that I write this blog post: to help people, if they desire, to move projects from Google Code to GitHub.

Moving from Google Code to GitHub

The protocol outlined below may appear complex, but it looks more intimidating than it really is. Moving a project takes about two to five minutes once your GitHub account and your migration computer is properly configured.

You need four things to move a Google Code SVN project to GitHub:

  1. A Google Code project to move
  2. A GitHub user account
  3. SSH keys, and
  4. A migration computer that is configured to migrate the project from Google Code to GitHub. (in this tutorial, we will use a Ubuntu server; but any other Linux/Windows/Mac computer, properly configured, should do the job)

Create GitHub Account

If you don’t already own a GitHub account, the first step is to create one here.

Create & Configure SSH Keys

Once your account has been created, you have to create and setup the SSH keys that you will use to commit the code into the Git Repository on GitHub:

  1. Go to the SSH Keys Registration page of your account
  2. If you already have a key, then add it to this page, otherwise read this manual to learn how to generate one

Configure Migration Server

The next step is to configure the computer that will be used to migrate the project. For this tutorial, I use a Ubuntu server to do the migration, but any Windows, Linux or Mac computer should do the job if properly configured.

The first step is to install Git and Ruby on that computer:

1
 sudo apt-get install git-core git-svn ruby rubygems

To perform the migration of a Google Code SVN project to GitHub, we are using a Ruby application called svn2git that is now developed by Kevin Menard. The next step is to install svn2git on that computer:

1
 sudo gem install svn2git --source http://gemcutter.org

Migrate Project

Before migrating your project, you have to link the Google Code committers to GitHub accounts. This is done by populating a simple text file that will be given as input to svn2git.

Open the authors.txt file into a temporary folder:

1
 sudo vim /tmp/authors.txt

Then, for each author, you have to add the mapping between their Google Code and GitHub accounts. If a Google Code committer does not exist on GitHub, then you should map it to your own GitHub account.

1
2
 (no author) = Frederick Giasson <fred@f...com>
 fred@f...com = Frederick Giasson <fred@f...com>

The format of this authors.txt file is:

1
 Google-Account-Username = Name-Of-Author-On-GitHub <Email-Of-Author-On-Github

Take note of the first Google Code committer (no author) mapping. This link is required for every authors.txt file. This placeholder is used to map the initial commit performed by the Google Code system. (When Google Code initializes a new project, it uses that username for creating the first commit of any project.)

When you are done, save the file.

Now that set up is complete, you are ready to migrate your project. First, let’s create the folder that will be used to checkout the SVN project on the server, and then to push it on GitHub.

1
2
3
cd /tmp/
mkdir myproject
cd myproject

In this tutorial, we have a normal migration scenario. However, your migration scenario may differ from this one. It is why I would suggest you check out the different scenarios that are supported by svn2git document. Change the following command accordingly. Let’s migrate the Google Code SVN Project into the local Git repository:

1
 /var/lib/gems/1.8/bin/svn2git http://myproject.googlecode.com/svn --authors /tmp/authors.txt --verbose

Make sure that no errors have been reported during the process. If it is the case, then refer to the Possible Errors and Fixes section below to troubleshoot your issue.

The next step is to create a new GitHub repository where to migrate the SVN project. Go to this GitHub page to create your new repository. Then you have to configure Git to add a remote link, from the local Git repository you created on your migration computer, to this remote GitHub repository:

1
 git remote add origin git@github.com:you-github-username/myproject.git

Finally, let’s push the local Git repository master, branches and tags to GitHub. The first thing to push onto GitHub is the SVN’s trunk. It is done by running that command:

1
 git push -u origin master

Then, if your project has multiple branches and tags, you can push them, one by one, using the same command. However, you will have to replace master by the name of that branch or tag. If you don’t know what is the exact name of these branches or tags, you can easily list all of them using this Git command:

1
 git show-ref

Once you have progressed through all branches and tags, you are done. If you take a look at your GitHub project’s page, you should see that the trunk, branches, tags and commits are now properly imported into that project.

Possible Errors And Fixes

Fatal Error: Not a valid object name

There are a few things that can go wrong while trying to migrate your project(s).

One of the errors I experienced is a "fatal" error message "Not a valid object name". To fix this, we have to fix a line of code in svn2git. Open the migration.rb file. Check around the line 227 for the method fix_branches(). Remove the first line of that method, and replace the second one by:

1
 svn_branches = @remote.find_all { |b| !@tags.include?(b) && b.strip =~ %r{^svn\/} }

Error: author not existing

While running the svn2git application, the process may finish prematurely. If you check the output, you may see that it can’t find the match for an author. What you will have to do is to add that author to your authors file and re-run svn2git. Otherwise you won’t be able to fully migrate the project.

I’m not quite sure why these minor glitches occurred during my initial migrate, but with the simple fixes above you should be good to go.

Open Sources Projects As A Pool Of Resources

In a previous blog post, I wrote about how Open Source may be unnatural, and even counter intuitive, to many people. However, that really begs some questions evident with my current company's strategy.

Why have Mike Bergman and I chosen to develop no less than three major open source projects (structWSF, conStruct and the Semantic Components), encompassing more than 100 000 lines of new code and leveraging between 30 to 50 other open source software and libraries? Why have we open sourced all our software? Why has open source formed the core business strategy of Structured Dynamics in the last three years? How have we been able to profitably sustain the company, even in the midst of the global economic crisis that began in 2008?

I will try to answer these questions in this blog post, perhaps even providing some guidance for newer startups that may follow behind us.

Why Open Sourcing?

Why did Structured Dynamics chose to open source all of its software? There are multiple reasons why people and businesses choose to go open source. For some, it is because they think that it is where the market place is moving. For others it is because they think that a community will emerge around their effort, and then get free resources that improve the piece of software. Some think that their software will promptly be reviewed by professional programmer. Others may think that their system will become more secure. Etc.

For Structured Dynamics the reason why we choose to go open source is somewhat different:

We perceived that by open sourcing our complete software stack we could bootstrap the company without any external investment.

Making a Living out of Open Source Projects

There are multiple ways to do a living from an open source project:

  • Doing consultancy work related to the project
  • Implementing the software(s) into clients’ computer environment(s)
  • Selling training classes
  • Selling support contracts
  • Selling maintenance contracts
  • Selling hosted instances of the software (the SaaS model for one)
  • Selling development time to improve some part(s) of the software
  • Creating conferences around their open source projects
  • Selling proprietary extensions
  • I am probably missing a few, so please add them in a comment section below, and I will make sure to add them to this list.

Depending on the software you are developing, and depending on the business plan of your company, you may be doing one — or multiple — of these things to generate some money from your open source projects.

At Structured Dynamics we are doing some of them: we do get consultancy contracts related to the Open Semantic Framework and we do implement OSF in our clients’ computer environments.

But, more importantly, we are also doing development contracts related to the framework. In fact, each project we are working on is quite different. Our major projects involve companies that reside in totally different domains, have different needs and need to accommodate different kinds of users. However, most of the projects share the same core needs, and all of them advance the core technology in ways meaningful to our vision. We choose our customers — and , of course, vice versa — based on a true sense of partnership wherein both parties have their objectives furthered.

Let’s see how we use these relationships to drive the development of the Open Semantic Framework.

Open Source Project as a Pool of Resources

In the last three years, Structured Dynamics has attracted multiple companies and organizations that share our vision, and which are willing to invest in the Open Semantic Framework open source project. (See Mike's recent post on business development for a bit more on that aspect of things.) Each of these clients did want to use the OSF framework for their own needs. However, each of them did want to do something special that was not currently implemented in the framework.

What we created in these three years is a pool of resources that we used to develop the framework such that it accommodates the needs of each of our clients. Each of our clients then becomes a participant to the shared pool of innovation. Our clients have been willing to invest in the open source framework because they need their own features and because they know that they will benefit from what other participants of the pool will invest themselves down the road.

In that scenario, we are the managers of a pool of resources. We have the vision of where we want the framework to go, we know the roadmap of the project and we know the needs of each participant (our clients). What we do is to try to optimize the resources we get from each of our clients by developing the framework such that it can accommodate as broad of a spectrum of participants as possible. Then, we seek to find new participants that have some needs that will help us continue to develop the next steps of the roadmap. In this manner, we Jacob's Ladder our existing work to increase the capabilities for later clients, but earlier clients still benefit because they can upgrade to the later improvements. This is a self-sustaining model to continue to move the development of the framework forward.

By finding new clients, what we do is to give a return on investment to the other pool participants. Most of the new features that we develop for these new clients will benefit the other participants to the pool and will create new possibilities for them without any additional investment. All of our first clients have implemented what other participants later invest into the pool, thus crystallizing and augmenting their return on investment by using these new features.

Open Source is Not Just About Software

Open Source is not just about pieces of code, and this is quite important to understand. What we have open sourced with the Open Semantic Framework is much more than a series of code sources. We open sourced the entire framework:

  1. The source codes
  2. The documentation
  3. The processes
  4. The methodologies

We term this comprehensive approach our total open solution.

This distinction with other open source projects is an essential differentiator with our approach. We choose to open source all of the pieces related to the framework. What drove this decision is a simple sentence that shows our philosophy behind it:

"We're Successful When We're Not Needed"

If the APIs, processes and methodologies are not properly documented, it means that we would certainly be needed by our clients, which would mean that we failed to open source our solution. But since we are working to open source our code, our processes and our methodologies, we are on the way to successfully open source the Open Semantic Framework since we won’t be needed by our clients.

This business approach is not as crazy as it sounds. We are free to work on new and important innovations, and are not basing our company culture on dependency and a constant drain by our customers. I know, it does not sound like Larry Ellison, but sounds good to us and our clients. It is certainly not a maximum revenue objective built on the backs of individual clients.

Our life is more fun and our clients trust us with new stuff. Further, each step of the way, we are able to leverage our own framework for unbelievable productivity in what we deliver for the money. But that is a topic for another day.

We think Structured Dynamics' business approach is a contemporary winning strategy. Our customers get good and advanced capabilities at low cost and risk, while we get to work on innovative extensions that are raising the semantic baseline for the marketplace. Who knows if we will always continue this path, but for now it is leading to sustained development and market growth for open semantic frameworks, including our own OSF.

 

 

Unnatural Open Source

I have never been an open source software advocate. In fact, like most people, I always wondered how companies could find a business advantage in developing open source softwares and how they could make money out of it to grow. It is nice to have open source softwares, but it is hard to imagine how you could justify putting thousands of hours in open source software projects if it is not only by passion.

In this post I will explain what I think is the main factor that put people, businesses and organizations on guard when come the time to think about open source softwares. In fact, I think it has much more to do with our nature: how we naturally are as human being, and much less to do with any real business related factors.

In a follow-up blog post, I will explain how Structured Dynamics embraced open source software, how we developed the company around the concept, and how we are managing the development of our project such that it benefits all our clients along with the company. But first, let’s try to figure out why much people are suspicious regarding open source softwares.

The Fear

"I must not fear. Fear is the mind-killer. Fear is the little-death that brings total obliteration. I will face my fear. I will permit it to pass over me and through me. And when it has gone past I will turn the inner eye to see its path. Where the fear has gone there will be nothing. Only I will remain."

- Dune, Frank Herbert

Have you ever heard someone telling you:

I found an incredible business idea! I am pretty sure that I am the first one to think about that. I will get some good money down the road!

Then, you naturally asked for more information about this great idea! And then the answer you got was something like:

Hooo! But I can’t tell you, this is really secret right now, at least until everything is ready to go.

Does this sound familiar? I does to me. I hear it often. But, why does people react that way? It is simply by fear: fearing that someone “steal” their ideas, start a company based on them, build projects or services that implemented them, and get rich while you are flipping burgers at McDonald’s.

To me, this is the main reason why people, organizations and businesses are suspicious regarding open source software: because of fear; fear of loosing something they don’t even have.

But the question is: is that rational? From my experience, and my understanding of how things works, I can certainly say that it is not. This way of thinking is not rational because it doesn’t take into account a few things:

  • The ability of others to do something with your ideas
  • The ability of others to have the vision you have for your ideas
  • The willingness of others to spend all their time and energy to make these ideas working
  • People tend to do what they want to do, and not what others wants­

The same behavior seems to happen with open source projects. When I am explaining to people what we are doing, one of the first reaction is: why your work is open and free? Don’t you fear that someone steal your project and ideas? How can you make money if it is free, people will just run with it for themselves no?

The simple answer to all these question is: no. No we don’t feature that anybody steal our projects and ideas just by cloning them from the source control. We don’t because of the four reasons listed above. We don’t because we trust our vision and our abilities to implement it in our various open source projects. And yes we can sustain the company pretty well with these projects and it is what I will cover in my following blog post.

Conclusion

Non-Open Source softwares are just like when someone has a business idea “for the next big thing” and that doesn’t want to share it with anybody else because he think that someone will take that idea and run with it by himself. In fact, it is quite the opposite. I learned with experience that there is only one person (or organization) that can make such a great idea a relative success: the person (or organization) that lives for that idea. An idea is just an idea, and has nothing great in it, until it gets implemented, until the idea lives by itself, propelled by it most dedicated advocate: its creators and their boundless enthusiasm. Any idea would fail without this… and would worth nothing; it would just be an idea.

WordPress’s Follow Button for Non-WordPress.com Users

About two weeks ago, the WordPress.com team released a wonderful new tool called the Follow Button to all theirs WordPress.com users. This button is floating in the bottom-right corner of a blogs and let readers subscribing, by email, to the blog’s publications. Each time a new blog post is published, they receive an update in their inbox.

The idea is far from new, and may even looks like old-school. However, the implementation they did is simple, really well done and really clever. Also, the wording they used in the tool is perfect (for example, using the word Follow instead of Subscribe).

The only problem is that this wonderful new tool is only available for WordPress.com users! As you may know, this blog is using WordPress, but it is a self-hosted instance. After doing some research, I couldn’t find any plugins or methods to install it on my blog. Also, the email service under this user interface is built into WordPress.com. As last resort, I checked their Jetpack plugin, to see if it got added the Follow Button to it, but apparently they didn’t (it is probably too recent).

So, I was in a dilemma: I wanted this feature for my blog, I didn’t want to migrate everything to WordPress.com, and I didn’t had the time to write a plugin that does exactly this. So what I did is to take a few hours to hack my own Follow Button using what is already existing out there. In fact, I have been quite surprised to see how easy it turned out to be.

It as been as easy as installing the really good Subscribe2 plugin and to create the UI, from the original Follow Button using some HTML, CSS and JQuery code. After some re-wiring, I ended-up with my own self-hosted Follow Button.

This is what I want to share with you here, in this Hors Série blog post. I am pretty sure that many self-hosted WordPress blogger will want it, so I took an additional hour to write and publish this blog post.

I did two additional “improvements” to the concept:

  1. I changed the icon to put some color in there. Not only to make it less dull, but also to bring a little bit mo attention to it.
  2. I also added a link to my RSS feed. To me, “Follow” is not just about emails, but it is also about other syndication mediums too. However, I kept the email as the first option to keep the spirit of the tool.

Finally, I didn’t want to hack any piece of code in WordPress nor in any other WordPress plugin. The only thing that we will modify is the theme, by adding some code to it. The current implementation could be improved by upgrading Subscriber2 for example, but I didn’t want people to have to do this to enable the Follow Button on their blog.

Step #1: Install Subscribe2

First thing first. The first thing you will have to do is to install the WordPress plugin that will enable your users to subscribe, and to manage their subscriptions, to your blog via emails. We are using the really good Subscribe2 WordPress Plugin that gives these features to your WordPress instance.

To install this plugin using WordPress’ automatic plugin installation system, follow these instructions. Read the plugin’s installation instruction if you want to do this the manual way:

  1. Log in to your WordPress blog and visit Plugins->Add New.
  2. Search for Subscribe2, click “Install Now” and then Activate the Plugin
  3. Click the “Settings” admin menu link, and select “Subscribe2″
  4. Configure the options to taste, including the email template and any categories which should be excluded from notification
  5. Click the “Tools” admin menu link, and select “Subscribers”
  6. Manually subscribe people as you see fit
  7. Create a WordPress Page to display the subscription form. When creating the page, you may click the “S2″ button on the QuickBar to automatically insert the subscribe2 token. Or, if you prefer, you may manually insert the subscribe2 shortcode or token: [subscribe2] or the HTML invisible Ensure the token is on a line by itself and that it has a blank line above and below. This token will automatically be replaced by dynamic subscription information and will display all forms and messages as necessary
  8. In the WordPress “Settings” area for Subscribe2 select the page name in the “Appearance” section that of the WordPress page created in step 7

On this blog, I called the page created at step #7: Follow. Once you are done installing the plugin, you can test it by visiting your Follow page and by entering your own email (one that is not attached to any user of your account is preferable) and by checking in your inbox if you receive a subscription notification. If you haven’t, you may want to take a look at this FAQ to debug any possible issue with your outgoing email service.

Step #2: Customize your Follow Page

This next step is optional. Since that the form generated by the Subscribe2 plugin is really minimalist, you may want to customize it a little bit, to change its design and to add some explanation in the page, to help your readers to understand what is going on. Take a look at my own Follow page to see what I did to customize that page.

Step #3: Add the Follow Button code in you theme

The third step is really what will morph the Subscribe2 plugin into the Follow Button. What we are doing here, is just to add the code, in your theme, to display the Follow Button.

The first thing you have to do, is to locate where the footer of the pages is generated in the theme. Open the theme folder of your blog: /../wordpress/wp-content/themes/mytheme/. Then you will have to open a few files to check where the </body> ending HTML tag is generated. The file where that code is generated really depends on how the theme got designed. You can do a search, within all the PHP files in that folder for the string “</body>“. This should give you the answer right away. Once you located that place, you are good to continue with the following instructions.

Important note: It is possible that your Theme doesn’t use jQuery by default. If it is the case, then you have to edit the header.php (or whatever the name of the file where the header of your blog is generated) of your theme, and add the following line in the <head>...</head> section of the page:

1
<script src=”https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js” type=text/javascript”></script>

If you don’t have jQuery loaded, a JavaScript error will be returned, and the panel will “freeze” in the webpage. Once you make sure that jQuery was loaded, do proceed with this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
<style type="text/css" media="screen">
  #bit, #bit * {}
  #bit {
      bottom: -300px;
      font: 13px "Helvetica Neue",sans-serif;
      position: fixed;
      right: 10px;
      z-index: 999999;
      width: 230px;
  }
 
  .loggedout-follow-typekit {
      margin-right: 4.5em;
  }
 
  #bit a.bsub {
      background-color: #464646;
      background-image: -moz-linear-gradient(center bottom , #3F3F3F, #464646 5px);
      background: -webkit-gradient(linear, left top, left bottom, from(#3F3F3F), to(#464646));
      filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#3F3F3F', endColorstr='#464646');   

      border: 0 none;
      box-shadow: 0 -1px 5px rgba(0, 0, 0, 0.2);
      color: #CCCCCC;
      display: block;
      float: right;
      font: 13px/28px "Helvetica Neue",sans-serif;
      letter-spacing: normal;
      outline-style: none;
      outline-width: 0;
      overflow: hidden;
      padding: 0 10px 0 8px;
      text-decoration: none !important;
      text-shadow: 0 -1px 0 #444444;
  }
 
  #bit a.bsub {
      border-radius: 2px 2px 0 0;
  }
 
  #bit a.bsub span {
      background-attachment: scroll;
      background-clip: border-box;
      background-color: transparent;
      background-image: url("[[PATH-TO-THE-FAMFAM-ICON]]asterisk_orange.png");
      background-origin: padding-box;
      background-position: 2px 3px;
      background-repeat: no-repeat;
      background-size: 20% auto;
      padding-left: 18px;
  }
 
  #bit a:hover span, #bit a.bsub.open span {
      /*background-position: 0 -117px;*/
      color: #FFFFFF !important;
  }
 
  #bit a.bsub.open {
      background: none repeat scroll 0 0 #333333;
  }
 
  #bitsubscribe {
      background: none repeat scroll 0 0 #464646;
      border-radius: 2px 0 0 0;
      color: #FFFFFF;
      margin-top: 27px;
      padding: 15px;
      width: 200px;
      float: right;
      margin-top: 0;
  }
 
  div#bitsubscribe.open {
      box-shadow: 0 0 8px rgba(0, 0, 0, 0.5);
  }
 
  #bitsubscribe div {
      overflow: hidden;
  }
 
  #bit h3, #bit #bitsubscribe h3 {
      color: #FFFFFF;
      font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
      font-size: 20px;
      font-weight: 300;
      margin: 0 0 0.5em !important;
      text-align: left;
      text-shadow: 0 1px 0 #333333;
  }
 
  #bit #bitsubscribe p {
      color: #FFFFFF;
      font: 300 15px/1.3em "Helvetica Neue",Helvetica,Arial,sans-serif;
      margin: 0 0 1em;
      text-shadow: 0 1px 0 #333333;
  }
 
  #bitsubscribe p a {
      margin: 20px 0 0;
  }
 
  #bit #bitsubscribe p.bit-follow-count {
      font-size: 13px;
  }
 
  #bitsubscribe input[type="submit"] {
      -moz-transition: all 0.25s ease-in-out 0s;
      -webkit-transition: all 0.25s ease-in-out 0s;
      -o-transition: all 0.25s ease-in-out 0s;
      -ms-transition: all 0.25s ease-in-out 0s;
      transition: all 0.25s ease-in-out 0s;  
      background: -moz-linear-gradient(center top , #333333 0%, #111111 100%) repeat scroll 0 0 transparent;
      background: -webkit-gradient(linear, left top, left bottom, from(#333333), to(#111111));
      filter:  progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#111111');   

      border: 1px solid #282828;
      border-radius: 11px 11px 11px 11px;
      box-shadow: 0 1px 0 #444444 inset;
      color: #CCCCCC;
      padding: 2px 20px;
      text-decoration: none;
      text-shadow: 0 1px 0 #000000;
  }
 
  #bitsubscribe input[type="submit"]:hover {
      background: -moz-linear-gradient(center top , #333333 0%, #222222 100%) repeat scroll 0 0 transparent;
      box-shadow: 0 1px 0 #4F4F4F inset;
      color: #FFFFFF;
      text-decoration: none;
  }
 
  #bitsubscribe input[type="submit"]:active {
      background: -moz-linear-gradient(center top , #111111 0%, #222222 100%) repeat scroll 0 0 transparent;
      box-shadow: 0 -1px 0 #333333 inset;
      color: #AAAAAA;
      text-decoration: none;
  }
 
  #bitsubscribe input[type="text"] {
      border-radius: 3px 3px 3px 3px;
      font: 300 15px "Helvetica Neue",Helvetica,Arial,sans-serif;
  }
 
  #bitsubscribe input[type="text"]:focus {
      border: 1px solid #000000;
  }
 
  #bitsubscribe.open {
      display: block;
  }
 
  #bsub-subscribe-button {
      margin: 0 auto;
      text-align: center;
  }
 
  #bitsubscribe #bsub-credit {
      border-top: 1px solid #3C3C3C;
      font: 11px "Helvetica Neue",sans-serif;
      margin: 0 0 -15px;
      padding: 7px 0;
      text-align: center;
  }
 
  #bitsubscribe #bsub-credit a {
      background: none repeat scroll 0 0 transparent;
      color: #AAAAAA;
      text-decoration: none;
      text-shadow: 0 1px 0 #262626;
  }
 
  #bitsubscribe #bsub-credit a:hover {
      background: none repeat scroll 0 0 transparent;
      color: #FFFFFF;
  }
</style>    

<script type="text/javascript" charset="utf-8">
  jQuery.extend(jQuery.easing, {
      easeOutCubic: function (x, t, b, c, d) {
          return c * ((t = t / d - 1) * t * t + 1) + b;
      }
  });
  jQuery(document).ready(function () {
      var isopen = false,
          bitHeight = jQuery('#bitsubscribe').height();
      setTimeout(function () {
          jQuery('#bit').animate({
              bottom: '-' + bitHeight - 30 + 'px'
          }, 200);
      }, 300);
      jQuery('#bit a.bsub').click(function () {
          if (!isopen) {
              isopen = true;
              jQuery('#bit a.bsub').addClass('open');
              jQuery('#bit #bitsubscribe').addClass('open')
              jQuery('#bit').stop();
              jQuery('#bit').animate({
                  bottom: '0px'
              }, {
                  duration: 400,
                  easing: "easeOutCubic"
              });
          } else {
              isopen = false;
              jQuery('#bit').stop();
              jQuery('#bit').animate({
                  bottom: '-' + bitHeight - 30 + 'px'
              }, 200, function () {
                  jQuery('#bit a.bsub').removeClass('open');
                  jQuery('#bit #bitsubscribe').removeClass('open');
              });
          }
      });
  });
</script>

<div id="bit" class="">
  <a class="bsub" href="javascript:void(0)"><span id='bsub-text'>Follow</span></a>
 
  <div id="bitsubscribe">
    <h3><label for="loggedout-follow-field">Follow this Blog</label></h3>
 
    <form action="[[PATH-TO-YOUR-FOLLOW-WORDPRESS-PAGE]]" method="post" accept-charset="utf-8" id="loggedout-follow">
      <p>Get every new post on this blog delivered to your Inbox.</p>
      <p class="bit-follow-count">Join <?php echo $wpdb->get_var("SELECT COUNT(id) FROM wp_subscribe2 WHERE active='1'"); ?> other followers:</p>
      <p>
        <input type="text" name="email" id="s2email" style="width: 95%; padding: 1px 2px" value="Enter email address" onfocus='this.value=(this.value=="Enter email address") ? "" : this.value;' onblur='this.value=(this.value=="") ? "Enter email address" : this.value;'  id="loggedout-follow-field"/>
      </p>
       
      <input type="hidden" name="ip" value="<?php echo $_SERVER['REMOTE_ADDR']; ?>">
     
      <p id='bsub-subscribe-button'>
        <input type="submit" name="subscribe"  value="Sign me up!" />
      </p>
    </form>
   
    <p style="padding-top: 10px;">Or subscribe to the RSS feed by clicking on the counter:</p>  
   
    <p>
      [[ADD-YOUR-RSS-FEED-LINK-HERE]]
    </p>
  </div>
</div>

The only thing you have to do is to copy/paste that code above the </body> tag. Then, do the following three modifications to properly wire it in your blog:

  • At line #41, replace [[PATH-TO-THE-FAMFAM-ICON]]with the path of the asterisk_orange.png icon, on your blog
  • At line #211, replace [[PATH-TO-YOUR-FOLLOW-WORDPRESS-PAGE]] by the URL of your Follow page (the one you created when you installed Subscribe2)
  • At line #228, replace [[ADD-YOUR-RSS-FEED-LINK-HERE]] by the link to your RSS feed

You can get the free asterisk_orange.png icon image from the FamFamFam website. The only thing you have to do, is to download that image, and to put it in the folder you defined for [[PATH-TO-THE-FAMFAM-ICON]]. However, you can use whatever image that you prefer, that may better fit the design of your blog.

Step #4: Disable it For Mobile Devices

Some mobile devices may have issues displaying this floating window. Sometimes, the window may be floating in the middle of the device’s screen without folding-back in the bottom of the page. For this reason, you may want to disable (remove) this option if the user is using a mobile device to read your blog. You can easily disable it if the web server detects that a mobile devise is requesting the webpage by adding these two blocks of code.

First, copy and paste this first block of code above the code of the Follow button (before line #1):

1
2
3
4
5
<?php
 $useragent = $_SERVER['HTTP_USER_AGENT'];
 if(!preg_match('/android.+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i',$useragent)||preg_match('/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i',substr($useragent,0,4)))
 {
?>

Then copy and paste this second block of code below the code of the follow button (after line #231):

1
2
3
<?php
  }
?>

This code come from the Detect Mobile Browser project and is the best mobile device detection code I saw so far. What this code does, is not to include the Follow Button if the device that is requesting the webpage is a mobile device. Otherwise, the Follow Button is added to the HTML page.

Step #5: Test it!

If you are reading this step #5, it means that you finished to create your own, self-hosted, Follow Button!

Congratulation!

But the last thing that remains to be done, is to test it. Once you saved your file with the code above, just refresh any page of your blog. You should see appearing the Follow button on the bottom-right corner of your blog. If you click on it, you should see the form that let your readers subscribing to the system. If you add one of your emails, and click the subscribe button, you should get redirected to the Follow page. Finally you should receive a confirmation email that ask you to confirm your subscription by clicking on a link.

If all these steps properly works, it means that you are done and ready to provide that new functionality to the readers of your blog!

Conclusion

Even if this blog post is few pages long, I hope you found it easy to install and setup. If you have any question regarding this hack, don’t hesitate to ask them down there, in the comments section of this post. I will be happy to answer all of them.

Happy Hacking!

 

Translations

This blog post as been translated in Federico Bozo in Spanish. Other translations will be added to this section.




This blog is a regularly updated collection of my thoughts, tips, tricks and ideas about my semantic Web researches and related software development.


RSS Twitter LinkedIN


Follow

Get every new post on this blog delivered to your Inbox.

Join 65 other followers:

Or subscribe to the RSS feed by clicking on the counter:




RSS Twitter LinkedIN