Before WordPress, publishing to the web meant one of three things: writing HTML by hand, paying for proprietary CMS software, or wrestling with Movable Type (Perl, complex) or b2/cafelog (PHP, abandoned by its original developer).
Matt Mullenweg was using b2/cafelog. In January 2003, b2's author, Michel Valdrighi, had seemingly disappeared. Mullenweg wrote a blog post: "Fortunately, b2/cafelog is GPL, which means that I could use the existing codebase to create a fork." Mike Little replied in the comments that he was interested in collaborating. On May 27, 2003, WordPress 0.7 was released.
I installed it that August. It was 2,500 lines of PHP. Installation: unzip, upload via FTP, create one MySQL database, visit install.php. Five minutes. For comparison, Movable Type's installation required configuring Perl modules, setting file permissions on a dozen directories, and editing a config file by hand. The difference in friction was categorical.
What WordPress 0.7 Actually Was
WordPress 0.7 was a single PHP application, not a framework. There were no plugins. There was one "theme" - a default template that you edited directly. The admin panel was basic HTML forms. But the core loop worked:
<?php
// The WordPress Loop - 2003 version
// This is the actual logic from WordPress 0.7
// query_posts() + the_post() pattern that defined a decade of templating
// In the index.php template:
<?php query_posts('showposts=10'); ?>
<?php while (have_posts()) : the_post(); ?>
<div class="post">
<h2>
<a href="<?php the_permalink(); ?>">
<?php the_title(); ?>
</a>
</h2>
<div class="postmetadata">
Posted on <?php the_time('F j, Y'); ?>
by <?php the_author(); ?>
in <?php the_category(', '); ?>
| <?php comments_popup_link('No Comments', '1 Comment', '% Comments'); ?>
</div>
<div class="entry">
<?php the_content('Read the rest of this entry »'); ?>
</div>
</div>
<?php endwhile; ?>
This loop - while (have_posts()) : the_post() - became the most-copied PHP code pattern in the history of the web. By 2010, it ran on roughly 13% of all websites.
The Database Schema (WordPress 0.7 / 0.71)
-- WordPress 0.7 original schema - MySQL 3.23+
-- Still recognizable in WordPress today, 20 years later
CREATE TABLE wp_posts (
ID bigint(20) unsigned NOT NULL auto_increment,
post_author bigint(20) unsigned NOT NULL default '0',
post_date datetime NOT NULL default '0000-00-00 00:00:00',
post_content longtext NOT NULL,
post_title text NOT NULL,
post_category int(4) NOT NULL default '0',
post_status varchar(10) NOT NULL default 'publish',
comment_status varchar(15) NOT NULL default 'open',
post_name varchar(200) NOT NULL default '', -- the URL slug
post_modified datetime NOT NULL default '0000-00-00 00:00:00',
PRIMARY KEY (ID),
KEY post_name (post_name),
KEY post_status (post_status),
KEY post_date (post_date)
) TYPE=MyISAM;
CREATE TABLE wp_comments (
comment_ID bigint(20) unsigned NOT NULL auto_increment,
comment_post_ID bigint(20) unsigned NOT NULL default '0',
comment_author tinytext NOT NULL,
comment_author_email varchar(100) NOT NULL default '',
comment_author_url varchar(200) NOT NULL default '',
comment_author_IP varchar(100) NOT NULL default '',
comment_date datetime NOT NULL default '0000-00-00 00:00:00',
comment_content text NOT NULL,
comment_approved enum('0','1','spam') NOT NULL default '1',
PRIMARY KEY (comment_ID),
KEY comment_post_ID (comment_post_ID),
KEY comment_approved (comment_approved)
) TYPE=MyISAM;
CREATE TABLE wp_options (
option_id bigint(20) unsigned NOT NULL auto_increment,
blog_id int(11) NOT NULL default '0',
option_name varchar(64) NOT NULL default '',
option_value longtext NOT NULL,
autoload varchar(20) NOT NULL default 'yes',
PRIMARY KEY (option_id),
UNIQUE KEY option_name (option_name)
) TYPE=MyISAM;
The wp_options table was a key-value store for all configuration. siteurl, blogname, admin_email, active_plugins - all in one table. This design was called "the options table pattern." It was flexible, required no schema migrations when adding new settings, and was later criticized as a performance bottleneck. In 2003, it was the right call.
Customizing WordPress 0.7: Direct Template Editing
There were no plugins yet. Customization meant editing index.php, wp-comments.php, and the handful of included files directly:
<?php
// Adding a custom "Recent Posts" sidebar - 2003 method
// No widgets. No plugins. Direct PHP in the sidebar template.
// sidebar.php
?>
<div id="sidebar">
<h2>Recent Posts</h2>
<ul>
<?php
// Direct database query - no WP_Query yet
global $wpdb;
$recent = $wpdb->get_results(
"SELECT ID, post_title, post_date
FROM $wpdb->posts
WHERE post_status = 'publish'
ORDER BY post_date DESC
LIMIT 5"
);
foreach ($recent as $post) :
?>
<li>
<a href="<?php echo get_permalink($post->ID); ?>">
<?php echo htmlspecialchars($post->post_title); ?>
</a>
</li>
<?php endforeach; ?>
</ul>
<h2>Archives</h2>
<ul>
<?php wp_get_archives('type=monthly'); ?>
</ul>
</div>
Direct SQL against $wpdb in templates became a pattern that developers used for years. It was the only way. The plugin API came in WordPress 1.2 (May 2004). Until then, everything was direct template modification.
The Permalink Revolution
One feature WordPress 0.7 implemented better than anything before it: clean URLs. The default was ?p=42. But with mod_rewrite enabled:
# .htaccess generated by WordPress
RewriteEngine On
RewriteBase /
# Rewrite everything that isn't a file or directory
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
This let you set permalink structures like /%year%/%monthnum%/%postname%/ - clean, readable URLs that worked as links, were human-memorable, and ranked better in the search engines that were beginning to weight URL structure.
The combination of clean URLs + easy publishing + comments built-in was the package. No other tool in 2003 offered all three without configuration complexity that blocked non-developers.
Why This Was the Most Important Software of 2003
Every year in tech produces tools that seem important at launch and fade. WordPress 0.7 seemed unimportant at launch - 2,500 lines of PHP, no plugins, one template - and became the infrastructure of the web.
What made it survive when Movable Type, b2, and dozens of other early blog tools did not:
GPL license. Anyone could fork it, modify it, redistribute it. The community could fix bugs without waiting for a company. This is what allowed the plugin ecosystem to explode after 1.2.
The update path was never broken. From 0.7 to today, upgrading WordPress never required manual database migration or template rewriting. The schema evolved backward-compatibly. This meant users stayed on WordPress instead of migrating to whatever was newer.
It ran on shared hosting. PHP + MySQL + .htaccess - the LAMP stack. The same $8/month hosting plan that ran WordPress 0.7 would run WordPress 6.x today. The addressable market was everyone with a hosting plan.
By 2008, WordPress was the dominant blogging platform. By 2012, it was the dominant CMS. By 2023, 43% of all websites ran WordPress. That story started with a 2,500-line PHP script uploaded to SourceForge on May 27, 2003.
Aunimeda builds production-grade backend systems - APIs, microservices, real-time applications, and system integrations.
Contact us for backend engineering services. See also: Custom Software Development, Web Development