Jump to content

Matt

Management
  • Posts

    69,387
  • Joined

  • Last visited

  • Days Won

    551

 Content Type 

Downloads

Release Notes

IPS4 Guides

IPS4 Developer Documentation

Invision Community Blog

Development Blog

Deprecation Tracker

Providers Directory

Forums

Events

Store

Gallery

Everything posted by Matt

  1. Thank you for you compliment. We're happy to allow all current license holders with download access have IP.Board 3 at no extra cost. I'm sure that if our accountants ran the numbers, they'd tell us to reconsider. We promised that there would be no extra charge for the upgrade to 3 and we'll stick by that. :)
  2. Meanies! It used Ajax. And Ajax was cool. We were the first to use it on a bulletin board and that was the best I could do. :(
  3. It's a bit of a limitation, I believe that the text editor needs focus to complete setting up design mode.
  4. Hey! I worked really really hard on that!!
  5. Oh dear.. are we doing this again?
  6. It would be pointless to release RC1 if we still have stuff to fix. RC 1 is when we consider it 'done'.
  7. You can restrict the number of characters allowed in the topic title in your ACP settings. We've left ours deliberately long.
  8. Thanks guys, go nuts and test it out as much as you can. Please don't be alarmed if we seem to take a minor step back with some stuff, I've fiddled with a few things, mostly: Topic MarkingCSS CachingMemory DebuggingSo let me know if you see anything odd with any of that.
  9. You won't need too. Our DB is not UTF-8 and we're using them just fine.
  10. Just a note: I've added back the basic character conversion tables which only take up about 200k space, uncompressed. I will write a function to check your character set and test for local conversion methods before checking if you need to download more tables.
  11. Matt

    IPB3 Beta 4

    I have turned off JSDebug in the templates. Let us know if this fixes the issue. :)
  12. Matt

    IPB3 Beta 4

    I was going to ask that too.
  13. Matt

    IPB3 Beta 4

    I am using FF 3.1 beta 3 and I can reproduce the edit bug, so I'll file a bug which was all that was needed in the first place. It seems that the ajax function isn't being fired for some reason. As we use prototype heavily, I'll check there first as there may be a bug with Prototype or change required.
  14. Matt

    IPB3 Beta 4

    I chose not to comment on the comparison between us and Mozilla because it's like comparing apples to fish.
  15. Matt

    IPB3 Beta 4

    Isn't a little premature to dump all your past purchases on the strength of a beta release of a future version not working with cutting edge alpha / beta versions of web browsers? The current version (2.3.6) is very stable and that's the supported version. We know that IP.Board 3.0.0 Beta has issues; that's the very reason we ask you to test it. We would not ask you to test it if you were going to make a decision whether to continue using IPS products on the strength of it. Now, does the edit button work for you in FF 3.0.7? Forget 3.1 Beta 3.5 beta, etc - just use the current stable FF release and let us know. If it does not, then file a bug report. That's all we ask. Lee, Sunrise was telling you that the option to include the full reply in a topic subscription notification has been in IP.Board for years, since 2.1 if I remember correctly. This feature is also in IP.Board 3.0.0 so there is no need for a mod, etc.
  16. Since we unveiled the new friendly url feature on our preview board, we have received a lot of feedback on how it could be improved with regards to maintaining good search engine optimization (SEO). Every feature we add has to be weighed against the impact to efficiency and memory usage. We understand that not every customer has the luxury of a dedicated server. We want to ensure the very best experience for a wide variety of hosting environments. However, in this case we felt we could make some improvements to the friendly url feature without compromising efficiency. The new settings can add some small overhead, but we felt that those who wanted the very best optimized content would accept that. Meta Tags I have added a way to add meta tags to the final content through: $this->registry->output->addMetaTag( 'name', 'content' ); This is used internally to add a meta tag for 'indentifier-url' and 'description'. The description is the first post of a topic; a forum description or the user's "About Me" information using the signature if no "About Me" information is present. You can use this interface in your own code to add more tags if desired. Robots.txt A primary concern for those interested in SEO is duplicate content. There are many ways to access a single topic due to the different variables that are used; pagination and search strings are a few examples. To help limit the duplicate pages indexed, IP.Board now ships with an example "robots.txt" file for you to edit and upload to your root directory. Redirecting 'old style' links Another concern was that the old style links, for example: index.php?showtopic=10, are still able to access pages. This is necessary so that you do not lose bookmarks or traffic from currently indexed links. You can now choose to redirect with an optional "301 Moved Permanently" header to the new link format. This is transparent to the end user but will help search engines locate the correct copy of your content. Incorrect Permalink Handling The new friendly URLs are often based on user generated content. For example, a topic called "My Great Topic" will have the permalink "/topic/10/my-great-topic/". Now, when this topic title is edited, the permalink will change too. For this reason IP.Board allowed access to the topic as long as the topic ID was present, so all of the following links resulted in the same topic being shown: /topic/10/my-great-topic/ /topic/10/my-edited-topic-title/ /topic/10/ /topic/10/i-just-made-this-up/ The downside to this is that some may consider this duplicate content. You can now opt to redirect with a "301 Moved Permanently" header to the correct permalink. This again is transparent to the end user but it will help search engines locate the correct copy to index. You can also opt for IP.Board to simply add a 'robots' meta tag with the value 'noindex' if you do not wish to redirect. This will tell the search engine to not index that URL. We hope that these improvements will be seen as a good first step in basic SEO without impacting performance.
  17. Matt

    Member Map for 3.0?

    I can categorically state that this will not be making an appearance in IP.Board 3.0.0.
  18. Since IP.Board 2, we've had a "kernel" of classes which IP.Board uses but do not depend on IP.Board to use. A selection of these kernel classes includes DB management, file uploads, emailing, RSS parsing and reading, XML parsing and reading and our proprietry archive format XMLArchive. For example, you could use "classUpload.php" and "classImage.php" in your own modifications or extensions to handle uploads and GD thumbnail generation. You would not have to initialize the registry or do anything else other than just include the file and use it. As we took the plunge and went ahead with making PHP 5 a requirement, we were able to make some long-awaited improvements. Here are the high-lights. Custom Fields Josh has completely re-written custom field handling within IP.Board and this class ties it altogether. Josh uses just about every PHP 5 trick in the book including abstract classes, interfaces and ArrayAccess to provide a simple clean interface that can be used in almost any project. It doesn't have to be limited to just IP.Board's custom profile fields. Graphing Remco has extended this class to include many new graph types including "funnel", "bubble" and "radar" graphs so that presenting data is more relevant. As IP.Board 3.0.0 develops, we'll be making good use of these new methods for statistic reporting within the ACP. GD and ImageMagick Brandon virtually started from scratch with our GD image creation. He also wrote a class for imagemagick offering more choice for those who have it installed. It's now very simple to resize an image or add a watermark. $image->init( array( 'image_path' => "/path/to/images/", 'image_file' => "image_filename.jpg" ) ); //Set max width and height $image->resizeImage( 600, 480 ); // Add a watermark $image->addWatermark( "/path/to/watermark/trans.png" ); $image->displayImage(); $image = new classImageGd(); XML Parsing and Creating We've had a class for XML parsing and creating since IP.Board 2 but it was a kludge of PHPs then primative XML handling extension and a hand-rolled class for when the XML engine wasn't available. These methods functioned well but were known to be memory intensive. Thankfully, PHP 5 has much better native XML handling which I took full advantage of when rewriting this class. I looked at simpleXML intially but found it too, well, simple for our needs so I went ahead and used the full DOM methods. This gives us full control over both reading and creating XML documents. Here's how simple it is to create a new XML document: $xml->newXMLDocument(); /* Create a root element */ $xml->addElement( 'productlist', '', array( 'name' => 'myname', 'version' => '1.0' ) ); /* Add a child.... */ $xml->addElement( 'productgroup', 'productlist', array( 'name' => 'thisgroup' ) ); $xml->addElementAsRecord( 'productgroup', array( 'product', array( 'id' => '1.0' ) ), array( 'description' => array( 'This is a description' ), 'title' => array( 'Baked Beans' ), 'room' => array( '103', array( 'store' => 1 ) ) ) ); $xml->addElementAsRecord( 'productgroup', array( 'product', array( 'id' => '2.0' ) ), array( 'description' => array( 'This is another description' ), 'title' => array( 'Green Beans' ), 'room' => array( '104', array( 'store' => 2 ) ) ) ); $xmlData = $xml->fetchDocument(); $xml = new classXML( 'utf-8' ); This will produce this document: <productgroup name="thisgroup"> <product id="1.0"> <description>This is a description</description> <title>Baked Beans</title> <room store="1">103</room> </product> <product id="2.0"> <description>This is another description</description> <title>Green Beans</title> <room store="2">104</room> </product> </productgroup> </productlist> <productlist name="myname" version="1.0"> This is how you'd parse that document: /* Grabbing specific data values from all 'products'... */ foreach( $xml->fetchElements('product') as $products ) { print $xml->fetchItem( $products, 'title' ) . "\"; } /* Prints: */ Baked Beans Green Beans $xml->loadXML( $xmlData ); I'm sure you can appreciate how simple it is to use these new XML features! XMLArchive I created our XMLArchive format for IP.Board as a way of combining several files into one without using tar or zip which can be troublesome on some servers. XMLArchive is very simply file data in a basic XML format. I rewrote the class to make it easier to use and to add more functionality. Here's how to read an archive: $archive->read( "/path/to/archive.xml" ); print $archive['someDir/file.html']; $archive = new classXMLArchive(); As you can see, we use PHPs ArrayAccess to transparently allow access to the contents of the fileset from the main class handle. Here's how to create an archive: $archive->add( "someDir" ); $archive->add( "anotherDir/anotherFile.html" ); $archive->add( "Create a new file from scratch!", "anotherDir/brandNewFile.html" ); # Save gzipped $archive->saveGZIP( "/path/to/archive.xml.gzip" ); # Save normally $archive->save( "/path/to/archive.xml" ); # Just return the data $archive->getArchiveContents(); $archive = new classXMLArchive(); For simplicity's sake, there is now just one interface to add files: "add()". Personally, the fewer function names to remember the better! Naturally, this blog entry does not cover all the changes and improvements within the kernel classes but it does go some way to showing just how much energy we've invested in ensuring that IP.Board is as robust and efficient as it can be.
  19. Brandon blogged a while back about IP.Board's integration points. I wanted to spend a moment discussing the features within IP.Board 3 that all you integrate the board with your website and to create your own network. Member Management Since IP.Board 2, we've had, what we call, "Log In Modules". This is basically a mini-framework to allow custom code to be used easily when authenticating and registering members. For example, if you had a database full of members and you wanted for them to be able to use their existing usernames and passwords, you could add a log in module to query your database or other system (via SOAP, XML-RPC, etc) for authentication. This system has been enhanced based on user feedback and IP.Board now ships with modules for LDAP and OpenID which will make it much easier to use existing authentication. Networking The log in modules also tie into our 'IP.Converge' product which allows you to share authentication details across multiple IP.Board installations. The IP.Boards don't even need to be on the same server! In fact, we use Converge and the log in modules ourselves so that our customers can use the same log in details on the forum as they do in our ticket center. You could use this functionality to share members across many forums, creating a true network of members. Using the IP.Board Engine We've made no secret that IP.Board 3 is a complete rewrite. The new framework makes full use of PHP 5 and incorporates many timesaving features that you can instantly make use of. It's common for our customers to ask how they can use certain parts of IP.Board within their own website. For example, they'd like to show a list of recent topics or posts. That's no problem as we've had an API class interface since IP.Board 2. However, if you wanted to send data to IP.Board, such as a new post or new personal message; things got tricky. Even using a template bit required a lot of code copying. For example, if you wanted to make use of our database engine or templating engine, you would need to copy a lot of 'index.php' so that it set up ipsclass correctly. With IP.Board 3, that is no longer required. You can use our engine in your own scripts as simply as this: require_once( IPS_ROOT_PATH . 'sources/base/ipsRegistry.php' ); $registry = ipsRegistry::instance(); $registry->init(); require_once( './initdata.php' ); Those few lines of code give you access to: Caches, settings, member management, database management and more. Writing your own code Quite often, you want to add some IP.Board functionality to your own website. With IP.Board 3.0.0 it's very simple. You want to add a new post? No problem, simply use that code above and add: $postClass = new classPostForms( $registry ); $postClass->setForumID( $forumID ); $postClass->setForumData( $this->registry->class_forums->forum_by_id[ $forumID ] ); $postClass->setTopicTitle( "My Topic" ) $postClass->setPostContent( "Hello, I am post content!" ); $postClass->setAuthor( $memberID ); try { $postClass->addTopic(); } catch( Exception $error ) { print $error->getMessage(); } require_once( IPSLib::getAppDir( 'forums' ) . '/sources/classes/post/classPost.php' ); It's really as simple as that! Note the try -> catch block? That's consistent with all the new API-like functions. We take advantage of the PHP 5 exception handler to return information on what went wrong. We also list all the possible exceptions that are returnable in the phpDoc for that function. Of course, seasoned modification authors will already be familiar with functions similar to those present in IP.Board 2's API system. The good news here is that this functionality doesn't require an API bridge anymore, it's the exact same code that is used in the normal posting routines. Do you want to send a new personal conversation to someone in your own code? Simple! $messengerFunctions = new messengerFunctions( $registry ); $messengerFunctions->sendNewPersonalTopic( $toMemberID, $fromMemberID, $invitedUserIDArray, $msgTitle, $msgContent ); require_once( IPSLib::getAppDir( 'members' ) . '/sources/classes/messaging/messengerFunctions.php' ); Want to get a list of PMs in your own code? $messengerFunctions = new messengerFunctions( $registry ); $messengerFunctions->getPersonalTopicsList( $memberID, 'in' ); require_once( IPSLib::getAppDir( 'members' ) . '/sources/classes/messaging/messengerFunctions.php' ); Another common request is to use IP.Board's templates in your own projects, again this is as simple as: require_once( IPS_ROOT_PATH . 'sources/base/ipsRegistry.php' ); $registry = ipsRegistry::instance(); $registry->init(); print $registry->output->getTemplate( $templateGroup )->templateName( $templateArguments); require_once( './initdata.php' ); There really is so much that you can do. Listing them all would make for a very large blog entry indeed! We will of course be providing a lot of documentation on these new features. Combine this functionality with the new hooks and plug-ins system and you've got a very quick way to build new code using our core. We're very excited to see what you do with it!
  20. Around ten years ago, I was hard at work on one of the first 'Private Message' modifications for a board that has long ceased to exist. At the time it was an exciting novelty to be able to message another board member. These days it's an expected feature for any seriously considered forum software. Not much has really changed with messaging's core features. Sure, the interface has become a little smarter and there have been a few little bells and whistles added such as message tracking but ultimately it's still sort-of email based in functionality. This was a limitation I noted when developing IP.Dynamic. In fact, almost two years ago, I blogged about Personal Topics, the next logical step in private messaging. Enter Personal Conversations As, with most of IP.Board 3.0.0's new features, personal conversations - as we like to call them - have been a popular request. A request that we have now fulfilled! Why bother CC-ing and forwarding messages to other members when you can invite them right into the conversation? How it Works Where you would normally 'compose' a new message, you now 'start a new conversation'. The form looks largely the same. However, instead of there being a space to "CC" other members, there are boxes for you to invite other members. How many members you can invite is up to the administrator as it's limited to your group settings. In fact, the admin could remove your ability to invite other members completely if they desired to return to a more traditional messaging system. The recipient and each invited member will be notified they have a new message (in terms of notification, a message is either a new conversation or a reply to any existing conversation). The new conversation will appear in both their "Inbox" and their "New" folders. It will remain in their "new" folder until its read and then it will only be available in the inbox. Why? Well, because of the magic folders. But more of that in a moment. The conversation looks largely the same as a normal topic does; linearly sorted with the newest replies last. There is even a "fast reply" form much like you use when replying to topics. This instantly makes it easier to view previous replies and keep the 'thread' of conversation without having to delving into your 'sent' folder to see what you replied with. The topic starter (and any participating super moderator) can choose to 'block' any participant that is blockable. Immunity from being blocked is granted by the "Not Ignorable" setting. This means you can ensure that you (the admin) can never be blocked from a conversation you are participating in. When a participant is blocked, the topic vanishes from their folders until they are unblocked. Each participant apart from the topic starter can choose to leave a conversation at any time. Once the participant has left the conversation, it is only available in the magic "Finished" folder and the replies no longer count towards your space allowance. The topic starter cannot re-invite you but you can choose to rejoin the conversation at any time. The topic starter can choose to invite more members (up to their invite allowance) at any time from the conversation display screen. Each participant can also view all participants and see the last time they read the conversation. Magic Folders This is the term we give to certain folders that are not editable or removable. They are: "New", "Finished", "All" and "My Conversations". Topics in "New" and "My Conversations" can also be in other folders. "My Conversations" is the default location for any conversation you start. You can then move into another folder -- but it will always be accessible from "My Conversations". "New" simply lists any new personal conversations or any personal conversations with new replies. So, you could have a conversation in "My Folder". When it receives a new reply, it will also be listed in "New" until you read it. "Finished" simply lists all the conversations you've left, allowing you to rejoin if desired. "All", as the name implies, lists all the conversations you are participating in as either a starter, recipient or invitee. We think this is a very exciting step forward for personal communication and opens up new ways to communicate via the forum. Ten years is a long time to wait for change. We hope you find it worth the wait!
  21. Possibly the most often requested feature we've had since the very first version of IP.Board is 'friendly URLs'. Although this sounds like you'd expect your URLs to greet you with a self-empowerment phrase first thing in the morning, it really relates to making the board generated URLs a little more attractive to both humans and search engines. I am being very careful to avoid the phrase "Search Engine Optimization" in this opening few paragraphs despite it being used often in the request for friendly URLs. What we've added will definitely help with SEO but it's not a complete solution and neither is it intended to be. So, what do you have? In a nutshell: friendly URLs! The process to create and manage them is far more interesting than the end result, but more on that in a moment. Lets first look at some examples of the new URLs. Here's a few sample URLs from IPB 2.3.x: To show a forum (My Test Forum): www.board.com/forums/index.php?showforum=10 To show a topic (My Test Topic): www.board.com/forums/index.php?showtopic=99 To show a user (Matt Mecham): www.board.com/forums/index.php?showuser=30 There's nothing wrong with those URLs. They are short and concise and they spider very well, but we can do a little better to make them more attractive. If you are on a Windows webserver, you can use the 'query' string method which presents URLs like this: www.board.com/forums/index.php?/forum/10/my-test-forum www.board.com/forums/index.php?/topic/99/my-test-topic www.board.com/forums/index.php?/user/30/matt-mecham If you are on an apache based web server you can make use of the 'path_info' method: www.board.com/forums/index.php/forum/10/my-test-forum www.board.com/forums/index.php/topic/99/my-test-topic www.board.com/forums/index.php/user/30/matt-mecham Even better, if you can manage your own .htaccess files, you can make use of the mod_rewrite functionality. For convenience, the mod_rewrite code is generated for you. The end result looks like this: www.board.com/forums/forum/10/my-test-forum www.board.com/forums/topic/99/my-test-topic www.board.com/forums/user/30/matt-mecham What would happen if you used accented characters like this: M
  22. Topic markers have evolved quite a bit over the past few years. What started out as being an almost secondary concern has become quite an important part of the user experience. A Very Brief History Early versions of IP.Board relied on cookies to track read topics. This worked fairly well but it wasn't without problems. Anything to do with cookies is always a little flaky. There is a very finite amount of information you can store and browsers have a habit of eating them or not setting them correctly. The biggest complaint, however, is that topics that you have read on one computer do not stay read on another computer. IP.Board 2 introduced topic markers that are stored in a database table. This greatly increased stability and allowed the read topics to remain read regardless of computer used. However, this did lead to some performance issues on busier boards as the topic marker table is often in demand whcih can result in locking issues and processes queueing. Also, the code wasn't centralized and sprawled through different files making maintenance very difficult. Learning From Experience It was obvious we needed to centralize all the code and create a common, simple public interface as a matter of course. We also wanted to allow our other applications (such as blog and gallery) to use this system without having to copy code. Making it truly extensible also allows modification authors to use this centralized system without having to maintain their own code. Next up was the performance issue. How could we increase performance without losing functionality? The most obvious answer was to store the read topics in the user's session. This was fine in principle but there were obstacles to overcome. First of all, session handling in IP.Board 2 is not entirely centralized. There is a class but it is not used exclusively. Other files such as register.php and login.php are allowed to modify the session table without telling other classes what it did. When you're trying to preserve data, this cannot be allowed. Also, session handling in general isn't an exact science. IP addresses change meaning new sessions can be created several times during a single visit. The solution to these problems must be robust, centralized and extensible. So, what's new? First up was tightening up session handling. All session management is now performed through a single class (publicSessions). Other files that need to manage sessions are done so via publicSessions. This allows this one class to keep tight control over the session data. The biggest challenge was to allow sessions to handle the marker data and only allowing the markers to be written back to the database table when the session is deleted. The theory is sound and simple but the execution a little trickier. The gory details of which are explained a littler further down for the technically minded. In brief, the system loads the markers from the database table when a new member session is created. The markers are saved in with the rest of the session data when the session is updated at the end of a page view (to update the running time and location, etc). This continues until the session is due to be removed, for example, when the member is no longer active and the session is older than the allowed time. The sessions to be removed are captured and allowed to be examined by other classes. The item marking class examines these sessions and writes back the marker information to the marker database. The system also makes use of cookies to give some permanence for guests and those that are not logged in. The cookies are limited to the last 100 items read to prevent cookies being sent that are too large. The end result is a much leaner system which should be much more efficient and presents a very simple public interface. Here's some sample code to give you a taste: $itemMarking->markRead( array( 'forumID' => 2, 'topicID' => 10 ) ); # To fetch the read status of an item if ( $itemMarking->isRead( array( 'forumID' => 2, 'itemID' => 99, 'itemLastUpdate' => 1200098989 ) ) === TRUE ) { .... } # To fetch the last time an item was marked $lastMarked = $itemmarking->fetchTimeLastMarked( array( 'forumID' => 2, 'itemID' => 99 ) ); # To mark an item read (an item is a topic for the forums 'application') Modification authors can write their own plug-ins and make use of the system with minimal coding effort. Listen Up, Here Comes The Science Bit For the more technically minded, this section explains how the system works within the new IP.Board 3.0.0 framework. The first challenge was to make proper use of __construct and __destruct within PHP 5. This is very straightforward in the case of __construct; this is run when the class is initialized. There are no problems with that. The item marking class grabs and filters the cookie data and also grabs and filters the session item marking data in __construct. The real issue is with __destruct. Specifically the order in which they are called. In PHP 5.0.0 to PHP 5.2.4 they are called in the order they were created. This means that by the time __destruct() is called in item Marking the DB connection has been closed which isn't at all helpful. This is because the DB is set up before classItemMarking. Now, as of PHP 5.2.5 the __destruct order has been reversed. This means that the DB connection will still be available. However, that's not very convenient for code that has to be robust on different platforms and with unpredictable version of PHP. Another solution was needed. Thankfully register_shutdown_function() executes before any __destruct() calls, so we can reliably use this. There is a __myDestruct function in the ipsRegistry class which calls __myDestruct() in all the registry child classes (DB, Member, Request, Cache, Settings, etc). The member registry class makes use of this to fire a manual destruct function within itemMarking to allow it to save back any data for deleted sessions and to provide information for the session update. A __myDestruct fires within the public session class to actually update the sessions and delete the expired ones. Phew! As you can see, there's a lot going on behind the scenes in IP.Board 3.0.0 which makes full use of all PHP 5 has to offer.
  23. Way, way back in the early days when we were planning IP.Board 3, a primary consideration was to completely overhaul the output engine to add several new features and to increase extensibility. Out with the old... The system in IP.Board 2.x is really just a perfunctory "engine" build around a few methods in a class. There was no real cohesive structure with many different files and functions accessing 'skin' methods. We decided that a virtual re-write was required. We didn't want to be tied to a single output format. Back when IP.Board 2 was first written, there were no iPhones and the idea of actually viewing a forum on a cell phone seemed more than a little crazy. Times have changed. ...and in with the new At first glance, the new system isn't that different from what we had in IP.Board 2. It's when you scratch the surface that its power becomes more obvious. The first change is that you can have an unlimited depth for child skins. In IP.Board 2 you could only have one level of child skins which was very limiting to some skinners. Also, in IP.Board 2 there was a single master skin from which each skin inherited from. While there is still a single "master" skin in IP.Board 3.0.0, it's completely transparent and instead you can set up several different "root" skins for which child skins inherit from. This instantly makes for more flexibility. In IP.Board 3, each skin can have multiple CSS files which can be hard-positioned within the ACP to ensure the correct load order for correct cascading. Also, each skin allows you to set group-based permissions so that you can determine exactly who can view and select skins. And finally, guests can select a skin (as long as you give them permission to do so!) Going Deeper: User Agents IP.Board has a completely new user-agent system where you can add new user-agents and group together several. This system is now used for the 'search engine spider' settings. This also means that you can tie a user agent to a specific skin. Do you want your iPod touch and iPhone users to use a specific skin? You can do that very easily within the ACP. Taking it further, you can even designate specific versions for each user agent. Do you want to take advantage of Firefox 3 or IE 8? That's very simple to do now. You can even set a range of versions very simply. Going Deeper Still: Output Formats The biggest change is that IP.Board can now handle multiple output formats. By this we mean that IP.Board has a plug-in architecture to allow completely different processing for HTML, XML or even WAP. This system is completely extensible so modification authors can easily write their own engine plug-ins which drop in and are available for use immediately. Each skin must choose an output format to use which means that you can have completely different skin sets for XML and HTML bringing in even more flexbility. You can also use a "gateway" file to set the output format. IP.Board 3 ships with two gateway files. "index.php" which is tied to the HTML output format and "xml.php" which is tied to the XML output format. This means that "index.php?showforum=1" and "xml.php?showforum=1" enable the correct output engine instantly. Putting it Together Take this scenario: You want to support WAP using XML with XLST templates specifically for Nokia cell phones. Done, done and done. All without having to make a single PHP modification. Now that's a powerful system!
  24. A while ago, I posted about the new template tags system in IP.Board 3.0.0. After some initial feedback on the syntax and having developed the system further, I felt it was worth revisiting in our blog. The template tag system is still based on PHP classes (extends and implements, PHP5 fans) which act as plug-ins. These plug-ins are only run when the templates are cached which makes the system very fast and very efficient. The new tag syntax is very straightforward and easy to remember: {parse plugin="data" option="value" option2="value2"} The updated system also allows you to embed tags, which we'll see later. First off, here are the tags which are currently being used in IP.Board 3.0.0 Expression This tag is used to parse an in-line PHP expression which returns a value. This can be any inbuilt PHP function or any IP.Board function. {parse expression="intval($data['count'])"} {parse expression="IPSText::alphanumerical_clean( $data['value'] )"} This makes it very easy to format data on the fly and removes the need for obsessive intval'ing in your code to ensure that a correct value is displayed such as a zero rather than nothing at all! Template This tag is used to insert any other template bit from IP.Board. {parse template="pageLinks" group="skin_global" params="$data['start'], $data['end']"} The benefit of this tag is immediately obvious. You don't have to 'hack' the PHP sources to re-use template bits. Variable This tag is used to set and alter a template variable. To set up a variable with they key 'className': {parse variable="className" default="tdRow1" oncondition="$data['foo'] == 'bar'" value="tdRow2"} To alter the variable based on different data: {parse variable="className" oncondition="$data['foo'] == 'foo'" value="tdRow3"} To use the variable: {parse variable="className"} Lets look at a practical example: {parse variable="className" default="row1" oncondition="$data['banned'] === TRUE" value="rowBanned"} <foreach loop="$key => $data"> <div class="{parse variable="className"}"> </foreach> Striping While Rikki was working on the new IP.Board skin, he mentioned that it would be very handy to have some kind of tag that could handle the 'zebra' striping (the alternate row colours when viewing a forum list, etc). To set up a striping tag: {parse striping="someKey" classes="tdrow1, tdrow2, tdrow3"} To use a striping tag: {parse striping="someKey"} When parsed, this tag will cycle through the classes, repeating the cycle if required. Let's look at a practical example: {parse striping="rows" classes="row1, row2"} <foreach loop="$data as $key => $value"> <div class="{parse striping="rows"}">$key = $value</div> </foreach> AddToHead It can be difficult to adhere to strict standards when dealing with templates and piece-meal code. Often you compromise and have javascript and CSS scattered throughout the finished document. IP.Board allows you to add content to the document <head> very quickly and simply: {parse addtohead="/js/someScript.js" type="javascript"} {parse addtohead="/css/someCSS.css" type="css"} {parse addtohead="<script>alert('boo')</script>" type="raw"} Date In previous versions of IP.Board, all the date processing was performed inside the PHP code which made it very hard to customize the date formats beyond what was allowed in the Admin CP. Now, IP.Board allows you to process dates using the date tag in templates. Examples: {parse date="now"} {parse date="1765346750" relative="1" format="long"} {parse date="-1 hour" format="manual{d, m, Y}"} URL IP.Board 3 allows a very easy way to format URLs without having to reply on special PHP variables. Examples: {parse url="showtopic=1" base="public"} {parse url="showforum=5" base="publicWithApp"} {parse url="photo1.jpg" base="upload"} Format Number IP.Board 3 allows a quick and easy to to access the built in "format_number" function. Example: {parse format_number="123456"} Replacement To keep our tags uniform, we've removed the old 'macro' tag (<{MACRO_HERE}>) and replaced it with the new 'replacements' tag: {parse replacement="macroKey"} Of course, the real power in this system is that you can very quickly and simply create your own template tags and drop them in the template tags folder for them to be available instantly.
  25. In a previous blog entry on IP.Board 3.0's new framework, I mentioned that at the core of the new framework is something called 'ipsRegistry'. This blog post will go into more detail and will be of interest to modification authors. Overview IP.Board, like most complex applications, has a need for 'core' data, like settings, session and input data ($_GET, $_POST, etc). There is also a need for a database connection and access to global objects like cached data. It would be incredibly wasteful to make each file and class set up a database connection, load any cached data, authorize the browser session and build up any settings. This could happen many time in any IP.Board view. Clearly there is a need for a way to initialize this data once and then pass it throughout the application. This is exactly what the ipsRegistry is for. Previous versions of IP.Board relied on the 'ipsclass' object as a registry; but this quickly became tarnished without clear boundries as more and more data was attached to it. It was more of a global variable than anything else. The new registry is composed of clearly defined objects. Also in previous versions initialization of the settings, caches, input data, sessions, etc was handled over a scattering of classes and files. The new registry is a single point for this initialization. This initialization occurs when init() is called. This makes it much easier to use IPS registry data in your own scripts and modifications. Previously you would have needed to copy out half of the default index.php. Now your scripts can be as simple as: require_once( 'classes/base/ipsRegistry.php' ); /* Call init which loads up input, caches, settings, creates the DB handle, authorizes and loads the member $registry = ipsRegistry::instance()->init(); print $registry->request()->getField('foo'); $registry->DB()->do_update( 'table', array( 'foo' => 'bar' ); ); print ( $registry->member()->getProperty('member_id') ) ? 'Hello ' . $registry->member()->getProperty('members_display_name') : 'You are a guest'; require_once( 'conf_data.php' ); Gathering Input from URLs and Forms One key part of IP.Board's initialization was the sanitization of $_GET and $_POST into a clean array. This was vital to the overall security of the board. IP.Board 3.0 as a 'request' registry object for this and all functions relating to this initialization (parse_key, parse_value, etc). This is available via either $this->request->getField('foo') or $this->request['foo']. This effectively replaces $this->ipsclass->input['foo']; Cached Data There are many improvements to the caching backend which we'll go into more detail in a later blog entry. The cache registry object simply returns the cache when requested via $this->registry->cache()->getCache('forums'); The cache is loaded and unpacked during initialization so you do not need to manually call it. The Database So much of the database code has been refactored that it's almost a separate blog on its own. Here, I'll concentrate on the registry object. The main function is getDB() which is interfaced via $this->DB (or ipsRegistry: :D B() when outside of class scope). This is a simple function to return the DB object which is set up during initialization via setDB(). This happens transparently when the file is included and init() called (which is done so by ipsController.php). You may set up more connections by specifying a key, for example: return $this->registry->DB( 'newConnection' )->build_and_exec_query( array( 'select' => '*', 'from' => 'table' ) ); $this->DB->setDB( 'mysql', 'newConnection', 'user@localhost.com', 'password', 'localhost' ); Settings The setting cache is loaded and unpacked during initialization. This registry object merely returns the setting when requested via $this->settings->getSetting('foo') or $this->settings['foo']. Member Information Previously member information was scattered through 'ipsclass'. IP.Board's member registry centralizes this information. This object sets up the incoming IP address, browser and operating system and attaches it to the member class. It also authorizes the current browser session (via cookies or an inline URL) and loads up the session member and builds up the permission arrays. All this is done during initialization meaning there is less to do on the front end. I hope this post has given you some insight into the IPS registry and the improvements it brings not only to IP.Board itself, but also to modification authors who will find their workload greatly reduced by automatic set up of all the required information. If you find that you do not need all of this information set up, then you can write a child class of ipsRegistry and alter the 'protected' functions to prevent them from initializing.
×
×
  • Create New...