Alkaline

Love your site again.

Remember your first site

Building your first Web site was exciting. You learned HTML. Uploaded some pictures. Maybe you joined an ad exchange or met some new friends. The Internet was buzzing with activity. Eventually, Web sites became larger. They needed software to make it easier, the content management system (CMS) entered the nerd lexicon, and the rest is history.

Fast forward to now

Search for “CMS.” Go ahead, we’ll wait. There are thousands of results. Most of them are dysfunctional, incomplete, and unsupported. You spend an hour or two trying to configure a new one only to discover it misses some obvious feature. You get frustrated, and you download the latest of version of WordPress, even though you hate WordPress. Where did we go wrong?

Introducing Alkaline

Alkaline is fundamentally different. It’s built using the latest standards. It treats posts and images separately but equally. It has powerful theme and extension engines. It features real-time analytics. It’s HTML5- and AJAX-savvy. It sports adaptive caching. It does version control. It has a built-in geo database. It supports enterprise-grade search. It’s fully supported by its maker.

First-class features.

1. ionCube removed

2. New Dashboard UI

3. Full XML-RPC MetaWeblog support

4. Editable smart sets

5. Excerpts

6. Export palettes to ASE and GPL

7. Upload text file as post draft

8. Categories

9. Version control

10. Recovery mode

11. Inline comment responses

12. Tag parents

13. Citations

14. Improved guests and sets

15. Improved searching

16. Sphinx search support



Alkaline v1.1 introduces 31 new features, and 5 new extensions. We read your feedback, and started with the big stuff: removing ionCube encoding, redesigning our Dashboard to do more with fewer clicks, and improving post-related features.

Then we started adding features we thought a CMS should have. Alkaline now has version control for posts and pages. Accidentally remove that quote? Go back in time, as often as you want. Navigate away from changes? Don’t worry, Alkaline autosaves. Did your dog hit delete? Enter recovery mode and recover it.

For the technophiles, we developed ways to make your site even more enjoyable. Sphinx search support? MetaWeblog support? Fluid.app SSB features? Check, check, check.

But what makes Alkaline v1.1 really special are all the small tweaks, improvements, and bug fixes we didn’t have room to list here. These hundreds of changes are what make Alkaline v1.1 our easiest, fastest, most fun Alkaline ever. Give it a spin, we think you’ll agree.

17. No-nonsense caching

18. Related items

19. Title formatting

20. Extension task management

21. Trackbacks

22. As-you-type text statistics

23. Searchable image panels

24. Improved error handling

25. HTML5 geo-awareness

26. Fluid.app SSB badges, Growl notifications

27. Send to action

28. Auto-saving

29. Dashboard XML feed

30. Hierarchical directory mode

31. In-template previewing (experimental)


Inner nerd, rejoice.

Unlike other content management systems, Alkaline uses semantic, object-oriented PHP
that works exactly as it looks and is fully documented.

Show from



					require_once('config.php');
					require_once(PATH . CLASSES . 'alkaline.php');

					$alkaline = new Alkaline;
					$alkaline->recordStat('home');

					$with_id = $alkaline->findID($_GET['with'], true);
					if(!$with_id and !empty($_GET['with'])){
						$alkaline->addError('No image was found.',
						'Try searching for the image you were seeking.', null, null,
						404);
					}

					$image_ids = new Find('images');
					$image_ids->page(null, 15, 4);
					if($with_id){ $image_ids->with($with_id); }
					$image_ids->published();
					$image_ids->privacy('public');
					$image_ids->sort('image_published', 'DESC');
					$image_ids->find();

					$images = new Image($image_ids);
					$images->formatTime();
					$images->getSizes();
					$images->getEXIF();
					$images->getColorkey(950, 15);
					$images->getSets();
					$images->getTags();
					$images->getRights();
					$images->getPages();
					$images->getComments();
					$images->addSequence('medium_last', 3);
					$images->hook();

					$page_ids = new Find('pages');
					$page_ids->find();

					$pages = new Page($page_ids);

					$header = new Canvas;
					$header->load('header');
					$header->setTitle('Welcome');
					$header->loop($pages);
					$header->display();

					$index = new Canvas;
					if($image_ids->page == 1){
						$index->load('index');
					}
					else{
						$index->load('index_sub');
					}
					$index->assign('Page_Next', $image_ids->page_next);
					$index->assign('Page_Previous', $image_ids->page_previous);
					$index->assign('Page_Next_URI', $image_ids->page_next_uri);
					$index->assign('Page_Previous_URI', $image_ids->page_previous_uri);
					$index->assign('Page_Current', $image_ids->page);
					$index->assign('Page_Count', $image_ids->page_count);
					$index->loop($images);
					$index->display();

					$footer = new Canvas;
					$footer->load('footer');
					$footer->display();
					
					{block:Images}
					<div class="image">
						<hr />

						{Image_Colorkey}

						<div class="center"><a href="{Image_URI}"><img src="{Image_Src_Large}" alt="" /></a></div>

						<div class="float_right_big">
							<div class="datetime">{Image_Published_Format}</div>
							<div class="right_set">
								{if:Image_Comment_Count}
									{Image_Comment_Count|alpha0|upperwords} comments.<br />
								{/if:Image_Comment_Count}
								{if:Right_Title}
									{Right_Title}
								{else:Right_Title}
									No rights set.
								{/if:Right_Title}
							</div>
						</div>

						{if:Image_Title}
							<h2>{Image_Title}</h2>
						{else:Image_Title}
							<h2>(Untitled)</h2>
						{/if:Image_Title}

						{if:Image_Description}
							{Image_Description}
						{/if:Image_Description}

						{if:Tags}
							<p>
							{block:Tags}
								<span class="tag"><a href="{Tag_URI}">{Tag_Name}</a></span>
							{/block:Tags}
							</p>
						{/if:Tags}

						<p>
						{if:Sets}
							<em>As featured in the collections:</em>{block:Sets}   <a href="{Set_URI}">{Set_Title}</a>{/block:Sets}<br />
						{/if:Sets}
						{if:Pages}
							<em>As featured on the pages:</em>{block:Pages}   <a href="{Page_URI}">{Page_Title}</a>{/block:Pages}
						{/if:Pages}
						</p>
					</div>
					{/block:Images}

					<hr />

					<div class="span-8">
						{if:Page_Previous}<strong><a href="{Page_Previous_URI}">← Previous page</a></strong>{/if:Page_Previous} 
					</div>
					<div class="span-8 center">
						Page #{Page_Current} of {Page_Count}
					</div>
					<div class="span-8 right last">
						 {if:Page_Next}<strong><a href="{Page_Next_URI}">Next page →</a></strong>{/if:Page_Next}
					</div>
					
					define('DRUPAL_ROOT', getcwd());

					require_once DRUPAL_ROOT . '/includes/bootstrap.inc';
					drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
					menu_execute_active_handler();
					
					// That's it? What's in /includes/bootstrap.inc?
					
					/**
					 * @file
					 * Functions that need to be loaded on every Drupal request.
					 */

					/**
					 * The current system version.
					 */
					define('VERSION', '7.2');

					/**
					 * Core API compatibility.
					 */
					define('DRUPAL_CORE_COMPATIBILITY', '7.x');

					/**
					 * Minimum supported version of PHP.
					 */
					define('DRUPAL_MINIMUM_PHP', '5.2.4');

					/**
					 * Minimum recommended value of PHP memory_limit.
					 */
					define('DRUPAL_MINIMUM_PHP_MEMORY_LIMIT', '32M');
					
					// We can't show it all here, it's over 3,000 lines
					
					<?php
					?>
					  <div id="branding" class="clearfix">
					    <?php print $breadcrumb; ?>
					    <?php print render($title_prefix); ?>
					    <?php if ($title): ?>
					      <h1 class="page-title"><?php print $title; ?></h1>
					    <?php endif; ?>
					    <?php print render($title_suffix); ?>
					    <?php print render($primary_local_tasks); ?>
					  </div>

					  <div id="page">
					    <?php print render($secondary_local_tasks); ?>

					    <div id="content" class="clearfix">
					      <div class="element-invisible"><a id="main-content"></a></div>
					      <?php if ($messages): ?>
					        <div id="console" class="clearfix"><?php print $messages; ?></div>
					      <?php endif; ?>
					      <?php if ($page['help']): ?>
					        <div id="help">
					          <?php print render($page['help']); ?>
					        </div>
					      <?php endif; ?>
					      <?php if ($action_links): ?><ul class="action-links"><?php print render($action_links); ?></ul><?php endif; ?>
					      <?php print render($page['content']); ?>
					    </div>

					    <div id="footer">
					      <?php print $feed_icons; ?>
					    </div>

					  </div>
					
					define('WP_USE_THEMES', true);

					/** Loads the WordPress Environment and Template */
					require('./wp-blog-header.php');
					
					// What's in /wp-blog-header.php?
					
					if ( !isset($wp_did_header) ) {

						$wp_did_header = true;

						require_once( dirname(__FILE__) . '/wp-load.php' );

						wp();

						require_once( ABSPATH . WPINC . '/template-loader.php' );

					}
					
					// What's in /wp-load.php?
					
					/** Define ABSPATH as this files directory */
					define( 'ABSPATH', dirname(__FILE__) . '/' );

					if ( defined('E_RECOVERABLE_ERROR') )
						error_reporting(E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING | E_RECOVERABLE_ERROR);
					else
						error_reporting(E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_ERROR | E_WARNING | E_PARSE | E_USER_ERROR | E_USER_WARNING);

					if ( file_exists( ABSPATH . 'wp-config.php') ) {

						/** The config file resides in ABSPATH */
						require_once( ABSPATH . 'wp-config.php' );

					} elseif ( file_exists( dirname(ABSPATH) . '/wp-config.php' ) && ! file_exists( dirname(ABSPATH) . '/wp-settings.php' ) ) {

						/** The config file resides one level above ABSPATH but is not part of another install*/
						require_once( dirname(ABSPATH) . '/wp-config.php' );

					} else {

						// A config file doesn't exist

						// Set a path for the link to the installer
						if ( strpos($_SERVER['PHP_SELF'], 'wp-admin') !== false )
							$path = '';
						else
							$path = 'wp-admin/';

						// Die with an error message
						require_once( ABSPATH . '/wp-includes/class-wp-error.php' );
						require_once( ABSPATH . '/wp-includes/functions.php' );
						require_once( ABSPATH . '/wp-includes/plugin.php' );
						$text_direction = /*WP_I18N_TEXT_DIRECTION*/"ltr"/*/WP_I18N_TEXT_DIRECTION*/;
						wp_die(sprintf(/*WP_I18N_NO_CONFIG*/"There doesn't seem to be a <code>wp-config.php</code> file. I need this before we can get started. Need more help? <a href='http://codex.wordpress.org/Editing_wp-config.php'>We got it</a>. You can create a <code>wp-config.php</code> file through a web interface, but this doesn't work for all server setups. The safest way is to manually create the file.</p><p><a href='%ssetup-config.php' class='button'>Create a Configuration File</a>"/*/WP_I18N_NO_CONFIG*/, $path), /*WP_I18N_ERROR_TITLE*/"WordPress › Error"/*/WP_I18N_ERROR_TITLE*/, array('text_direction' => $text_direction));
							
					}
					
				<?php get_header(); ?>

						<div id="container">
							<div id="content" role="main">

							<?php
							/* Run the loop to output the posts.
							 * If you want to overload this in a child theme then include a file
							 * called loop-index.php and that will be used instead.
							 */
							 get_template_part( 'loop', 'index' );
							?>
							</div><!-- #content -->
						</div><!-- #container -->

				<?php get_sidebar(); ?>
				<?php get_footer(); ?>
				
					$_zp_script_timer['start'] = microtime();
					// force UTF-8 Ø
					require_once(dirname(__FILE__).'/zp-core/global-definitions.php');
					if (!file_exists(dirname(__FILE__) . '/' . DATA_FOLDER . "/zp-config.php")) {
						if (file_exists(dirname(__FILE__).'/'.ZENFOLDER.'/setup.php')) {
							$dir = str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME']));
							if (substr($dir, -1) == '/') $dir = substr($dir, 0, -1);
							$location = "http://". $_SERVER['HTTP_HOST']. $dir . "/" . ZENFOLDER . "/setup.php";
							header("Location: $location" );
						} else {
							die('setup scripts missing');
						}
					}
					define('OFFSET_PATH', 0);
					require_once(ZENFOLDER . "/template-functions.php");
					checkInstall();
					//$_zp_script_timer['require'] = microtime();
					//rss feeds
					if(isset($_GET['rss']) || isset($_GET['rss-news']) || isset($_GET['rss-comments'])) {
						require_once(dirname(__FILE__). '/'.ZENFOLDER.'/functions-rss.php');
						rssHitcounter();
						startRSSCache();

						//XXX This stuff could probably be cleared a little but some are needed as we can't pass queries via include()
						// Using a http wrapper would work but is disabled on a lot of servers incl. mine
						//gallery RSS
						if(isset($_GET['rss'])) {
							if (!getOption('RSS_album_image')) {
								header("HTTP/1.0 404 Not Found");
								header("Status: 404 Not Found");
								include(ZENFOLDER. '/404.php');
								exit();
							}
							require_once(ZENFOLDER .'/'.PLUGIN_FOLDER . "/image_album_statistics.php");
							include(dirname(__FILE__). "/".ZENFOLDER.'/rss/rss.php');
						}

						//Zenpage News RSS
						if(isset($_GET['rss-news'])) {
							if (!getOption('RSS_articles')) {
								header("HTTP/1.0 404 Not Found");
								header("Status: 404 Not Found");
								include(ZENFOLDER. '/404.php');
								exit();
							}
							include(dirname(__FILE__). "/".ZENFOLDER.'/rss/rss-news.php');
						}

						//Comments RSS
						if(isset($_GET['rss-comments'])) {
							if (!getOption('RSS_comments')) {
								header("HTTP/1.0 404 Not Found");
								header("Status: 404 Not Found");
								include(ZENFOLDER. '/404.php');
								exit();
							}
							include(dirname(__FILE__). "/".ZENFOLDER.'/rss/rss-comments.php');
						}
						endRSSCache();
						exit();
					}
					//$_zp_script_timer['rss'] = microtime();
					/**
					 * Invoke the controller to handle requests
					 */
					require_once(dirname(__FILE__). "/".ZENFOLDER.'/controller.php');
					header ('Content-Type: text/html; charset=' . getOption('charset'));
					$_zp_obj = '';
					//$_zp_script_timer['controller'] = microtime();
					// Display an arbitrary theme-included PHP page
					if (isset($_GET['p'])) {
						handleSearchParms('page', $_zp_current_album, $_zp_current_image);
						$theme = setupTheme();
						$page = str_replace(array('/','\\','.'), '', sanitize($_GET['p']));
						if (strpos($page, '*')===0) {
							$page = substr($page,1); // handle old zenfolder page urls
							$_GET['z'] = true;
						}
						if (isset($_GET['z'])) { // system page
							$_zp_gallery_page = basename($_zp_obj = ZENFOLDER."/".$page.".php");
						} else {
							$_zp_obj = THEMEFOLDER."/$theme/$page.php";
							$_zp_gallery_page = basename($_zp_obj);
						}

					// Display an Image page.
					} else if (in_context(ZP_IMAGE)) {
						handleSearchParms('image', $_zp_current_album, $_zp_current_image);
						$theme = setupTheme();
						$_zp_gallery_page = basename($_zp_obj = THEMEFOLDER."/$theme/image.php");

					// Display an Album page.
					} else if (in_context(ZP_ALBUM)) {
						if ($_zp_current_album->isDynamic()) {
							$search = $_zp_current_album->getSearchEngine();
							zp_setcookie("zenphoto_search_params", $search->getSearchParams(), time()+60);
						} else {
							handleSearchParms('album', $_zp_current_album);
						}
						$theme = setupTheme();
						$_zp_gallery_page = basename($_zp_obj = THEMEFOLDER."/$theme/album.php");
						// Display the Index page.
					} else if (in_context(ZP_INDEX)) {
						handleSearchParms('index');
						$theme = setupTheme();
						$_zp_gallery_page = basename($_zp_obj = THEMEFOLDER."/$theme/index.php");
					}

					//$_zp_script_timer['page'] = microtime();
					if (!isset($theme)) {
						$theme = setupTheme();
					}
					//$_zp_script_timer['theme setup'] = microtime();
					$custom = SERVERPATH.'/'.THEMEFOLDER.'/'.internalToFilesystem($theme).'/functions.php';
					if (file_exists($custom)) {
						require_once($custom);
					} else {
						$custom = false;
					}

					if (DEBUG_PLUGINS) {
						debugLog('Loading the "theme" plugins.');
					}
					$_zp_loaded_plugins = array();
					foreach (getEnabledPlugins() as $extension=>$loadtype) {
						if ($loadtype&THEME_PLUGIN) {
							if (DEBUG_PLUGINS) {
								list($usec, $sec) = explode(" ", microtime());
								$start = (float)$usec + (float)$sec;
							}
							require_once(getPlugin($extension.'.php'));
							if (DEBUG_PLUGINS) {
									list($usec, $sec) = explode(" ", microtime());
									$end = (float)$usec + (float)$sec;
									debugLog(sprintf('    '.$extension.'('.($priority & PLUGIN_PRIORITY).')=>%.4fs',$end-$start));
								}
					//		$_zp_script_timer['load '.$extension] = microtime();
						}
						$_zp_loaded_plugins[] = $extension;
					}
					if ($zp_request) {
						$_zp_obj = zp_apply_filter('load_theme_script',$_zp_obj);
					}
					//$_zp_script_timer['theme scripts'] = microtime();
					if ($zp_request && file_exists(SERVERPATH . "/" . internalToFilesystem($_zp_obj))) {
						$hint = $show = false;
						if (checkAccess($hint, $show)) { // ok to view
							// re-initialize video dimensions if needed
							if (isImageVideo() & isset($_zp_flash_player)) {
								$_zp_current_image->updateDimensions();
							}
							setThemeColumns();
						} else {
							if (is_object($_zp_HTML_cache)) {	//	don't cache the logon page or you can never see the real one
								$_zp_HTML_cache->abortHTMLCache();
							}
							$_zp_obj = SERVERPATH.'/'.THEMEFOLDER.'/'.$theme.'/password.php';
							if (!file_exists(internalToFilesystem($_zp_obj))) {
								$_zp_obj = SERVERPATH.'/'.ZENFOLDER.'/password.php';
							}
						}
						// Include the appropriate page for the requested object, and a 200 OK header.
						header("HTTP/1.0 200 OK");
						header("Status: 200 OK");
						header('Last-Modified: ' . $_zp_last_modified);
						zp_apply_filter('theme_headers');
						include(internalToFilesystem($_zp_obj));
					} else {
						// If the requested object does not exist, issue a 404 and redirect to the theme's
						// 404.php page, or a 404.php in the zp-core folder.
						list($album, $image) = rewrite_get_album_image('album','image');
						debug404($album, $image, $theme);
						$_zp_gallery_page = '404.php';
						$errpage = THEMEFOLDER.'/'.internalToFilesystem($theme).'/404.php';
						header("HTTP/1.0 404 Not Found");
						header("Status: 404 Not Found");
						zp_apply_filter('theme_headers');
						if (is_object($_zp_HTML_cache)) {
							$_zp_HTML_cache->abortHTMLCache();
						}
						if (file_exists(SERVERPATH . "/" . $errpage)) {
							if ($custom) require_once($custom);
							include($errpage);
						} else {
							include(ZENFOLDER. '/404.php');
						}
					}
					//$_zp_script_timer['theme script load'] = microtime();
					exposeZenPhotoInformations($_zp_obj, $_zp_loaded_plugins, $theme);
					//$_zp_script_timer['expose information'] = microtime();
					db_close();	// close the database as we are done
					echo "\n";
					list($usec, $sec) = explode(' ', array_shift($_zp_script_timer));
					$first = $last = (float)$usec + (float)$sec;
					$_zp_script_timer['end'] = microtime();
					foreach ($_zp_script_timer as $step=>$time) {
						list($usec, $sec) = explode(" ", $time);
						$cur = (float)$usec + (float)$sec;
						printf("\n",$step,$cur-$last);
						$last = $cur;
					}
					if (count($_zp_script_timer)>1) printf("\n",$last-$first);
					if (is_object($_zp_HTML_cache)) {
						$_zp_HTML_cache->endHTMLCache();
					}

					
					<?php

					// force UTF-8 Ø

					if (!defined('WEBPATH')) die(); $themeResult = getTheme($zenCSS, $themeColor, 'light');
					?>
					<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
					<html xmlns="http://www.w3.org/1999/xhtml">
					<head>
						<?php zp_apply_filter('theme_head'); ?>
						<title><?php echo getBareGalleryTitle(); ?></title>
						<meta http-equiv="content-type" content="text/html; charset=<?php echo getOption('charset'); ?>" />
						<link rel="stylesheet" href="<?php echo pathurlencode($zenCSS); ?>" type="text/css" />
						<?php printRSSHeaderLink('Gallery',gettext('Gallery RSS')); ?>
					</head>

					<body>
					<?php zp_apply_filter('theme_body_open'); ?>

					<div id="main">

						<div id="gallerytitle">
							<?php if (getOption('Allow_search')) {  printSearchForm(''); } ?>
							<h2><?php printHomeLink('', ' | '); echo getGalleryTitle(); ?></h2>
						</div>

							<div id="padbox">
							<?php printGalleryDesc(); ?>
							<div id="albums">
								<?php while (next_album()): ?>
								<div class="album">
											<div class="thumb">
										<a href="<?php echo html_encode(getAlbumLinkURL());?>" title="<?php echo gettext('View album:'); ?> <?php echo getAnnotatedAlbumTitle();?>"><?php printAlbumThumbImage(getAnnotatedAlbumTitle()); ?></a>
					 						 </div>
											<div class="albumdesc">
										<h3><a href="<?php echo html_encode(getAlbumLinkURL());?>" title="<?php echo gettext('View album:'); ?> <?php echo getAnnotatedAlbumTitle();?>"><?php printAlbumTitle(); ?></a></h3>
					 							<small><?php printAlbumDate(""); ?></small>
										<p><?php printAlbumDesc(); ?></p>
									</div>
									<p style="clear: both; "></p>
								</div>
								<?php endwhile; ?>
							</div>
							<br clear="all" />
							<?php printPageListWithNav("« ".gettext("prev"), gettext("next")." »"); ?>
						</div>

					</div>
					<?php if (function_exists('printLanguageSelector')) { printLanguageSelector(); } ?>

					<div id="credit">
					<?php
					if (function_exists('printUserLogin_out')) {
						printUserLogin_out('', ' | ');
					}
					?>
					<?php printRSSLink('Gallery','','RSS', ' | '); ?>
					<?php printCustomPageURL(gettext("Archive View"),"archive"); ?> |

					<?php	if (function_exists('printContactForm')) {
						printCustomPageURL(gettext('Contact us'), 'contact', '', '', ' | ');
					}
					?>

					<?php
					if (!zp_loggedin() && function_exists('printRegistrationForm')) {
						printCustomPageURL(gettext('Register for this site'), 'register', '', '', ' | ');
					}
					?>
					<?php printZenphotoLink(); ?>
					</div>

					<?php
					printAdminToolbox();
					zp_apply_filter('theme_body_close');
					?>

					</body>
					</html>
					

Try and buy Alkaline→