Skip to main content

· 6 min read

Motivation

Dealing with WordPress again. What I want to achieve is for the documents(PDFs, Images etc) that I have on a WordPress site, the visitors will have to key in their information in order to download them. This way, the number of downloads per document(publication, in my case) and also the details of people who are downloading the documents can be recorded and analysed later on.

Process

My initial idea was to look for a free backend service which would serve to process API calls from my front-end. On the pages where I display the documents, I will have a form that collects visitor information before allowing download to happen. When information is collected, download will initiate and an API call will be made to communicate with the backend.

Front-end can be make up of a simple HTML form + Javascript for any data preprocessing. The issue I had was that even if I am able to find a free backend service, the POST API call that I make to that backend will contain authentication keys. Leaving API keys in plain javascript is definitely not a good idea. Although, I must say that there are many interesting Database-as-a-service that caught my attention. One of them is Quickmetrics. It provides free 10000 events per day and 5 metrics to track. No time limit and no credit card required. I will definitely check this out in the future. The documentation also seems to be straight to the point.

Ok, so sending request from Javascript may not be a good idea. The way to go will then be via PHP. There is plenty of opportunities to write PHP in WordPress and my first instinct was to check if there is a plugin available. I did not manage to find suitable ones and those form service plugins are mostly limited in their free versions. So the next step for me was to download a plugin that I used before to easily insert PHP code into a page: Post Snippets. It makes creating shortcodes fairly easy. Also, even if PHP is not used, it is still a good way to write some HTML/Javascript code that can be used in different pages.


My PHP code to render the front-end form is as follows:

Part 1: Copy and edit a html form template from W3 School
echo "<h3>Please tell us about you before downloading</h3>";

$html= <<<HTML
<form id="toolkit" method="post" action="">
<label for="name">Name:</label>
<input
type="text"
id="name"
name="name"
placeholder="e.g John"
required
maxlength="100"
minlength="1"
/>
<label for="email">Email:</label>
<input
type="email"
id="email"
name="email"
placeholder="e.g John@example.com"
required
/>
<label for="organisation">Organisation:</label>
<input
type="text"
id="organisation"
name="organisation"
placeholder="e.g Google"
maxlength="100"
minlength="1"
required
/>
<input type="hidden" id="publication" name="publication" value="" />
<input type="hidden" name="action" value="addDownload" />
<input type="submit" />
</form>
HTML;

echo $html;
Part 2: Copy and add in the style for the html form as well
$style = <<<STYLE
<style>
/* Style inputs, select elements and textareas */
input[type="text"],
select,
input[type="email"] {
width: 100%;
padding: 12px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
resize: vertical;
}
/* Style the label to display next to the inputs */
label {
padding: 12px 12px 12px 0;
display: inline-block;
}
/* Style the submit button */
input[type="submit"] {
background-color: #4caf50;
color: white;
padding: 12px 20px;
margin-top: 10px;
border: none;
border-radius: 4px;
cursor: pointer;
float: right;
}
/* Style the container */
.container {
border-radius: 5px;
background-color: #f2f2f2;
padding: 20px;
}
/* Floating column for labels: 25% width */
.col-25 {
float: left;
width: 25%;
margin-top: 6px;
}
/* Floating column for inputs: 75% width */
.col-75 {
float: left;
width: 75%;
margin-top: 6px;
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
}
/* Responsive layout - when the screen is less than 600px wide, make the two columns stack on top of each other instead of next to each other */
@media screen and (max-width: 600px) {
.col-25,
.col-75,
input[type="submit"] {
width: 100%;
margin-top: 0;
}
}
</style>
STYLE;

echo $style ;
Part 3: Add in JS logic to handle form submit

Two things I did here:

  • Submit the completed form via Ajax to "/wp-admin/admin-ajax.php" (my backend)
  • Trigger auto download of document by simulating clicking of downloable link to the document
$js = <<<JS
<script>
jQuery("#toolkit").submit(ajaxSubmit);
const submitBtn = document.querySelector("input[type='submit']");

// add title of publication as part of form
const title = document.querySelector(".blog-post-detail .inner h2").innerText;
const publication = document.querySelector("#publication");
publication.value = title;

function ajaxSubmit() {
// handle storing of data
var newDownloaderForm = jQuery(this).serialize();
jQuery.ajax({
type: "POST",
url: "/wp-admin/admin-ajax.php",
data: newDownloaderForm,
success: function (data) {
console.log(data);
submitBtn.value = "Thank You";
submitBtn.style.backgroundColor = "grey";
submitBtn.disable = true;
},
error: function (error) {
console.log(error);
submitBtn.value = "Something is wrong...please try again";
submitBtn.style.backgroundColor = "grey";
submitBtn.disable = true;
},
});

// handle auto downloading of files
const link = document.createElement("a");
link.href ="{link}";
link.download = "";
link.dispatchEvent(new MouseEvent("click"));

return false;
}
</script>
JS;

echo $js;

So that's all for the front-end. Not the best way to do things but it does the job. The last part of the puzzle is to setup the backend to receive the form and store data accordingly.

I honestly do not know WordPress well enough to find an alternative. So here, I will add my backend processing code in the current theme's functions.php file (accessible from Appearance -> Theme Editor -> functions.php). I am aware that if the theme changes, this code will no longer work but oh well...

Part 4: Add in PHP function to be triggered to save form data
// Add to the bottom of functions.php
// Added to deal with tracking of document downloads
// Every download will add a post of post type: downloader
// and it includes the form data
// https://stackoverflow.com/questions/43557755/how-to-call-ajax-in-wordpress
wp_enqueue_script('jquery');

function update() {
$new_post = array(
'post_title' => sanitize_text_field($_POST['publication']),
'post_status' => 'publish',
'post_author' => 1,
'post_type' => 'downloader'
);

// Insert the post into the database
$new_post_id = wp_insert_post( $new_post );
update_field('name', sanitize_text_field($_POST['name']) , $new_post_id);
update_field('email', sanitize_email($_POST['email']), $new_post_id);
update_field('organisation', sanitize_text_field($_POST['organisation']), $new_post_id);
update_field('publication', sanitize_text_field($_POST['publication']), $new_post_id);
}

// this is invoked when ajax call from front-end JS is invoked
// because of <input type="hidden" name="action" value="addDownload" />
// the ajax action(function) to call is specified in the form to be named "addDownload"
function addDownload() {
update();
echo "done";
}
add_action('wp_ajax_addDownload', 'addDownload');
add_action('wp_ajax_nopriv_addDownload', 'addDownload');

This is by no means a difficult task but I am really happy to actually know how to make an ajax call within WordPress.

Achievement unlocked!

· 5 min read

This is my first post written for my new blog! How exciting!

At the start of 2020, I was done with national service and waiting for university to start in August. I did not want to waste the eight-month period doing nothing, so I applied for advanced credit modules(Programming intro course) at NUS and also did a lot of learning on my own.

I had already taken one or two python introductory courses on Coursera back in 2017 - 2018, during school term breaks. However, I did not really pick things up because I wasn't doing any projects, and learning to code without practicing was a disaster in the making. I could understand the concepts taught in the video lectures but I simply forget most of the syntax over time. At the start of 2020, I began watching Youtube videos in the tech space that was mainly filled with Youtubers like "Joma", "TechLead" etc. While Youtube videos may not be that educational or even of any practical value, the "developer" Youtubers often talked about similar topics such as "how to get better at coding" or "how to get a tech internship". From those videos and my past experiences, I knew I had to commit to doing side projects and practice coding more frequently. Funny enough, I picked web development as an area to focus on (and later found internships doing that stuff) because of a Youtube video.

So the reason why I picked web development was due to a video made by the now controversial Youtuber "TechLead" (who has 913K subscribers by the way, interesting...). Basically, it was a video in which he talked about how web development is a good way to prototype and have a visual appreciation of your work immediately. It's easy to show your work to others and you get a sense of achievement fairly quickly. Points were made and I agreed to most of them. What I also learned from this was that learning can take place anywhere, even while mindlessly surfing the web or succuming to the Youtube algorithm.

So earlier this year, I worked on getting better at web development in general. And I also had two goals in mind:

2020 Goals

I had to learn enough to apply for an internship. And I would like to be knowledgeable enough to write articles related to tech. The goal of getting an internship before I embarked on my computer science undergraduate journey was challenging. I spent most of my time learning from tutorials and doing Leetcode questions. I created my very first resume and started to build projects to fill the void. I applied to a few companies where they seemed not to expect too much in their job posts. For a month or two, I was out of luck. The few that replied did not proceed further with me. Fortunately enough I managed to obtain an internship working for a startup and it was honestly a good ride. So long story short, I accomplished goal No.1 before the half-year mark.

It was goal No.2 that I wanted to talk about in this post. Besides the Imposter syndrome, writing a blog seemed to be really difficult to begin with and hard to follow through. I procrastinated and finally in September, I started writing on the platform "Dev.to". And I continued to do so with the aim to publish one article per week, till the end of this year. Happy to say that I generated over 30 posts and that amounted to over 16 weeks of writing streak.

2020 writing

I am satisfied with the amount of time I put into this and the learning in that process. Writing and also editing the pieces were very time-consuming. I had to spend many hours before I could publish an article. I would need to generate code examples and explain things in (hopefully) a clear and concise manner. I learned a lot from the research and the poking around in the writing process.

So I did manage to do the tasks set for 2020. I am grateful for the opportunities and also the new people that I met in 2020. I will continue to write and also explore interesting job opportunities next year. The good thing is that things that are harder to begin with tend to be slightly "easier" to continue.

Coming to the end of 2020, I should write down my school/work-related goals for 2021.

  • Secure one summer internship (or NUS'CVWO)
  • Continue to write CS & web dev related stuff (at least on a Bi-weekly basis)
  • Be great at one module each semester (aim to TA for it)
  • Put in efforts to develop one of my ideas to fruition
  • Do one open-source project
  • Be wholesome and happy while doing the above:)

The end.

· 5 min read

The initial struggle with Vim is very real, speaking from the perspective of a VScode user. However, after using Vim for a few months, I definitely feel much better and more comfortable with Vim.

Especially for shorter Java programs, one will come to appreciate the simplicity and power of Vim in no time. I won't be making Vim my main code editor in the near future, but I definitely do not hate it anymore.

In this article, I hope to note down the absolutely necessary commands needed to use Vim as a programming "IDE". Nothing fancy 😂

P.S There are far comprehensive/detailed tutorials out there, such as vimtutor(if you have Vim installed, simply type vimtutor in the command line, it will bring you through some basic lessons). What I hope to achieve here is to share my most helpful commands. I won't be explaining much for this is more of a reference that sieves out the essential commands than to introduce them formally.


Super Basic Understanding Of Vim

When we start with something like vim Sample.java and open up the standard Vim editing window, we are going to be in the Command mode where the keys we type/press are supposed to be commands that Vim can understand. This is like a control center where we speak jargon that Vim is listening out for.

The other very important mode that we need to know about is the Insert Mode. This is where we type the text that is meant to be in the body of our program. This is the mode that we are in when we open up a typical text editor such as Notepad or Microsoft Word.

When you are done with your changes in insert mode, you have to return to command mode before you can issue a quit command.

I prefer using Ctrl + c to return to command mode from insert mode because the Esc key can be quite far from the normal typing position and Ctrl + c is within reach.


Basics
KeyFor
vim filenameCreate/open a file with given filename
iEnter insert mode
Esc /Ctrl + cQuit insert mode and
return to command mode
:wqSave and quit Vim
:q!Discard changes and quit Vim
Code Related
KeyFor
gg=GFix code indentation
ctrl + nAuto word completion
:!javac *.javaCompile code without quitting Vim
Navigation
KeyFor
hjklthe equivalent arrow keys
ggGo to top of screen
shift + gGo to the bottom of screen
0Go to start of line
$Go to end of line
Ctrl + fPage down
Ctrl + bPage up
Edit
KeyFor
rreplace a single character
oadd newline above and enter insert mode
Oadd newline below and enter insert mode
yyCopy line
pPaste
ddDelete/cut line
dwDelete/cut word
d$Delete/cut from cursor to end of line
xDelete/cut a character

For copying a block of code:

  • press shift + v to start selecting visually by navigating up or down. The block of code will be selected, then press y to copy. Afterward, simply press p to paste.
Common Tasks
KeyFor
uUndo
Ctrl + rRedo
:s/foo/bar/gFind and replace
"foo" with "bar"
for all "foo"

Multiple tabs
To open a new file in another tab:

  • use :tabe filename
  • e.g. :tabe test.java

To navigate between tabs:

  • use gt to go to next tab
  • use 1gt, 2gt, 3gt to go to different tab by number
  • e.g. 1gt goes to the first tab from the left

To get out of Vim for a while:

  • use ctrl + z to suspend activity
  • use fg (foreground) to come back to Vim
Common UNIX commands
KeyFor
lslist files in current folder
cd <directory>enter this folder
cd ..go out of current folder
rm <file>delete this file
mkdir <directory>make new folder
mv <file1> <file2>Rename file1 as file2
cp <file1> <file2>copy file1 to file2
tabfor auto completion of possible commands

The End

I will be updating this article to add/reflect my latest list of frequently used commands. Bye now!

gif bye

*5/12/2020 P.S. I have updated pretty much whatever I found useful, will continue to update this list in the future as this list also serves as my own notes.