• entries
  • comments
  • views

About this blog

Our staff keeps you up to date on happenings

Entries in this blog

We are releasing patches for IP.Board 3.3.x and IP.Board 3.4.x to address two issues recently reported to us.
It has been brought to our attention that certain PHP configurations allow for a potential SQL injection vulnerability. Although this exploit requires some knowledge of your configuration and for certain files to be web-readable, we felt it important to release an update.
Additionally, it has been brought to our attention that it may be possible to send attachments via the email classes which would ordinarily be removed.

To apply the patch
Simply download the attached zip for your IP.Board version and upload the files to your forum server. You do not need to run any scripts or the upgrade system.
IP.Board 3.3.x
IP.Board 3.4.x
If you are an IPS Community in the Cloud client running IP.Board 3.3 or above, no further action is necessary as we have already automatically patched your account. If you are using a version older than IP.Board 3.3, you should contact support to upgrade.
If you install or upgrade to IP.Board 3.4.7 after the date and time of this post, no further action is necessary as we have already updated the main download zips.
We extend our thanks to  Andrew Erb  for notifying us of the email issue privately and promptly.
IPS is investigating a possible security exploit reported to us a few hours ago.
We are developing a fix for this issue now and anticipate its release tomorrow. Until the fix is released, clients are advised to delete the following file from their community:
This will disable the IPS Connect service which is our system to allow for multiple sites to share one login. Most clients will not need this service but if you do use it then we still suggest you temporarily disable until a fix is released tomorrow.
IPS Community in the Cloud clients: we have already disabled this feature for you so you are not impacted by this exploit.
Update : Patches are now available .
We are happy to release the second beta of IPS Community Suite 4.0!
IPS welcomes any clients who enjoy testing beta software to participate and post bugs in our  bug tracker . These beta releases help us to provide a more stable final release and the more people who participate in testing the better it is for all.
This release makes available: [*]Forums [*]Blog [*]Gallery [*]Downloads [*]Calendar
This release does  not  contain Commerce (formerly IP.Nexus), Pages (formerly IP.content), or Chat. These three apps will be released soon as a separate download.
The upgrade system is now available and you can upgrade from IP.Board 3.4.7 to test this system  However:   do not upgrade your live community!  IPS does  not  provide technical support or services for beta releases. You can append "-TESTINSTALL" on to the end of your license key to allow to a separate install for test purposes.
You can download IPS Community Suite 4.0.0 Beta 2 in the  client area . Go to your Purchases section, select your license, and click the download link. IPS Community in the Cloud clients do not yet have access to the beta. That will be coming soon.
You will be able to upgrade from Beta 2 to Beta 3 when it is released and to all future betas through final release.
If you are not interested in downloading our beta releases you can still check out our IPS Community Suite 4.0  preview site  to see the new version in action.
Note: If you are already running Beta 1 you can upgrade in your AdminCP. You will see a notice on your Dashboard.
Please post in our special  Beta Releases forum  on the preview site for anything about Beta 2. Enjoy!
We will be upgrading our own site next week. Stay tuned!
Update:  Pages pre-release now available .

We are happy to release the first beta of IPS Community Suite 4.0!
IPS welcomes any clients who enjoy testing beta software to participate and post bugs in our bug tracker . These beta releases help us to provide a more stable final release and the more people who participate in testing the better it is for all.
This release makes available: [*]Forums [*]Blog [*]Gallery [*]Downloads [*]Calendar
This release does  not contain Commerce (formerly IP.Nexus), Pages (formerly IP.content), or Chat. These three apps will be released soon as a separate download.
The upgrade system is now available and you can upgrade from IP.Board 3.4.7 to test this system  However: do not upgrade your live community! IPS does  not provide technical support or services for beta releases. You can append "-TESTINSTALL" on to the end of your license key to allow to a separate install for test purposes.
You can download IPS Community Suite 4.0.0 Beta 1 in the client area . Go to your Purchases section, select your license, and click the download link. IPS Community in the Cloud clients do not yet have access to the beta. That will be coming soon.
You will be able to upgrade from Beta 1 to Beta 2 when it is released and to all future betas through final release.
If you are not interested in downloading our beta releases you can still check out our IPS Community Suite 4.0 preview site to see the new version in action.
Please post in our special Beta Releases forum on the preview site for anything about Beta 1. Enjoy!

IPS Community Suite 4.0 is nearly here, and we'll be distributing betas very soon. But 4.0 is really just the beginning; with the new tightly integrated, one-version suite of applications, we're already starting to think about all of the features we'd like to add in the future. This brings us nicely to the final 4.0 feature we'd like to talk about: the upgrade system.
In 4.0, when a new version is released, you'll see a message like this pop up in the Admin CP:

Clicking the "Download" button will allow you download, right from the Admin CP, a zip file with the new version. This zip file will contain just the changed the files from the version you're using (in technical terms, this is called a  delta update ) to save time and bandwidth when uploading the new version to your server. The system automatically knows what apps you have installed (so you don't have to download a separate zip for each application) and even knows if you've renamed your AdminCP directory and accommodates for that.
Here's a video of the process in action:

As mentioned in our last blog entry, we're hard at work on our next version of IP.Nexus.

One of the more visual features we're adding in this version is an updated mobile skin - here are some screenshots!

Main store page:

Category listing:

Product screen:

Cart view:

Checkout screen:

Client area - menu:

Client area - invoice view:

New support request form:

Login Handlers are the different methods for logging into the IPS Social Suite. We currently support: [*] " Internal", which is for accounts created natively through the suite. [*]Facebook [*]Twitter [*]Microsoft (this is currently referred to as "Windows Live", though they rebranded to "Microsoft Account" a short while ago) [*]LDAP [*]"IPS Connect", which is our SSO solution for connecting your site with other IPS Social Suite installations or third-party applications. [*]A generic handler for any MySQL database you have access to.
In 4.0 we've made a number of changes to the Login Handlers which I wanted to mention.
Improved Password Encryption
We currently use a salted md5 hash for hashing passwords. md5 has been a popular password hashing technique for years - however, it is not the most secure hashing method.
md5 is designed to be computationally efficient (meaning generating a hash is quick). The problem with this is that if a server were ever compromised to the point that someone were able to gain access to a database containing passwords hashed using md5, and someone were to use a program to generate and hash different strings repeatedly until a match were found, the password could be worked out. One particularly well-known program claims to be able to make 5.6 billion md5 hashes per second with a relatively modern GPU. Even with our hashing method which includes multi-level hashing and a salt, this means, assuming an 8-character long password using only alphanumeric characters were used, a password could be calculated in about 3 days.
While I'm unaware of any cases of this actually happening, we want to make sure that our products are as secure as they can be. For this reason, in 4.0, we're migrating to Blowfish . Blowfish is a more cryptographically secure technique for generating hashes that is deliberately slow, meaning that even if your database were ever compromised, the passwords will still be secure.
New Login Handlers
In addition to the Login Handlers mentioned above, we've added support for Google and LinkedIn.
Improved Facebook and Twitter support
Currently, although you can log in with Facebook and Twitter, they're not treated on the back-end as true Login Handers. This is because of how Login Handlers in 3.x were designed (which was before such 3rd party login services were popular) in that they assumed you would provide a username (or email) and password directly into a form, and subsequently didn't accommodate the OAuth-style login processes.
Since we've rewritten the way Login Handlers are designed, this means we can treat Facebook and Twitter (and Google and LinkedIn which both also use OAuth) exactly the same as the rest.
Practically, this means you'll see Facebook and Twitter in the Login Handlers section of the Admin CP, and manage them as you would any other login method.
Updated Microsoft Support
Microsoft now support OAuth for login through them so we've updated to use that. In addition to being necessary for when they stop supporting the old way, it's much easier to set up for the administrator.

I want to briefly show our new cover photo support. Cover photos allow users to upload an image to represent something in the community; we currently support them in profiles and calendar events and may roll out support to other areas later.
Here's a video of it in action for a calendar event.

It's really simple to use, and of course still works responsively like the rest of our default theme. We hope it adds a new element of customization for content in your community.
For developers, supporting cover photos in your own addons is as easy as you'd expect. A helper is available which handles the nitty-gritty for you; you simply add $item->coverPhoto()  to your template, override a couple of methods in your controller, and optionally build your own menu to control the user interaction (or you can let the helper output them for you, as in the video above). That's it!
As always, screenshots are from pre-release software and are subject to change before release.   

By Mark,

There's a table in the Admin CP of the IPS Social Suite that I really like - the members table. It has some really cool options - you can reorder the data just by clicking on a column head; you can quickly search for a member by typing a name into a search box at the top; there's some filter options to quickly show banned, locked, spam and validating members; and there's an advanced search form to search for members based on practically any criteria.
It would be great if these features were available elsewhere. So much like we did for forms , we decided to create a central helper class for building tables.
To demonstrate how it works, I'm going to go through, step by step, how I recreated the Admin CP members table in IPS 4.
It starts with one line to create the table, and another to pass it to the output class:
With just those two lines, you'll see this:

Some things to note: [*]We're calling IPSHelpersTableDb - the "Db" part indicates that the source of data for our table is a database table. There are other classes to use, for example, a JSON document as the data source. [*]We pass it the name of our database table (or for the other classes, whatever the data source is) and the query string part of the URL where we're going to be displaying this (which we need to build the links and AJAX calls). [*]I'm passing it to the output through a template called "block" which simply adds the dark-blue bar at the top, which isn't actually part of the table itself, and some padding. The "members" parameter is the key for the langauge string to use in that dark-blue bar. [*]I'm passing $table directly to the template - the helper class has a __toString method which renders the table, so the output class thinks it's been given a normal string.
The first obvious thing is that we're showing all the columns in the database table, which obviously we don't want. So let's add another line to specify which columns we want:
In this example, I'm giving the helper class a list of columns to include - I could alternatively pass a list of columns to exclude, if that would be more appropriate.

The output is now this:

Some things to note: [*]It's worked out pagination itself. When you click a pagination link, the contents of the table will update with AJAX, including changing your browser's URL (unless you have JavaScript disabled of course, in which case it will work like a normal link). Pagination defaults to 25 results per page, but you can change that just by changing a property in the class. [*]All the columns are clickable, which will resort the results. You can sort any column ascending or descending. Resorting will also update with AJAX (including changing your browser's URL), unless JavaScript is disabled.
I want the headers to display something more meaningful than the column name. The system will automatically look for language strings which match the column name - you can also optionally specify a prefix, and it'll look for langauge strings which match that followed by the column name.
Let's specify a prefix:
And I'll then create some language strings that match that (so "members_name", "members_email", etc.).
The output is now this:

Next - we need to change how we display some of those values. The joined date and the group are displaying the raw values from the database, but we want something more meaningful than that.
To format the values, we simply create an array of lambda functions - one for each we want to format:
I'm also going to add one additional line to specify the "main" column, which applies some additional styles:
The output is now this:

Some things to note: [*]I'm using the IPSDateTime class to format the joined date. The ts method in this is a factory method which takes a UNIX timestamp and returns an object of IPSDateTime . IPSDateTime extends DateTime , so all the features of that class are available to us. The localeDate method returns a string with the date formatted appropriately according to user's locale. [*]The IPSMemberGroup::load call being executed for each result may look like it might be resource intensive, but it caches objects it creates, so it's only actually "loading" each group once.
Now  I want to add a column with the user's photo. There isn't a single "photo" column in the database we can use for this (since the photo could be one they uploaded, a photo from their Facebook account if they're using Facebook Connect, a Gravatar image, or some other things), we need to use a method in the IPSMember class.
This isn't a problem. I can simply add an element to our list of fields to include and add that into the parsers.
I'll also want to specify that we cannot use the photo column for sorting:
The output is now this:

Some things to note: [*]Since this isn't a value which exists in the database, the value of $val in the lambda function will be NULL , however, $row has all the data for that record. [*]We're not using IPSMember::load to get the member object, since that would execute an additional query for every result, which would be resource intensive, and unnecessary since we already have that data. Instead, we use the constructFromData method and pass it the row from the database.
Next, I want to specify the default sorting. This is done with just two lines of code:
The output is now this:

Now, I want to add a quick search box. All we need to do is specify which column the quick search should look at:
The output is now this:

Some things to note: [*]As you type, results are obtained with AJAX. [*]You can page through your results (the number of pages will update automatically) and reorder your results by clicking the headers without loosing your search.
I also want to allow more advanced search options - like to search by email address, or joined date. To do this, I create a new array:
To explain what's going on here: [*]The keys are the columns we're letting the user search on. [*]The values are usually a constant indicating the type of search that is appropriate for that column. [*]The member_group_id element is a bit more complicated. It has to specify an array of options (I've omitted the code to generate $groups in this snippet, but it'll be at the end of this blog entry), and, because we need to search both primary and secondary groups based on the value, there's a lambda function to get the proper WHERE clause for the query.
Now, next to the quick search box there's a button which will bring up a modal popup (or just take you to a new page if JavaScript is disabled) which looks like this:

Some things to note: [*]The date entry boxes use the HTML5 date input type: If your browser doesn't support that, there's a JavaScript fallback: And if you're really awkward and are using a browser that doesn't support the HTML5 date input type and have JavaScript disabled, you'll see a regular text box where you can enter a date in practically any format, and it'll work it out. [*]After performing the search, you can reorder your results by clicking the headers without loosing your search.
Now, I want to add some filters so you can quickly see banned, spam, locked and validating members. To do this, you create an array simply specifying the WHERE clause to use in the query for each filter:
For this though, I'll also need to join the core_validating database table, so we add one more line for that:
The output is now this:

Some things to note: [*]The helper class will add the "All" filter automatically. [*]It's getting the word to use for the filter by looking for a language string with the same key as the key in the array passed. [*]Like everything else, clicking a filter updates the results with AJAX and the filter is retained in searches.
Finally, the last thing I need to do is add a column with some buttons. You can specify a normal array for buttons to show in the header, and a lambda functions to return an array for buttons to show for each row:
Our finished table looks like this:

And behaves like this:
To recap, here's the code, in it's entirety to generate that table:
/* Create the table */ $table = new IPSHelpersTableDb( 'core_members', 'app=core&module=members&section=members' ); /* Display */ IPSOutput::i()->output = IPSOutput::i()->getTemplate( 'global' )->block( 'members', $table ); $table->include = array( 'name', 'email', 'joined', 'member_group_id', 'ip_address' ); $table->langPrefix = 'members_'; $table->parsers = array( 'joined' => function( $val, $row ) { return IPSDateTime::ts( $val )->localeDate(); }, 'member_group_id' => function( $val, $row ) { return IPSMemberGroup::load( $val )->formattedName(); } ); $table->mainColumn = 'name'; $table->include = array( 'photo', 'name', 'email', 'joined', 'member_group_id', 'ip_address' ); $table->parsers = array( 'photo' => function( $val, $row ) { return IPSMember::constructFromData( $row )->photo('mini'); }, $table->noSort = array( 'photo' ); $table->sortBy = $table->sortBy ?: 'joined'; $table->sortDirection = $table->sortDirection ?: 'desc'; $table->quickSearch = 'name'; $table->advancedSearch = array( 'member_id' => IPSHelpersTableSEARCH_CONTAINS_TEXT, 'email' => IPSHelpersTableSEARCH_CONTAINS_TEXT, 'ip_address' => IPSHelpersTableSEARCH_CONTAINS_TEXT, 'member_group_id' => array( IPSHelpersTableSEARCH_SELECT, array( 'options' => $groups ), function( $val ) { return array( 'member_group_id=? OR ? IN(mgroup_others)', $val, $val ); } ), 'joined' => IPSHelpersTableSEARCH_DATE_RANGE, ); /* Filters */ $table->filters = array( 'members_filter_banned' => 'member_banned=1', 'members_filter_locked' => 'failed_login_count>=' . (int) IPSSettings::i()->ipb_bruteforce_attempts, 'members_filter_spam' => '(members_bitoptions & ' . IPSMember::$bitOptions['bw_is_spammer'] . ') != 0', 'members_filter_validating' => 'v.lost_pass=0 AND v.vid IS NOT NULL' ); $table->joins = array( array( 'from' => array( 'core_validating' => 'v' ), 'where' => 'v.member_id=_0.member_id' ) ); $table->rootButtons = array( 'add' => array( 'icon' => array( 'icons/add.png', 'core' ), 'title' => 'members_add', 'link' => 'app=members&module=members&section=members&do=add', ) ); $table->rowButtons = function( $row ) { return array( 'edit' => array( 'icon' => array( 'icons/edit.png', 'core' ), 'title' => 'edit', 'link' => 'app=members&module=members&section=members&do=edit&id=' . $row['member_id'], ), 'delete' => array( 'icon' => array( 'icons/delete.png', 'core' ), 'title' => 'delete', 'link' => 'app=members&module=members&section=members&do=delete&id=' . $row['member_id'], 'class' => 'delete', ), ); }; /* Create the table */ $table = new IPSHelpersTableDb( 'core_members', 'app=core&module=members&section=members' ); $table->langPrefix = 'members_'; /* Columns we need */ $table->include = array( 'photo', 'name', 'email', 'joined', 'member_group_id', 'ip_address' ); $table->mainColumn = 'name'; $table->noSort = array( 'photo' ); /* Default sort options */ $table->sortBy = $table->sortBy ?: 'joined'; $table->sortDirection = $table->sortDirection ?: 'desc'; /* Filters */ $table->joins = array( array( 'from' => array( 'core_validating' => 'v' ), 'where' => 'v.member_id=_0.member_id' ) ); $table->filters = array( 'members_filter_banned' => 'member_banned=1', 'members_filter_locked' => 'failed_login_count>=' . (int) IPSSettings::i()->ipb_bruteforce_attempts, /*@todo*/ 'members_filter_spam' => '(members_bitoptions & ' . IPSMember::$bitOptions['bw_is_spammer'] . ') != 0', 'members_filter_validating' => 'v.lost_pass=0 AND v.vid IS NOT NULL' ); /* Groups for advanced filter (need to do it this way because array_merge renumbers the result */ $groups = array( '' => 'any_group' ); foreach ( IPSMemberGroup::groups() as $k => $v ) { $groups[ $k ] = $v; } /* Search */ $table->quickSearch = 'name'; $table->advancedSearch = array( 'member_id' => IPSHelpersTableSEARCH_CONTAINS_TEXT, 'email' => IPSHelpersTableSEARCH_CONTAINS_TEXT, 'ip_address' => IPSHelpersTableSEARCH_CONTAINS_TEXT, 'member_group_id' => array( IPSHelpersTableSEARCH_SELECT, array( 'options' => $groups ), function( $val ) { return array( 'member_group_id=? OR ? IN(mgroup_others)', $val, $val ); } ), 'joined' => IPSHelpersTableSEARCH_DATE_RANGE, ); /* Custom parsers */ $table->parsers = array( 'photo' => function( $val, $row ) { return IPSMember::constructFromData( $row )->photo('mini'); }, 'joined' => function( $val, $row ) { return IPSDateTime::ts( $val )->localeDate(); }, 'member_group_id' => function( $val, $row ) { return IPSMemberGroup::load( $val )->formattedName(); } ); /* Specify the buttons */ $table->rootButtons = array( 'add' => array( 'icon' => array( 'icons/add.png', 'core' ), 'title' => 'members_add', 'link' => 'app=members&module=members&section=members&do=add', ) ); $table->rowButtons = function( $row ) { return array( 'edit' => array( 'icon' => array( 'icons/edit.png', 'core' ), 'title' => 'edit', 'link' => 'app=members&module=members&section=members&do=edit&id=' . $row['member_id'], ), 'delete' => array( 'icon' => array( 'icons/delete.png', 'core' ), 'title' => 'delete', 'link' => 'app=members&module=members&section=members&do=delete&id=' . $row['member_id'], 'class' => 'delete', ), ); }; /* Display */ IPSOutput::i()->output = IPSOutput::i()->getTemplate( 'global' )->block( 'members', $table );
IPS Community Suite 4.0, the most significant update to IP.Board and the rest of our apps we've ever made, is fast approaching a state where we'll be ready for a public preview and, soon after that, public beta testing!
We know most of you are just as excited as we are about this and can't wait to try it out.
With 4.0, we've made some significant leaps in terms of modernization, and it's possible that you might need to do some preparation before you're ready to install it. Notably, our minimum PHP and MySQL versions have gone up. It's the first time we've needed you to do this in 6 years, and the versions we need you to have have been around for a long time, we're not requiring the latest versions.
In addition, 4.0 is UTF-8 only (if you don't know what that is, it's a way text can be stored in your database which you may or may not be using at the moment) and while the 4.0 upgrade process will ask you to convert your database if you're not already using it, this is a moderately time-consuming process, so if you convert your database now, it's one less thing to worry about on upgrade day.
To make this process as easy as possible, we have created a little script which you can upload to your server to test if you're ready.
Download Now
We've previously shown how responsiveness works in the AdminCP, but I'd like to briefly introduce responsiveness on the front end, and pick a few views to show you as examples (this will be a screenshot-heavy entry!)
What is responsiveness?
Before we get to that, allow me to recap what responsiveness is. Responsive design is a method by which you design one page in such a way that it adapts for the available screen space on the device the user is using. This means that one theme handles both the full desktop view and the condensed mobile view with some clever CSS, in contrast to 3.x where we had a separate mobile skin.
When we took the decision to use responsive design for IPS4, one key aim was to ensure that the mobile view isn't feature reduced. We want all functionality and all areas of the suite to be available regardless of device, and with only a couple of exceptions we're on track to deliver this.
Primary navigation
In mobile view, the primary navigation collapses and moves to a menu accessible with the icon in the top-right. The breadcrumb becomes a 'Back' control, taking you up a level from the current page:

The primary navigation, when opened, looks like this:

Given that the responsive theme supports all functionality, this naturally includes moderation. IPS4 support full moderation capabilities regardless of the device you're using. Here's an example of moderating images in Gallery. Notice the menu to quickly select types of content to moderate, as well as the floating toolbar at the bottom of the screen to choose actions.

Settings page
Taking the settings area as an example, here's the same screen at the three supported breakpoints - desktop, tablet and mobile.



Profile view
Here's profile view (which we covered in more detail here ) as seen on a phone:

Calendar views on mobile:


Viewing albums & images in a category:

The blog homepage:

And viewing a blog:

Submitting a topic on mobile:

So that wraps up this round-up of responsive views. Naturally, there's  many more views than this in the suite and we can't show screenshots of every single one, but hopefully this entry has given you a taste of a variety of views, and a better idea of how we're approaching mobile users in IPS4.
As always, screenshots are from pre-release software and are subject to change before release. 

By Mark,

I can distinctly remember 5 years ago reading a blog entry on this site about the "personal conversations" feature in IP.Board 3.0, which we were working on at the time. Up until then, the messenger system in community software and other websites was much like email - you sent one message at a time, with little continuity between messages. We were one of the first, on the entire of the web, to introduce what we called "personal conversations" - a sort of "private topic" between invited members - it was a really exciting idea back then.
For 4.0, we wanted to really focus on the experience of using the messenger - making it super fast and easy to compose, navigate and participate in conversations.
Starting a conversation
When browsing the site, you'll see a messenger icon at the top of every screen just like you do now. When hitting the "Compose Now" button inside though, the form to send your message will appear as a modal window, and when you send, it will disappear again with no page reload. This makes it incredibly fast and easy to send a message from wherever you are, without interrupting your flow. You can also send a message to a specific member by hovering over their name wherever you see it on the site and clicking the "Send Message" button in the hover card that shows.

Browsing conversations
We've completely redesigned the main messenger pages. You now see a (infinitely scrolling) list of all your messages on the left-side. Clicking on any message opens it up in the main pane. All the common actions are enhanced with AJAX so you can open a conversation, add a user and reply all really quickly.
We've not forgotten about mobile devices! The new responsive design in IPS 4.0 means the whole messenger works and looks great whether you're on a desktop or on your phone.

We recognise that when members send a new message, it is often as a response to content read in all areas of the suite. You can now send messages in place without disrupting your flow. We have improved all aspects of sending, receiving and managing messages and are confident these changes will make communicating with other members in private simpler and faster. 
For many years, IP.Board has featured a "Moderating Team" page where the community moderators are listed so that users can quickly and easily identify who to contact in the event they need assistance.  This page has typically been a somewhat generic table-style view of users who are a moderator of some level.  The page is not configurable and has limited usefulness and relevance when you consider the entirety of the suite.  It is a relic of an older age and it really stood out as needing an overhaul, so that is exactly what we have done in 4.0.
As mentioned above, the moderating team page has never been configurable in IP.Board.  If a user is a moderator (either a super moderator, or a forum-level moderator) then they are displayed on this page.  The users are displayed in basic alphabetical order in a table-style view and you cannot easily see which user is responsible for which roles on the site.  Furthermore, if you add a moderator to another application (for instance, IP.Downloads or IP.Gallery) then they may not be displayed on this page if they aren't also a moderator in the forums.
We have completely done away with the way this page used to work and rethought it from the ground up.  Its purpose is simple: show the viewing user which users on the site are "important" and their relevance to the site.  To implement our goal, we have decided to make the entire page configurable.
In the admin area you can now create groupings for this page.  This means that you can put some users in one group, some users in another group, and so on in order to better reflect the hierarchy of your organization.  For instance, here at IPS we would list Management staff at the top, followed by Developers, followed by Support Agents, and possibly followed by community moderators.  You can reorder the groups however you see fit to ensure that the most important users are listed first.
You can also now associate a template with each group.  When you view the staff page, you will probably want to show a little more information for the most important users, but you may want to just show simple links to a profile for the regular community moderators.  By default we will ship with 3 or 4 basic templates that we feel will allow you to display staff groups in different ways to better reflect your organization, however any administrator can add new templates by simply creating a template with the appropriate prefix in the appropriate template group.
When you add users to a group, you can specify a custom name to show (which will fall back to the member's username), you can specify a custom title to show (which will fall back to the member's title) and you can specify a bio to show. Users who are displayed on this page can edit their details right from the staff page directly.

Viewing the page
We wanted to allow this page to be set up to better reflect the staff on a community.  A simple listing of moderators is no longer relevant for many users of the Community Suite - you may want one moderator to not be displayed because they only manage pre-sales questions, or you may want an administrator who is not a moderator to be displayed, or perhaps you want to create a game roster instead of displaying staff but you don't want to give those users moderator privileges on the site.  Now you can do that, and you can better present the page to your users.

As you can see here, the first grouping (labeled "Management") is displayed in full width.  The second grouping called "Developers" are blocks that take up half of the available width.  The last grouping called "Support Agents" are rows of 4 blocks each.  It is important to note that the interface is subject to change and we are still putting some finishing touches on this screen, however hopefully the screenshot will give you a good idea of how the page can be laid out to improve communication between your staff and your visitors.
One of the goals for IPS Community Suite 4.0 was improving content discovery. In other words, making sure content still receives exposure even if it is posted in less used areas of the suite.
The sidebar that shows on the IP.Board index page in 3.x helps with this goal to some extent, however people who visit the forums app infrequently may miss out on valuable content. This became an even more important issue when the decision was made to decouple IP.Board as a standalone application. What if the focus of your site is Gallery or what if IP.Board is not even enabled for example?
Our solution was to extend the sidebar across all applications as shown below in IP.Downloads. 

You may notice from the screenshot that the announcements block is not specific to the downloads application. Any block can show in any application and they are configurable using moderator permissions. This immediately addresses the issue of content discovery.
While the sidebar is now global in 4.0, it is important to note that individual areas can enable and disable the sidebar if necessary.  Some areas of the suite simply require more room in order to display ideally, so the sidebar is disabled in these cases (e.g. the calendar "monthly" view needs a full page table grid to display in its ideal format). Further, you can configure sidebars differently for different areas of the suite in context-sensitive manner.  You may show a recent topics block in the IP.Board application, for instance, while showing a recent files block in IP.Downloads.  Or you can show both blocks in both areas - the choice is yours.
Many areas of the suite have specific things they wish to automatically show in the sidebar and will do so.  This is determined at a programmatic level and is not something that can be shut off.  For instance, in IP.Downloads the primary screenshot and the download button show in the sidebar, while in IP.Calendar a map and a button to download an event show.  Each application has the ability to output arbitrary content to the top of the sidebar where-ever necessary.
It is also worth noting that advertisements have the inherent ability to display in the sidebar site-wide as well.
Editing is carried out inline from the front-end, rather than the ACP, and can be customized based on the application, module or individual view. The technicalities of this are beyond the scope of this blog entry but what this means in practice is that you can vary what is shown in the sidebar for each individual area of your site. Ordering of the blocks is of course fully supported using a simple drag and drop interface, and some sidebars additionally have configuration options available to them as needed.
Here is a video demonstration of how editing the sidebar works in IPS Community Suite 4.0.

With this approach it was important that performance was not compromised and for that reason sidebar blocks support varying degrees of output caching. The active users block which must always be kept up to date utilizes no caching, a more general block showing overall statistics is cached for all users at once and other blocks that rely on permissions are cached for each user group combination. The level of caching used is determined by the developer when writing the block so, while it is important to mention that this performance aspect has been considered, it is something that is transparent to end users and admins in day to day use.
Community integration is a key strength of the IPS platform and the new sidebar in version 4 expands on this even further allowing you to share content across all areas effectively.
A while back , we casually mentioned in a blog entry that 4.0 would be next major version after 3.4. Development of 4.0 is underway and we're going to be using this new blog to talk about development as we go.

As Brandon mentioned  a couple of days ago - the format of these entries is going to be developer-specific. If what we're saying doesn't make much sense right now, we will still be putting announcements up in our main blog when they're finished and ready for everyone to see.

Because of that, it's also worth bearing in mind that everything is subject to change. I'm going to be posting code samples, screenshots and so forth - but everything in this blog is a work in progress - not the final product - and that will probably show.
With that out the way - let's talk about 4.0! :D
The file structure
Currently, applications are mostly self contained in their folders (which is either /admin/applications, /admin/applications_addon/ips or /admin/applications_addon/other) however, other files are dotted around in /interface, /public, etc. In 4.0, applications will be completely self-contained within a single /applications directory.
An application directory will look something like this: [*]extensions [*]dev [*]css [*]html [*]img [*]js [*]lang
[*]admin [*]front (it's "front" rather than "public" now)

You will notice the inclusion of a /dev folder. This will not actually be shipped in production, but rather replaces /cache/lang_cache/master_lang and so forth in the 3.x line.

Outside of the applications directory, there will be a "system" directory, which contains core framework classes.
Namespaces and autoloading
In 4.0, we'll be making use of PHP namespaces and using an autoloader. The best way to demonstrate how this works is with a few examples: [*] classDb  (/ips_kernel/classDb.php) is now IPSDb and located in /system/Db/Db.php [*] output (/admin/sources/classes/output/publicOutput.php) is now IPSOutput and located in /system/Output/Output.php [*] class_forums (/admin/applications/forums/sources/classes/forums/class_forums.php) is now IPSforumsForum and located in /applications/forums/sources/Forum/Forum.php [*] IPSDispatcherFront  and  IPSDispatcherAdmin  are two new classes (with similar functionality to  ipsController in 3.x) and both  extend  IPSDispatcherDispatcher - all 3 are located in /system/Dispatcher/ in individual files.
Better framework design
Where appropriate, classes are being refactored to make better use of appropriate design patterns. One lovely side-effect of this is ipsRegistry no longer exists.
Instead of, for example  ipsRegistry::DB() you now use  IPSDb::i() - the Db class uses a multiton design pattern (I didn't pass any arguments in that example, which doing will cause the Db class to load conf_global.php and create the default database connection, but I could have passed it a key) - the i method in this case will create the database connection if it doesn't already exist.
To give another example -  IPSMember  (the new IPSMember ) uses an Active Record pattern. So there's no more of this:
IPSMember::isInGroup( 1, 4 );
It's now, the much more logical:
IPSMember::load( 1 )->isInGroup( 4 );
Monkey patching hooks
One of the great things about the IPS Community Suite is hooks - you can easily create a class and instruct the framework to use that instead of a core class.
Now, I don't know about you, but I really, really, really hate having to do this:
$class = IPSLib::loadLibrary( '/path/to/file', 'myClass' );
$object = new $class;

Especially if what you want to call is a static method, in which case it can't be done. You want to of course, just be able to do:
$object = new myClass;
There is a concept in software engineering to do this sort of thing, called monkey patching , and by clever use of the autoloader, we've managed to make this work. loadLibary and loadActionOverloader are no more.
These points are of course, just the beginning of 4.0. Stay tuned for more :smile:



Hopefully most of you don't have the need to visit our bug tracker enough to have noticed, but we recently switched from a third party application for managing our bugs to IP.Content .

The history of the software we used to use for our bug tracker goes back quite a bit. It was originally written by Matt, many years ago - before that we used regular forum topics as bug reports!

A couple of years ago, around the time IP.Board 3.0 was released, we handed over the codebase to a group of volunteers who wanted to develop the bug tracker application further - and they did .

The developers have done a fantastic job with Tracker, however since then we've released IP.Content , our own application which lets you create (amongst other things) custom databases.

We decided that since moving forward it's definitely easier for us to be using our own applications (otherwise we have issues whenever we upgrade this site to beta software) especially as soon we'll be developing them all under one release cycle , and IP.Content is more than capable of handling the task, to switch from Tracker to IP.Content.

So what did we do to turn IP.Content into a fully featured bug tracker? Actually, nothing special!

IP.Content's databases already have support for categories (we created one for each product) and custom fields (we created fields for "status", "version" and "fixed in version"). We didn't need to do any skinning either - the default database templates work fantastic for a bug tracker. We also took this opportunity to have one of our non-technical members of staff create the database. This gave us some great ideas on improving the system for ease of use.

In fact, there was only 3 hurdles we had to overcome:

1. Filter Bars

When you're working through bug reports you only really want to see open bug reports - we needed a way to filter the records being shown created on the custom "status" field we'd created.

After thinking about the best approach for this, we realised that there's probably other uses for IP.Content which also might benefit from fields being "filterable". So we went ahead and added the feature to IP.Content .

When the next version of IP.Content is released, any enumerable field type (dropdowns, radio boxes, checkboxes) will be able to be selected as "filterable".

When viewing records you'll then see a sidebar allowing you to select one or more of those values to filter the records by.

This is what it looks like in our new bug tracker:

2. Quick Changing Fields

Unlike most database uses, in a bug tracker, you need to be able to change the record's data (status, fixed in version) quickly - and often at the same time as making a comment on the report.

We decided for this we'd need to write some code specifically for our needs. Fortunately, IP.Board's hook system makes this really easy.

In case anyone out there is feeling particularly geeky and wants to know how this works, the hook has 3 parts: [*]A skin overloader which adds dropdown boxes above the comment form [*]A data hook which intercepts the comment being added and updates the records data based on the dropdown box values. It also edits the comment that was posted and adds in "Updating Status to: X", or whatever was changed. [*]An action overloader which stops an error being thrown if the comment is empty.
In total, the hook is just 81 lines of code and took about 30 minutes to write.

3. Moving the data

Our final hurdle was converting the data (for which I whipped up a CLI script).

Naturally, we also had to make sure that old bug report links gave HTTP 301 redirects to the new reports - wouldn't want our SEO to suffer!

To do this, I just dropped a few lines of code in one of the old Tracker source files.

So here it is, our brand new bug tracker, completely powered by IP.Content.

Read more about IP.Content or try it for free .
If you have any questions about what IP.Content can do, shoot us an email - we'd love to hear from you.

If you like living on the edge and testing new products we would love your help in testing IPS Community Suite 4.0!
We now have pre-release versions available for download if you are an active Community Suite license holder.
Pre-Release vs. Beta
This is a pre-release which means we are not quite done adding/changing some areas of the Suite. It also means that you  cannot upgrade between each pre-release. Once we reach Beta stage you will be able to upgrade from Beta 1 to Beta 2 and so on.
Important Information [*]This is a preview of unfinished software. Do not install this on a live server or attempt to upgrade your current community. Please. [*]You cannot upgrade between pre-release builds so you will have do a clean install each time we update this package. This will change when we reach proper beta stage. [*] Only download this preview if you are comfortable testing software with known issues and want to provide bug reports and feedback. [*]We provide no support for these pre-release builds.
Please post any bugs you find in the  bug tracker  and feedback/questions on the  preview site . We are getting close to a public beta and the final, supported release of IPS Community Suite 4.0 and appreciate your help getting there!
Download Pre-Release Now
Note that Nexus, Content, and Chat are not yet available for download but will show up on our preview site soon.

One of the things we wanted to focus on for IPS Social Suite 4.0 right from the beginning was providing better support for sites which do not use English or use multiple languages (or, as it was scribbled on my whiteboard, "++ i18n/L19n"). In this blog entry I'm going to cover some of those changes and new features.
Translatable Everything
Currently when you create a forum, user group, custom profile field, etc. you have to give it a title and can only do this in one language. If you have more that one language installed, you might want to provide different titles for different languages.
In 4.0 you can do exactly that - if you have only one language installed, these fields will continue to show as normal text boxes - however, if you have more than one installed you'll see several text boxes like this:

Visual Language Editor
One feature that has been really popular in IP.Board is the Visual Skin Editor - a tool which allows you to browse your site, and click on elements to bring up a colour selector to change it. What if we could take this idea and apply it to translating as well? Allowing you to click on any word or phrase on your site and translate it there immediately. In 4.0, you can.
Easier Language Management
In addition to the visual translation we've also made several improvements to the traditional translation method: [*]As you search for a language string, results appear as you type. [*]Editing a language string saves immediately without needing to click a save button. [*]Filter tabs can show you words/phrases which have not yet been translated or the translation is out of date (meaning we've changed the default English value for the word/phrase since it was translated).
We've also made importing/exporting much faster and more reliable - no matter how large your language is (it will grow as you add more applications of course) there is now no risk of hitting an error importing/exporting (for those interested in the technical side of how this is achieved, see this blog entry ).
An exported language pack will also now maintain information on the version of each application it was exported from, so that the filter which shows outdated language strings is always accurate.
Automatic Language Detection
Let's say you have Spanish and French languages installed on your site - up until now, you'd have to choose one default language, and users who want the other would have to manually choose it (which can be extremely difficult to find how to do when you're browsing a site in a foreign language).
In 4.0, we automatically examine the information that the user's browser sends (which includes their preferred language) to choose the best one out of what's available, if that user hasn't already set an explicit preference.
In English, pluralisation is very simple - for most nouns, you just append "s" on the end, with some variation for certain words.
This however, isn't the case in all languages - for example, I was speaking with the owner of a site in Slovak recently who was telling me that the word "records" changes depending on the number of records there are - for 2 records, it's "2 články", but for 5 records it's "5  člán kov". Currently, most language strings only have a singular and plural form (as is all that's needed in English) - meaning having the site show "2 články"/"5  člán kov" was impossible.
In 4.0, we've introduced some really basic logic into language strings to accommodate this. Rather than having, for example, two language strings with the singular and the plural, there is now one with a value like this:
The # indicates where the number will go, then each set of square brackets represents a possible value - the number before the : indicating the number which will cause that to show, and ? meaning "all other numbers".
So for our Slovak example, we'd set the value to:
On display, it will automatically show the appropriate version.
Along a similar thread to pluralisation, we've also made the way lists are formatted to be customised through a special language string. For example, a list in English looks like "one, two and three". However, in Japanese, it's "一、二、三。" (the comma symbol is different and there's no "and") - similarly Arabic, Thai and others have similar differences. In 4.0, simply by changing an example language string, this can be changed.
In the default language, this language string is:
For our Japanese example, we'd just change it to:
Without wanting to get into too much technical detail - UTF-8 is the most common of many ways text can be encoded for storage and display on webpages. UTF-8 has been the default encoding in our software since IP.Board 3.0.
Some sites which have been around for a long while though may not be using UTF-8. This can cause issues with some features where UTF-8 encoding is expected (for example, many features which rely on JavaScript require UTF-8 due to JSON only supporting it and nothing else). In addition, some sites may try to use UTF-8, but content is actually stored differently as the database is set to a different encoding, which can also cause issues.
In 4.0, we're going all UTF-8. If you're not already on it, the upgrader will convert data. This means a much more reliable and compatible way of handling text.

{# [1:record][?:records]} {# [1:článok][5:článkov][?:články]} a, b and c a、b、c
Please note that this entry may be a little technical, if you do have any questions, please post them in the comments below.
A little history
IP.Board was first released over ten years ago when the web landscape was very different. A lot of emerging technologies were still trying to define new standards. Very early versions of IP.Board allowed one to specify the document character set and had a default of "ISO-8559-1" which is useful for languages that use latin based characters. This meant, for example, that if you needed Chinese characters you would need to change the character set to something more suitable. This disparity between character sets creates many challenges when working with a single code base.
Over the past handful of years there has been a push towards a single document character set; UTF-8. UTF-8 is a variable-width encoding that is able to show every character in the Unicode character set. This makes it suitable for latin and Chinese characters (and many many more!). Popular Javascript libraries such as jQuery require that data is sent and received with UTF-8 and many native PHP string functions prefer UTF-8. The future is very much UTF-8 and trying to keep our codebase working with any other character set is going to be more and more challenging.
IPS 4.0
Even though IP.Board 3 introduced UTF-8 as the default character set for new installations, we're aware that we still have many clients that are not using UTF-8 currently. IPS 4.0 is going to be strictly UTF-8 only which means we need to convert the data before or as part of the upgrade process.
Converting to UTF-8 isn't as simple as changing the database encoding. Merely doing this will simply corrupt the data you have in your database. We need to be a little smarter and use a script to do this work for us.
The great news is that even if you choose to convert your data to UTF-8 today, your IP.Board 3.x will run just fine and you may even find it more efficient as it doesn't have to convert lots of data on the fly.
The IPS UTF-8 Database Converter
We've written a script that can safely convert your database to UTF-8. The script does not overwrite your data until you manually confirm that the conversion process has been successful. This means that there is no risk of corrupting your existing data.
Of course, it is good practice to perform a full MySQL back-up before making any changes to the database as a precaution and we recommend that you do this.
You can download the converter and its instructions here .
How can I tell if I need to convert my database?
When you first run the converter, it'll check your database and let you know if you need to convert or not. Even if you are running UTF-8, you may not be using the correct collation (utf8_unicode_ci) so you have the option of changing your collation which is a very fast procedure and does not need a full conversion to complete.
If you first used IP.Board with IP.Board 3.0 then you may only need to change your database table collation. This isn't a required step and the IPS 4 upgrade process will perform this task if you'd prefer to wait until IPS 4.0 is released.
Please note that while we're happy to provide some pointers within the client forums, this release is not officially supported by our technical support department.
Beta Release
As this is a beta release, please be aware that there may be bugs. If you do spot one, please post it to the  IPS Extras bug tracker .
Profiles are one of the key sections of a community, as everyone knows. They are what represent your users; where their information is shown and their content is gathered. When users contribute quality content to your community, their profile is where other users go to find it in one place. In short, it's an important area.
In IPS4, profiles have had a complete makeover. There's a lot to cover, so I'll start with a numbered screenshot, and address each section individually (please note this is a large image; if you're on mobile, you may wish to wait to view it full-size).

1 - Header images
In 3.x, users could customize their profiles by uploading a background image. In practice, this didn't work well when the software was integrated into an existing website design, and the options presented often ended up with a garish profile. In addition, social networks like Facebook and Twitter have adjusted user expectations on how profiles are customized.
In IPS4, instead of page backgrounds, users instead get to customize their profile header image. This provides the best of both worlds - ample space to choose something creative, but it's contained and won't mess up a website design.
2 - Reputation
The user's current reputation count is shown prominently in the info column, letting other users know if this member is an asset to the community.
3 - Warnings
For moderators/staff, the profile now provides quick access to warning tools. By expanding the panel, they can see a brief history of recent warnings:

And clicking one of these pops up the warning details:

New warnings can also be issued inline, of course.
4 - Followers
Followers replace friends in IPS4, and the user's followers are shown in this block. Instead of requiring mutual acknowledgement as with the traditional friends system (an approach that isn't entirely useful in a community of anonymous users), in IPS4 you follow users whom you find interesting in order to be updated when they contribute to the community. Users can of course prevent others from following them, if that is a concern to them. We'll have more details on how followers works in a later entry.
5 - About the user
Traditional information about the user is shown in the next block, including custom profile fields.
6 - Recent visitors
Recent visitors to this user's profile are shown next. As with 3.x, this can be toggled on and off by the profile owner. In 4.x, this is done by clicking the X in the corner of the block.
7 - Follow/Message member
These primary buttons enable others to follow the user (if enabled), and send a new message inline, without leaving the page.
8 - User's content
In 3.x, browsing a user's content was handled by the search area of the community (though links were available in the user's profile and hovercard). We felt this wasn't the best place for it, though. After all, a user's content should be available in their profile.
That's what this button does. It switches the profile view to 'content browsing' mode, where you can see  everything the user has done. It's smooth and buttery, and because it all loads dynamically, it feels like a true part of the profile. Here's a video of it in action (14MB)

9 - Long-form custom profile fields
IPS4 supports various kinds of custom profile fields, including rich-text editors for long, styled content. Those custom profile fields will be shown in the main section of the profile where they get the space they need to be effective. About Me is a default field, but you can of course add your own too for your users to fill in.
10 - User's 'Nodes'
A node is a fancy developer term for content containers that a user creates themselves, like gallery albums and blogs (as opposed to forum categories, which are created by the admin). In IPS4, a user's 'nodes' are shown right on their profile page, making it easy to find more interesting content from the user. In this screenshot, you can see my profile is showing my albums, my blogs, and other blogs to which I contribute.
For developers, supporting your application in this section is easy too.
11 - Status feed
The status feed from 3.x is of course still present, and the interaction is all inline without leaving the page.
That's profiles in 4.0. We hope the new focus on content and streamlined design provides a better experience for your users!
As always, screenshots are from pre-release software and are subject to change before release. 
The IPS Community Suite 4.0 preview site is open and ready for you to start browsing our new software!
We have had the site quietly open for a few weeks now getting feedback and addressing issues. We want to make sure everyone is aware so you get a chance to look at what's new.
Register and have a look around at what's new. Read our updates forum to check out videos demoing the system. Get involved in feedback and bug testing. Everyone at IPS is very proud of 4.0 and really hope you enjoy it. Public beta releases of 4.0 are not yet available but are just around the corner so take this opportunity to become familiar with IPS 4.0 so your community is ready when it's released.
See you on the preview site!
Please keep all feedback about 4.0 on the preview site so we can keep things organized. Thanks!
Effective moderation features are essential for online communities. Forums, blog entries and member-to-member messaging are particularly attractive for spam bots and nuisance users alike. IPS Social Suite has always been best in class when it comes to moderation features with features like the free IPS Spam Service that are completely unmatched by other web applications. Over this series of 5 blog entries I'm going to introduce you to some of the new moderation features in the IPS Community Suite 4.0.
Part 1: Setting up moderators
Part 2: Approval Queue
Part 3: Reports
Part 4: Effective Moderation
Part 5: Warnings

A lot of what I'm going to cover in this blog entry is similar to the warning system in 3.x which was recently overhauled. Since warnings and moderations are such an important aspect of running a community though, I wanted to reintroduce the system, showing off the new UI for 4.0 and highlighting some of the tweaks that have been made.
The warnings system in the IPS Community Suite is point-based. When issuing a warning to a member, you select a reason , and each reason is tied to a number of points, and then when a member reaches a certain number of points, an  action (such as to ban them from the site) is taken.
This is the setup page for reasons - I've set up each one to give one point which is never removed.

For each reason, I can choose if moderators can override that or not:

This is the setup page for actions:

I've set up a number of actions so that the following flow happens: [*]On the first warning, nothing happens (it's a verbal warning only) [*]On the second warning, all posts the user makes for the next day will need to be approved by a moderator. [*]On the third warning, the user will be banned for one day and all posts the user makes for the next week will need to be approved by a moderator. [*]On the fourth warning, the user will be banned for a week. [*]On the fifth warning, the user will be permanently banned.   You can control whether members can see their previous warnings or not.     Moderator Permissions   For each moderator you can control is they can see, issue and revoke warnings, and control how often they can give warnings:       Viewing Warnings   You will be able to see the current warning points for a member from their hover card (which shows whenever you hover your mouse over their name throughout the suite) and can see the details in their profile.       Clicking on a warning brings up the details which show a link to the content the user posted which prompted the warning, the notes both for the member and for other moderators, and lists the actions taken (points given, if the member was suspended, etc.):     In addition, when viewing content (posts, comments, etc.) if that post prompted a warning, this will be shown to moderators:       Issuing Warnings   When issuing a warning, selecting a reason will automatically fill in the number of points and actions to take based on the number of points the member already has (these can be changed if the administrator has allowed it). You can clearly see the pre-defined actions for each point level on the right. You can optionally add notes, both a note for the member and for other moderators.       Acknowledging Warnings   You can optionally set the system so that members have to acknowledge a warning before they can post again. When this is the case, the member will se a message on every page:     Viewing the warning details will have a button allowing the member to acknowledge the warning:     Even if you do not require warnings to be specifically acknowledged - members who have restrictions applied to their account (are on moderator queue, are restricted from posting or are banned) can clearly see this and the reason why. For example, this is what a member who is on moderator queue sees when making a comment:     Revoking Warnings   A new feature in 4.0 is that warnings can be revoked. You can reverse all the actions of the warning, or just delete the record of it:  

In the last blog entry  I introduced some of the features in the post editor in IPS Social Suite 4.0. In this blog entry I'd like to show you the uploading features in the editor.
Using the "Image" and "Attachment" dialogs
Along the bottom of the editor there are two buttons that deal with uploading files: image and attachments. Both present a dialog which looks like this:

We decided to keep both an images and an attachments dialog as users wanting to insert an image will naturally look for the "Image" button - if however, you upload an image to the attachments dialog, it will work completely as expected.

The upload panel here is based on HTML5 which supports drag and drop uploading, if your browser doesn't support this, it will use Flash, Silverlight or Google Gears if you have any of those installed, and if not it will fallback to a HTML4 & JavaScript implementation (none of these support drag and drop, but instead you click the "Choose Files" button just as you do now - the label in the box will change to reflect this).
Uploaded files then show below the box (images will get a preview), and you can click on any to add them into the editor, or click the "Insert All" button. When you insert an attachment into the editor, it displays either the image if it's an image, or a link if it's anything else, just as it will actually appear in the post (rather than the current "[attach=XXX]" tag).
You can also of course delete the attachment, which will automatically remove it from the editor if you've already inserted it.
Video Demonstration
Quick drag-and-drop
In addition to interacting with the panels, if you're using a supported browser, you can drag and drop straight into the editor. It will automatically figure out whether the uploaded file(s) are images or other files and add them to the appropriate panel automatically.
Video Demonstration
Image URLs
In the image panel, there is an additional "From URL" tab which allows you to insert an image from a URL, as you type the URL a preview is shown, and you can optionally link to the image.
Video Demonstration
My Files
In IP.Board currently, there is a "My Media" button which allows you to insert content submitted either in other posts or elsewhere in the community (images in IP.Gallery or files in IP.Downloads for example) into the editor. In 4.0, this feature is found in the images and attachments dialogs.
Just with normal attachments, the content is inserted as it will be shown rather than the current "[sharedmedia=XXX]" tag.
Please let us know what you think of the uploading features in the comments. Remember though that we're only half way through our series on the 4.0 editor. In my next blog entry I'll be talking about customising the editor and the place of BBCode. 

By Mark,

Modifications, add-ons, plugins, hooks - whatever your preferred name for them is - 3rd party code modifications are an important part of any successful web application. It wasn't that long ago that the way you did this was manually opening up files and copying and pasting bits of code in, or the really cool web applications had points scattered throughout the code for modifications to be injected into, or even scripts which opened up the files and made the changes for you (I'm not joking, that's seriously what used to go on!). In fact, IP.Board was one of the first web applications to, using OOP, support modifications in a more structured way.
Currently, we largely have 2 types of modifications: applications , which add whole new areas and functionality to your site (all of our applications: IP.Blog, IP.Gallery, IP.Downloads, IP.Chat, IP.Content and IP.Nexus use this architecture) and  hooks which modify or extend the functionality of the IPS Social Suite or of applications.
Applications themselves are sort of self-governing so there isn't much to say about them, with one exception: applications will now be able to be downloaded and subsequently installed into your Admin CP as one file - you will not have to FTP upload application source files. The file will just be a regular .tar file, so course, if you were so inclined, you could open it and go old skool.
For the rest of this blog entry, I'm going to focus on hooks. Though parts of this blog entry will be more technical in nature than our others, I've tried to keep it just to what everyone will be interested in, and leave the boring stuff until the end.
The term "hook" in 3.x is ambiguous. Sometimes it refers to the whole thing (e.g. "install a hook") and sometimes it refers to a specific technical part of that - the code which overloads other code (e.g. "skin hook", "library hook"), which are, even more confusingly, sometimes called "hook files".
In 4.0, we've decided to rename hooks to  plugins . The technical parts which make up a plugin will still be referred to as hooks.
Plugins, by their nature, extend functionality already present on your site. Up until now, if a plugin experiences a problem (for example, if a new version is installed which the plugin doesn't support) it can cause an error on your site, which disabling the plugin fixes.
Starting in 4.0, plugins will be sandboxed. This means that if a plugin experiences an unexpected error (such as a database driver error), your site will automatically fallback to the default behaviour, and your users will never know anything went wrong.
Simple (yet advanced) settings
In IP.Board 3.x, the Admin CP maintained a massive central area for managing most (though not all) settings. Plugins could add settings to this area, though there was no real standard to where to do that. Also, because this area was separate from the area where you install plugins, it could sometimes be confusing how to configure a plugin after installing it.
In 4.0, each plugin is allocated a settings page which is accessed just by hitting the "Edit" button on the list of plugins. Plugin authors can manage this page how they like - rather than being confined to the strictly tabular layout and specific input types in 3.x.
In 3.x, unlike with applications, there was no particularly clear way to upgrade a plugin from one version to another. In 4.x, plugins now support full versioning, so you can just upload a new version, and an upgrader will take care of it.
Hook Types
In 3.x, there were several different underlying types of hooks: [*]Action overloaders - which allowed overloading the PHP class for any controller. [*]Library hooks - which allowed overloading the PHP class for some (though not all) other classes. [*]Data hooks - which allowed the modification of variables at specific, defined places in the code. [*]Skin overloaders - which allowed overloading the compiled PHP class representing a group of templates. [*]Template hooks - which allowed content to be inserted at specific points in templates.
For 4.0, we've made some quite radical changes:
Code Hooks
The first 3 have been merged into one concept we call "Code Hooks". Code Hooks can overload  any  class (even things which presently can't be overloaded like extensions) through a technique called monkey-patching ( more details have been mentioned in the developer channel ). This, combined with the use of Active Record models for all content items (so "Topic", etc. is a class that can be overloaded) also makes data hooks obsolete.
Theme Hooks
The last 2 have also been merged into a concept called "Theme Hooks" (we're also renaming "skin" to "theme"). The way the current template hooks work is to insert content around certain pre-defined tags in the template. The problem is, not always is the point the plugin author needs available, also this is done in a way the content being inserted isn't aware of it's surroundings, which makes it difficult for things like adding a button to every post, which would need to know information about that post.
After thinking for ages about a better way to facilitate theme hooks (I was halfway through a system which injected hook points automatically at compile time), our designer Rikki reminded us that a pretty well-known method for selecting HTML elements already exists... CSS selectors.
Video demonstration
What's really cool about this is that the content used acts as if it was part of the template - if for example, it's inserted in a foreach loop, the variables created by that are available. It can also use template logic and everything else templates themselves can do.
On the back-end, these are compiled into a file which behaves like a 3.x skin overloader - so if it is necessary (or just desired) to overload the compiled version of the template, that is still possible.
Theme hooks work for the Admin CP as well as the front-end.
Developer information
Developers no doubt would like to know the technical information of how this all works. Rather than write a blog entry covering all the different parts of plugins, we thought you might be interested to just see the developer documentation. We have 2 articles we can show you - one covering all the technical details of plugins , and another which provides a step-by-step guide for how to create a plugin .

Reminder: this blog covers the technical details of 4.0's programming. For details on 4.0's features, follow our main blog .
For almost all applications in the IPS Social Suite (IP.Chat being the notable exception), there are three components: [*]Categories created by the administrator. For example, forums in IP.Board, categories in IP.Downloads, calendars in IP.Calendar). In 4.0, the terminology used throughout the code for these is "Nodes". [*]Content created by users, usually (though, not always) within categories. For example, topics in IP.Board, files in IP.Downloads, events in IP.Calendar, images in IP.Gallery, personal conversations). In 4.0, the terminology used throughout the code for these is "Content Items". [*]Comments posted on Content Items by other users. In most applications these are simply called "comments" though in IP.Board they are called "posts" and in IP.Nexus and IP.Downloads they take the form of reviews.   Each of these different types of items share many common features. For example, in all applications you can "follow" nodes and Content Items, you can like (or give reputation on) Content Items and comments. There's also searching, tagging, moderator controls (pinning, locking, etc.), sharing, reports and so on.   Up until now, applications were largely in charge of managing these different components and their relationships themselves, and utilised often complicated  extensions  to implement the common features.     In 4.0, these components are handled differently. Each component follows an Active Record design pattern , extending a central class for the component, and implementing interfaces to enable additional features.     Working with objects   So, taking IP.Board as an example, the classes for each of the components (forums, topics and posts) will start off like this: In an earlier blog entry , I already talked about how Nodes work and showed how easy it is to start using them. Content Items and comments are the same, with very little additional programming (only specifying a few properties to specify what database table to use and the names of the other classes they relate to), we can start using them.   For example, to get a topic from the database, I just do: In this example, 1 is the ID number. If I was accepting user input, I could just wrap it in a try/catch statement. I could also, rather than using load() use an alternative factory method, loadAndCheckPerms(), which automatically checks if the currently logged in user has permission to view and throws an exception if not: In the object, properties match the columns from the database table. For example, to set the page title to the topic title, I just do: There's also lots of methods available. For example, to get the IPSforumsForum object of the forum the topic belongs to, I just do: Or to get the IPSMember object of the member that posted the topic, I just do: An Example:  Getting the latest 5 topics   One thing which is particularly easier now is that now the central classes handle common functionality, you can easily obtain data without having to worry about if everything has been accommodated - the class handles it automatically. I already showed how loadAndCheckPerms() works - for a more complicated example, let's say you wanted to get the 5 most recent topics to display in the sidebar. Previously you'd have to do a query, joining on the permissions table, providing the permission mask IDs of the current user manually, remembering to check to exclude hidden topics (unless of course, the user had permission to view hidden topics).   In 3.x, it would have looked something like this: In 4.0, the same thing can be done with just one line of code: Naturally, one could have written a method to do this in 3.x, but in 4.0, because it is handled centrally, it is common to all applications. If a new feature is added which affects the functionality (such as when hiding content was added), each application does not have to be updated.     Adding Features   I already mentioned how there are certain features, like tagging, reputation, searching, etc. which are common to Nodes and Content Items throughout all applications. In 3.x, integrating these features involved writing a usually lengthy, extension. In 4.x, implementing most of these features is as simple as adding a few elements to your class.   For example, let's take tagging. In 3.x, we have lengthy  developer documentation for implementing tagging . It involves creating an extension, which in the IP.Board application totals 360 lines of code.   In 4.x, you simply add an interface to your class - changing this: Into this: That's all there is to it. Having done that, the form where a user adds or edits a topic will immediately gain a tags input field (the elements included on the form is handled centrally) and I can now call an additional method to get the tags on any topic so that I can display them in the HTML: Here is a screenshot of the full developer documentation for tagging in 4.x:     The programming method employed here is actually more suited to traits, as implementing the interface does not involve adding any additional code to your class. The reason we've chosen to do it this way though is because traits are only a feature in PHP 5.4 and above, and we wanted to support PHP 5.3. It is likely that in a future version of IPS Social Suite we will switch to using traits.     Other examples   Reporting   In 3.x:  http://www.invisionpower.com/support/guides/_/advanced-and-developers/application/application-extension-reportplugins-r100  - 502 lines for IP.Board.   In 4.0:       Read Markers (shows if content has been read or not)   In 3.x:  http://www.invisionpower.com/support/guides/_/advanced-and-developers/application/item-marking-r211 - 146 lines for IP.Board, plus manually marking items as read.   In 4.0:       Liking / Reputation   In 3.x:  http://www.invisionpower.com/support/guides/_/advanced-and-developers/application/application-extension-reputationphp-r101 - 222 lines for IP.Board.   In 4.0:       Following   In 3.x:  http://www.invisionpower.com/support/guides/_/advanced-and-developers/application/application-extension-like-r69 - 357 lines for forums, plus 361 lines for topics in IP.Board.   In 4.0:   For content items:     For comments:  

namespace IPSforums; class Forum extends IPSNodeModel { ... } class Topic extends IPSContentItem { ... } class Post extends IPSContentComment { ... } $topic = IPSforumsTopic::load( 1 ); try { $topic = IPSforumsTopic::loadAndCheckPerms( IPSRequest::i()->id ); } catch ( IPSContentNoPermissionException $e ) { IPSOutput::i()->error( "You do not have permission to view that topic.", 1, 403 ); } catch ( OutOfRangeException $e ) { IPSOutput::i()->error( "Could not find topic. It may have been deleted.", 2, 404 ); } IPSOutput::i()->title = $topic->title; $forum = $topic->container(); $author = $topic->author(); $member = ipsRegistry::instance()->member()->fetchMemberData(); $topics = ipsRegistry::DB()->buildAndFetchAll( array( 'select' => '*', 'from' => array( 'topics' => 't' ), 'where' => ipsRegistry::getClass('class_public_permissions')->buildPermQuery( 'p', 'perm_2' ) . ( !$member['g_is_supmod'] ? ' AND queued=0' : '' ), 'add_join' => array( array( 'select' => 'p.*', 'from' => array( 'permission_index' => 'p' ), 'where' => 'p.perm_app="forums" AND p.perm_type="forum" AND p.perm_type_id=t.forum_id', 'type' => 'left', ) ) ) ); $topics = IPSforumsTopic::getItemsWithPermission( NULL, 'start_date DESC', 5 ); class Topic extends IPSContentItem { ... } class Topic extends IPSContentItem implements IPSContentTags { ... } $tags = $topic->tags();