Jump to content






Photo * * * * * 5 votes

App Creation Walkthrough

Posted by Michael, 15 June 2011 · 746 views


So yesterday I went through the steps in creating a hook from scratch.  Lots of people seemed to enjoy that and found it useful, which is awesome.  I was asked in the comments to do another one of these for an application, so I'd like to take the time to do that now.

Application development is different in a lot of ways from hooks.  Apps can do so much, that to write up a walkthrough for something that takes advantage of all of the available options would take a massive amount of effort.  So what I'd like to do is write up a very basic application here as a starting point, and then maybe later we can talk about specific new application functionality topics.

For this example, I've chosen to make a basic "About Us" application.  The end product will be a new tab at the top of the page that links to this app, and clicking on it will bring you to a single page that has some text on it that you set in the Admin CP. using an IP.Board editor setting.  The public page will use a friendly URL for it's address, and there will be a single Admin CP page where you can adjust the text.

The way I start with a new application is by starting to build the file structure in the IP.Board files.  A new app you create will always reside in the /admin/applications_addon/other/ directory in your IP.Board install.  Create a new folder in this directory and name it whatever you like.  It has to be a single word (underscores are fine if you'd like) with no spaces.  I prefer to stay with a completely lowercase name for my apps if possible, so I'm going to call this 'aboutus'.  This is your home base for this application, and will be referred to as the application directory throughout this walkthrough.  Inside that folder you need to start making files and folders based on what all the application will be able to do.

Since we will have both a public and admin side to this application, add a modules_admin and modules_public directory inside your application's directory.  As stated above, we'll have a friendly URL for our application, and that is done through an extensions file, so also add an extensions directory to this folder.  In addition, (nearly) all applications will have both a setup and xml folder too, those store the instructions needed to install, upgrade, and uninstall the app, so add each of those too.  In addition, you want to have a skin_cp folder.  This is used for skin files you'll use in the Admin CP (which we won't need) and for an application icon (which we will need).  The way IP.Board's application framework works is that it looks for these specific folder names, so as long as you name them correctly, the application will see them and use them.

Right now, we have the following setup for our application:

Attached Image

The next thing we want to do is put the standard index.html files that IP.Board uses into each of these folders.  This file is used so that if anyone should happen to browse to the folder in their browser, instead of seeing the content of the folder they see the content of this index.html file instead.  So go up one level to your /admin/applications_addon/other/ folder, copy the index.html file from there, and paste a copy into your application directory, and inside each subfolder.

Now that we have the basic structure of our application folders, let's go to the development board Admin CP and set up the application.  Go to the Manage Applications & Modules page and click the Add New Application button.  On the resulting page we fill this out based on what this application will do.  For this application, that looks like this:

Attached Image

A few things to keep in mind: the application Public Title is what will be used on the public side tab.  You want the application directory setting to match the name of the folder you created.  Be sure to enable it, but there shouldn't be any real need in most cases to protect it.  The update URL is again optional.

On the tab permissions tab, you can set this however you like.  We'll not be hiding it from anyone, but you can change this as needed.  And there's likely no need to use the global caches tab for most apps.  You can then save this application.

Next we need to set up the application's modules.  Click the button to the right of our newly added application and select "Manage ADMIN modules".  Modules are different large sections of an application, the highest way of categorizing different functionaly inside of the app.  Since we have a very basic app we're working with, we just need a single module.  Click the Add New Admin Module button and fill it out like so:

Attached Image

Again, let's go over this.  The Module Title will show up when inside the module in the Admin CP.  The module key is important, it'll be used in both folder names and class names coming up here shortly, so keep those unique (you can use the same module name once on the admin side and once on the public side, but not twice in either one of those places) and short enough for easy use.  Again, don't use spaces, and try to keep them a single word and lowercase.  And again, keep it enabled and not necessarily protected.  Save the module.

Jump back out to your application's directory, and go into the modules_admin directory.  Create a new folder here, and name it the same as the module key above.  Go ahead and copy that index.html file into that new directory too; we'll want to always put one of those index.html files in each folder, so be sure to do that for each folder you added.

Now, inside of this configuration folder, we can start making our PHP files.  Each file you create is going to be a distinct 'section', which like modules, is just a further way to categorize functionality.  You have to have at least one section (like like you needed at least one module), so let's create one.  Create a new PHP file here and name it settings.php.  In addition to this file, each module folder needs a special file called defaultSection.php, so create that as well.

Our next step is to start writing code.  Let;s start with the defaultSection.php file.  Open it up in a code editing program and set its code to this:

<?php

$DEFAULT_SECTION = 'settings';

That's all that's needed in this file.  You can add comments if you'd like, but that's up to you.  All you need this file to do is tell IP.Board which section is the default one that is loaded when loading this module.  So just give it the section name there.  No closing ?> tag is needed.

Next, open up the settings .php file.  This is where things start to get interesting.  First off, we need to define our class name.  This will be not something we create on our own, it is based on the application, module, and section names, as well as whether this is a public or admin file.  The structure of the class name is this:

PUBLIC|ADMIN_APPLICATIONKEY_MODULEKEY_SECTIONKEY

Following how we've set this up so far, that gives us this as the class name:

admin_aboutus_configuration_settings

So we use that in our source code.  These classes will always also extend the standard IP.Board class 'ipsCommand'.  By extending that class, these files automatically get access to all of the standard objects like $this->registry, $this->settings, $this->memberData, etc.  Here's the basic initial structure of the file:

<?php

class admin_aboutus_configuration_settings extends ipsCommand
{
}

Again, we don't need a closing ?> tag.  As a small security measure, we add this code to the top, above the class declaration line:

if ( !defined('IN_ACP') )
{
	print "<h1>Incorrect access</h1>You cannot access this file directly. If you have recently upgraded, make sure you upgraded 'admin.php'.";
	exit();
}

This just basically stops anyone from directly accessing the file.

Now, inside of the class we've created, we need to create a function called doExecute.  This is the standard function that is always called first by IP.Board when a section file is loaded.  You would use this to put in the code that actually kicks off the section.  If your app was complex, you'd probably have something that does a switch statement to choose different actions based on the user input.  Think about how modifying a member works in the Admin CP.  The process of finding the member in the list, viewing them in the Admin CP, and making changes, is all one section.  You just might do different things that the same section file handles.

As we'll only be using the Admin CP to handle a settings page, we can make a relatively simple function in our doExecute function.  Don't worry if this code is confusing, this is just some basic code for displaying a setting group page.  Here is our current code for this file:

<?php

if ( !defined('IN_ACP') )
{
	print "<h1>Incorrect access</h1>You cannot access this file directly. If you have recently upgraded, make sure you upgraded 'admin.php'.";
	exit();
}

class admin_aboutus_configuration_settings extends ipsCommand
{
	public function doExecute( ipsRegistry $registry )
	{
		/* Get settings library */
		$classToLoad = IPSLib::loadActionOverloader( IPSLib::getAppDir('core').'/modules_admin/settings/settings.php', 'admin_core_settings_settings' );
		$settings	= new $classToLoad();
		$settings->makeRegistryShortcuts( $this->registry );
		
		/* Load the language */
		$this->lang->loadLanguageFile( array( 'admin_tools' ), 'core' );
		
		/* HTML and form code */
		$settings->html		 = $this->registry->output->loadTemplate( 'cp_skin_settings', 'core' );		
		$settings->form_code	= $settings->html->form_code	= 'module=settings&amp;section=settings';
		$settings->form_code_js = $settings->html->form_code_js = 'module=settings&section=settings';		
		
		/* Some final stuff */
		$settings->return_after_save = $this->settings[ 'base_url' ] . $this->form_code;
		$this->request[ 'conf_title_keyword' ] = 'aboutus';
		
		/* Display the settings */
		$settings->_viewSettings();
		
		/* Output */
		$this->registry->output->html_main .= $this->registry->output->global_template->global_frame_wrapper();
		$this->registry->output->sendOutput();
	}
}

What is important is that last output section.  Without that there, IP.Board will never display anything, so don't forget that.

As we're going to be using the Admin CP in this app to display a settings page, let's go set that up now before we get to the point where we're checking the page itself.  So, in the Admin CP, go to the System Settings page, and click the Add New Setting Group button.  This is for adding the group that our main setting will live in.  So fill out the form like this:

Attached Image

There are some very important things to note here.  First, we want to make sure the setting group is associated with our application in the Group Application setting.  Next, in the Group Keyword setting, we don't necessarily need it to match our application key, but it is helpful to do so.  Note that whatever you put here is what needs to go in the $this->request[ 'conf_title_keyword' ] line in the code above.  Finally, we do want to hide this from the main settings list, as we'll be accessing it from the My Apps tab instead.  Save this group.

Back on the System Settings page, click on the Apps tab, then click on the new 'About Us' group we created.  In here, click the Add New Setting button at the top.  All you really need to set for this setting are the title (About Us Text), the type (Full Editor), and a key (aboutUsText).  You can flesh out the rest if you'd like, but it's not necessary to get this setting working.  Save the setting.

We have one last thing we need to do before the Admin CP page will work.  Back in the application directory, in the /modules_admin/configuration/ folder, add a new folder called xml.  Again, put an index.html file in there like we've been doing for new folders.  Then create a new file in this folder called menu.xml.  This file will be used by IP.Board to build the application menu.  This can be very complex for larger applications, but as ours is simple it only needs a little bit of code.  Add the following to your menu.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<menu>
	<tabitems>
		<item>
			<title>Manage Settings</title>
			<subitems>
				<subitem>
					<subitemtitle>Manage Settings</subitemtitle>
					<subsection>settings</subsection>
					<subitemurl></subitemurl>
					<subitemrolekey></subitemrolekey>
					<subisredirect>0</subisredirect>
				</subitem>
			</subitems>
		</item>
	</tabitems>
</menu>

Save the file, then jump back to the Manage Applications & Modules page and click the Recache Apps & Modules button at the top.  This will rebuild the application menus based on the XML files, and so after doing so you should see that this has been updated, and the Admin CP part of this application works:

Attached Image

One final thing we'll want to do to wrap up the Admin CP side is to create an application icon.  I like to use the set of Silk icons from FamFamFam.com for this, as that's what IPS uses for a lot of its icons.  Pick an image file from there and save it into your application's skin_cp folder, and rename it appIcon.png.  That image will now show up as the application's icon in various points in the Admin CP:

Attached Image

Now, on to the public side.  We'll start by creating a module just like we did on the admin side.  In the Manage Applications & Modules page, click the button beside our app and click Manage PUBLIC Modules, then Add New Public Module.  Here's how we'll set this one up:

Attached Image

Most of this is pretty straightforward, just again remember that we need to note what we're using in the module key as it is used elsewhere.  Back out in the application directory, create a folder in modules_public using that name 'main' for this module, and add the standard index.html to it.  Again, we'll need to create a section file and the defaultSection.php file that points to it.  So first create a PHP file named view.php, and one called defaultSection.php.  The content of the defaultSection.php one should be just like the last one, but pointing to the name of this default section instead:

<?php

$DEFAULT_SECTION = 'view';

Save that, then open up the view.php file we created.  The basic structure will again be similar to what we did in the Admin file: the class name follows the same format, we also start with a doExecute function, but that little security check at the top is a little different.  Here's our starting code for this part:

<?php

if ( !defined( 'IN_IPB' ) )
{
	print "<h1>Incorrect access</h1>You cannot access this file directly. If you have recently upgraded, make sure you upgraded all the relevant files.";
	exit();
}

class public_aboutus_main_view extends ipsCommand
{
	public function doExecute( ipsRegistry $registry )
	{
	}
}

Now again, we need to just start writing some code in here to do something.  Like the admin side, some sections may do a lot of different things in these files and thus need some control statement to handle different actions.  But we're just going to go ahead and add code to display our text that we set in the Admin CP.  Here's our new code for this file:

<?php

if ( !defined( 'IN_IPB' ) )
{
	print "<h1>Incorrect access</h1>You cannot access this file directly. If you have recently upgraded, make sure you upgraded all the relevant files.";
	exit();
}

class public_aboutus_main_view extends ipsCommand
{
	public function doExecute( ipsRegistry $registry )
	{
		/* Set our parser flags */
		IPSText::getTextClass('bbcode')->parse_html	= 0;
		IPSText::getTextClass('bbcode')->parse_nl2br   = 0;
		IPSText::getTextClass('bbcode')->parse_bbcode  = 1;
		IPSText::getTextClass('bbcode')->parse_smilies = 1;
		
		/* Clean up the message */
		$this->settings['aboutUsText'] = IPSText::getTextClass('bbcode')->preDisplayParse( IPSText::getTextClass('bbcode')->preDbParse( $this->settings['aboutUsText'] ) );
		
		/* Set the title and navigation */
		$this->registry->output->setTitle( IPSLib::getAppTitle('aboutus') );
		$this->registry->output->addNavigation( IPSLib::getAppTitle('aboutus'), 'app=aboutus', "false", 'app=aboutus' );
		
		/* Send to screen */
		$this->registry->output->addContent( $this->settings['aboutUsText'] );
		$this->registry->output->sendOutput();
	}
}

The top half of our doExecute function is just us setting up the parser and parsing the text we'll be setting in the Admin CP.  The bottom half does things like set the page title, construct the navigation breadcrumb, and actually tell IP.Board to display this.  Save the file, then jump back over to the Admin CP, to the settings page for this app.  Set some basic text for this to display and save that.  I'll use some Lorem Ipsum text as an example.  Setting this, and checking the public side, and clicking on the About Us tab, we see this:

Attached Image

Fantastic!  We have content showing up that we can control via the Admin CP.  So now there are just a few things to wrap up.  First off, we want friendly URLs, so back in the application directory, in the extensions folder, create a new file called furlTemplates.php.  Inside that file, add this code:

<?php

if ( !defined( 'IN_IPB' ) )
{
	print "<h1>Incorrect access</h1>You cannot access this file directly. If you have recently upgraded, make sure you upgraded all the relevant files.";
	exit();
}

$_SEOTEMPLATES = array( 'app=aboutus' => array( 'app'			=> 'aboutus',
												'allowRedirect' => 1,
												'out'		   => array( '/app=aboutus/i', 'aboutus/' ),
												'in'			=> array( 'regex'   => "#^/aboutus(/|$|\?)#i", 'matches' => array( array( 'app', 'aboutus' ) ) ) )
					  );

This is the code that tells IP.Board that it needs to change any URLs that end in app=aboutus to now end in /aboutus/.  Save this, then visit the Cache Management page in the Admin CP and click the Rebuild FURL Cache button.  Jump back out to the public side and refresh the page, the tab should now be pointing to a friendly URL instead of the non-friendly version.

Attached Image

The app itself is now done and will work just fine on your site, but we need to package it up for redistribution.  This generally involves two different parts: the XML files and the PHP setup files.  The setup files are generally used for database commands, such as the queries necessary to install any new database tables used by the app, or to add new columns to the groups table for group permissions.  We didn't have any of these in this app, so we can skip this part.  We do, however, need to create our XML files.

In our application's main directory, open the /xml/ folder.  In here, we'll need to hand-code a file first.  Create a file named versions.xml in this folder.  The content of the file should be this:

<?xml version="1.0" encoding="UTF-8"?>
<versions>
	<version>
		<human>1.0.0</human>
		<long>10000</long>
	</version>
</versions>

This file is used to record the various versions of our app, including a human-readable version and a long version number.  As this is the first version of our app, we set these to the basic values listed here.  As you update your app you'll create additional <version> nodes in this file.  But for now, just save this.

Next, we can create some more XML files that hold data about the items we created manually above.  Start by creating empty files with the following names: information.xml, aboutus_settings.xml & aboutus_modules.xml (full disclosure: you should not need to create these files by hand, but there's a bug with this feature as of the time of this entry).  Now, on the Manage Applications & Modules page in the Admin CP, click the buttons for Export Modules XML and Export Applications XML.  Then go to the System Settings page and click the Export All XML Settings button.  By clicking these buttons, you'll populate the appropriate XML files with the application, module, and settings data:

Attached Image

And that is that.  If you zip up this application directory, it can be redistributed, uploaded to other sites, and the application can be installed by others.  I've attached the source code for this in case you'd like to look through it as you follow along, or if you just want to use this as the starting point for your own project.

Attached File  Application Sample.zip (15.02K)
Number of downloads: 62

Hopefully I didn't miss anything, but again, if I've left anything unexplained that you'd like to talk about more, or if there was something you felt I left out, please just let me know.




OMG Amazing.. When I get more time I'm going to COMB this thing.
humbling... :)
Quick question
$classToLoad = IPSLib::loadActionOverloader( IPSLib::getAppDir('core').'/modules_admin/settings/settings.php', 'admin_core_settings_settings' );

How does that work if settings/settings.php doesn't even exist?
Oh, are you doing this on 3.2, or 3.1?  The location for that file changed in 3.2, and that's the version I was doing this on.
I'm on 3.2 but I figured it out in the end. Managed to get the app up :D http://xternalserv.c...dex.php/aboutus My board was having really weird issues with getting skin errors in the ACP.

One thing, could you go over how to use skin bits (cache) and language bits? Especially admin skin bits.. Thanks to your guide I was able to get the Hello World App that Mark created to work. That example uses skin and language caches and I didn't really understand how they worked.

Thanks a bunch :) Really well written.

.Peter, on 16 June 2011 - 10:17 AM, said:

One thing, could you go over how to use skin bits (cache) and language bits? Especially admin skin bits.
Yeah, I figured skin and language stuff would be something people would like to learn about too.  Maybe I'll use this app as a starting point for a series of entries where I add new features to show off things like skin and language bits.
:D Where is the like button for blogs :(
Evidently there isn't one anymore, or at least it just hasn't gotten updated for this new version yet.
Typical, its an about us application, when I have developed an about us app called iAbout ULTRA lol
I hope you're not mad, Andy, I didn't intend to say that this is a better way of doing an app like that, or anything, I just thought this would be a good way of showing off a few basic parts of app creation.  Don't hate me!
I don't hate you, just hope know one comes up with any ideas to do it themselves.

Might use this walkthrough to upgrade my apps, they need a recode to clean them up a bit.

Plus, I have been having issues upgrading them something to do with settings file or somethign or other.
Although, I am having trouble with it displaying a template bit.
Did you check out the newest entry?  That one has better examples of templates.
I've fixed, it, named the template bit wrong in the file, now with the furl (never understood), I have a switch like so;

switch ( ipsRegistry::$request['view'] )
				{
						case 'admins':
								$this->showAdmins();
								break;
						case 'profile':
								$this->output .= $this->registry->output->getTemplate( 'iAboutULTRA' )->viewProfile( $data );
								break;
   					 default:
								$this->output .= $this->registry->output->getTemplate( 'iAboutULTRA' )->ViewLanding( $data );
								break;

				}

How would that show up in the users address bar :S
How it'll show up in the address bar will depend on how you have your friendly URLs set up in the furlTemplates.php file, and how you handle inputs in the coreVariables.php file.  Start off by making sure your non-friendly URLs work like they should, then you can concern yourself with using these extensions to pretty them up.
I've tried this;

$_SEOTEMPLATES = array( 'app=about' => array( 'app'   		 => 'about',
   											 'allowRedirect' => 1,
   											 'out'	   	=> array( '/app=about/i', 'about/' ),
   											 'out'	   	=> array( '/app=about&view=admins/i', 'about/admins' ),
   											 'out'	   	=> array( '/app=about&view=profile/i', 'about/profile' ),
   											 'in'			=> array( 'regex'   => "#^/about(/|$|\?)#i", 'matches' => array( array( 'app', 'about' ) ) ) )
   				   );

But it don't seem to work.
You're defining 'out' three times there, you'd want to set each of those up as individual elements of this $_SEOTEMPLATES array.
Oh right, I never did understand furl in IP.Board, thanks :D

Sorry to be cheeky can you show me an example, either here, or in PM please.
Brilliant.  Very many thanks for this and the hooks blog.  Like others I just never new how to get started.
Grr.... So I've tried to make my own apps but if I do app=appName it either shows a blank screen, the forum index or it redirects to index.php.

Tags

  • development
  • walkthrough
  • app
  • application
  • hook

0 user(s) viewing

0 members, 0 guests, 0 anonymous users