Jump to content

Jim M

Invision Community Team
  • Posts

  • Joined

  • Last visited

  • Days Won


Reputation Activity

  1. Like
    Jim M reacted to Matt for an entry, IC5: Theme Tools   
    Theming has been a core component of Invision Community since its inception, and this continues with Invision Community 5, but in a very different way.
    If you haven't already seen Ehren's blog on the new Theme Editor, please do take the time to watch it. The all-new theme editor reduces the complexity of theming by taking complex concepts like HSL CSS variables into a pretty slick UI that almost any Invision Community owner can use to personalise or brand match to any existing properties.
    Ehren will talk more on the technology behind the theme editor in another developer blog soon, but the short version is that the CSS framework has been completely rewritten from scratch with a new approach to how CSS classes interact with page elements.
    Of course, if you're reading this, you'll want to know what tools you have for more advanced theming in v5.
    Custom templates and template hooks
    Invision Community 5 merges the concepts of custom templates and template hooks into a single feature. In the past, you could edit templates directly and create theme hooks. With Invision Community 5, these features are replaced with the new custom template system.

    You can create new templates, which you can use in other custom templates via the short tag: {customtemplate='key'}. 
    You can also hook into specific areas with a custom template allowing you to insert code before the opening tag, after the opening tag, before the closing tag or after the closing tag.
    CleanShot 2023-10-19 at 13.17.16.mp4
    For example, if you wanted to add something custom before the reply editor when viewing a topic, you would target that area like so:

    The result, when viewed on the front end, is as follows:

    These hookable areas are defined by a special tag that we add to the core templates. We would expect a lot of requests through the beta release and will likely create a request form so we can process them. We will try and accommodate as many areas as possible.
    While direct template editing is no longer possible in Invision Community v5, the new custom template and hook system allows you to add new functionality, while the new CSS framework makes it easier to target and change elements without the need to edit templates.
    We also added a suite of new development tools to enable you to target menus, data attributes and other areas where developers commonly had to edit templates before.
    The good news is that now custom templates are not built on top of our 'master' template engine; they are virtually upgrade-proof and do not require manual merging.
    Theme Designer Mode
    Those who create themes for others have some extra tooling to enable them to build truly custom themes.
    Even though the theme editor has space for custom CSS, there is always a need for CSS that your customers cannot edit, and Invision Community 5 has a special area for that once Theme Designer Mode has been enabled.

    You also can add any ad-hoc javascript for when you want to hide elements or provide custom interactions.
    As direct CSS editing and direct template editing are no longer possible with Invision Community 5, there is no need for a 'sync' tool to copy from the filesystem.
    The new front-end theme editor is now the primary way to manage themes. This is where you upload logos and toggle settings.
    As you can see, theming may look different in Invision Community v5. Still, the new custom templates, theme designer tools and UI extensions provide a lot of functionality that means you can do nearly everything you did in v4, but often in an easier way.
    I'm sure you'll have many questions, so please add them below, and we'll do our best to answer them for you.

  2. Like
    Jim M reacted to Esther E. for an entry, IC5: UI Extensions, Part II   
    In our  previous blog entry, we described the UI Extension and its overall capabilities. Today, we'll talk about how to use this new tool to extend content forms and menus.

    Form Fields
    A popular modification request is to add fields to a Content Item, such as a Topic. All UI extension classes contain the following methods:
    Returns an array of form elements that will be added to the form. Note: Unlike other UI Extension methods, the first parameter of this method can be NULL, if you are creating a new item.
    Allows you to process the fields that were added in the formElements method. Note that this method is triggered after the form is saved. Note: This method has the same function as the ContentListener method onCreateOrEdit, but we've added support for it here as well to avoid the creation of multiple classes, and to keep related code in the same place.
    Element Placement
    By default, all new form elements will be inserted at the end of the form. However, there are times that you may want to insert your fields into specific positions within the form. You can use the new FormAbstract::setPosition() method to specify where the element should be inserted.
    Let's look at an example.
    public function formElements( ?BaseItem $item, ?Model $container ): array { return [ 'my_new_field' => new Text( 'my_new_field', $item ? $item->new_field : null, true ) ]; } The above will append a Text field called "my_new_field" at the end of the Topic form.
    public function formElements( ?BaseItem $item, ?Model $container ): array { $field = new Text( 'my_new_field', null, true ); return [ 'my_new_field' => $field->setPosition( Topic::$formLangPrefix . 'tags', Topic::$formLangPrefix . 'mainTab' ) ]; } By using setPosition, I've placed the new field after the "tags" field, on the main tab in the form.
    Extending Content Menus
    In this blog entry, we introduced our new approach to building menus. With UI extensions, you can add your own items to Item and Comment menus using the following methods:
    UIItem::menuItems UIComment::menuItems We will discuss nodes and their menus in a future blog entry.
    Extending Item Badges
    Similarly, you can use the UI Extension to add badges to the item header. The UIItem::badges() method returns an array of badges and/or icons to be appended to the badge display.
    This concludes our discussion of UI Extension features related to Items and Comments. In our next blog entry, we'll discuss Nodes and what additional methods are available.
  3. Like
    Jim M reacted to Esther E. for an entry, IC5: UI Extensions, Part I   
    Only a little over a week into our development tools announcements, and there is already lots of buzz about our new UI Extensions. The UI Extensions handle a variety of functionality, and we will discuss them all in detail, over the course of multiple blog entries. For today, we'll start with an introduction and an overview of some of the basic usage.
    Features and Functionality
    UI Extensions are extensions to a single content class - Nodes, Items, Comments, or Reviews. With a UI Extension, you can:
    Add custom CSS classes and data attributes Add options to content menus Add badges to content item headers Add fields to content forms ACP-related functionality (for nodes) And a couple of other small things that we'll cover here.

    The Application Developer Center has 4 new options in the Extensions tab:
    UIComment UIItem UINode UIReview To add a UI extension, simply create a class under the appropriate extension type.
    Note: We are working on improving this process, however, those changes will likely be introduced at a later date.
    The default extension file will be generated in the appropriate directory within your application's extensions folder. All UI Extensions are abstracted, so if you omit a method from your class, or if new methods are introduced later on, your extension will not throw an error.
    All UI Extension methods receive the object as the first parameter.
    UI Extensions for... UI
    The idea for UI Extensions was born when we were reviewing the most common third-party development hooks. With the removal of theme hooks, we needed a way for developers to add custom CSS and attributes to areas such as topic rows, the author panel, among others. Even with the theme hooks in v4, the way to accomplish this was less than ideal. Adding a CSS class typically required at least 2 hooks per template - one to determine the correct class (usually based on custom logic) and one to insert the class as a variable. It was tedious and finicky at best.
    All UI Extensions include the following methods:
    Returns an array of CSS classes that will be applied to the object dataAttributes
    Returns an array of data attributes (as "key=value", "key=value") that will be applied to the object To insert those values into the appropriate location, our templates now contain the following syntax:
    {$object->ui( 'css' )} and
    {$object->ui( 'dataAttributes' )} Let's examine the Content::ui() method (identical to Model::ui().)
    public function ui( string $method, ?array $payload=array(), bool $returnAsArray=false, string $separator = " " ) : array|string The ui method accepts 4 arguments: the method name, an optional payload (determined based on the method being called), the option to return as an array (vs a string), and an optional separator (when data is returned as a string). The defaults for this method were set for the simplest, shortest syntax within the templates, as seen above. You may also see syntax like this:
    foreach( $this->ui( 'menuItems', array(), TRUE ) as $key => $link ) { $links[$key] = $link; } As you can see, in this case the ui method will return the results as an array.
    Class-Specific Methods
    Some of our extensions include methods that are applicable only to objects of that type.
    Returns HTML that will be included in the contextual sidebar when viewing the item UIComment::authorPanel()
    Returns HTML to be inserted into the author panel of a post Note: All methods in the UIComment extension are also available in UIReview.
    We hope this entry gave you a glimpse into what will be available with this new tool, and a better understanding of the direction we are taking with our toolkit. We will discuss the other features of this tool in upcoming blog entries.
  4. Like
    Jim M reacted to Esther E. for an entry, IC5: Introduction to Listeners   
    I'm very excited to be posting my first blog entry for IPS, and thrilled that this is what I get to post.
    When we started planning the new development tools for v5, we looked at existing resources - from the marketplace, from some contributors, and from our own managed clients - and asked, what is it that developers find themselves doing the most often? Matt’s previous blog entry gave a brief summary of some of those functions. Today’s blog entry is going to focus on one of our powerful new tools, Listeners.
    One common reason for a code hook was to execute custom code when a specific action occurs. For example, when a topic is created, or when a new reply is posted. Listeners allow you to execute your code at key points in the workflow, without the worry of finding exactly the right hook location.
    Here is an excerpt from the BlogComment listener in our Cloud application:

    Creating Listeners
    Let’s start with the application’s Developer Center.

    We’ve added a new tab for Listeners. This tab lists all your existing listeners, as well as the class on which it is listening.
    You’ll notice that each listener can only observe a single class. While this may seem slightly tedious, the idea here was that as a developer, you should be conscious of what class you are working with. It also eliminates the need to check what type of object is being passed preventing accidents and unintended consequences when missing class checks.
    When you add a listener, there are several listener types available. We will discuss each one in detail.

    Content Listener
    This listener is fired on an Item or Comment (or Review) class. When adding a Content Listener, you must specify the class you are observing. When you hit Save, there is a validation check in place to ensure that the class exists, and that it is a valid class for the selected listener type.
    Content Listeners have the following methods available. All methods are included in the default listener file that is generated.
    Triggered when an object is loaded (in Content::constructFromData) NOTE: Be careful! This event could be fired at unexpected times. If you’re executing code here, you may want to check the dispatcher instance to verify that your code is running where you expect.
    Fired when a form is submitted, before it is saved. This is the equivalent of Item::processBeforeCreate and Item::processBeforeEdit. This method includes a parameter to indicate whether this is a create or edit. onCreateOrEdit
    Fired after a form is saved. This is the equivalent of Item::processAfterCreate and Item::processAfterEdit. This method includes a parameter to indicate whether this is a create or edit. onDelete
    Fired after an object is deleted. onStatusChange
    Fired when any moderation action occurs. For example, when an item is pinned/unpinned, locked/unlocked. The moderation action is passed as a parameter so that your code can take that into account. onMerge
    Triggered AFTER an item is merged. onItemView
    Triggered when an item is viewed and the view count is incremented.  
    Invoice Listener
    An Invoice listener is fired only on the \IPS\nexus\Invoice class. This listener does not require you to specify a class to extend.
    The Invoice listener includes a single method, onStatusChange. This is fired when the invoice is saved and the status changes (pending/paid/expired/canceled).
    Member Listener
    The Member listener will be familiar to many of you. We have taken the MemberSync extension and moved it in its entirety to a listener, as it was a better fit for this structure. All the previous methods that were available are still available here. We have also added the following new methods:
    Fired when a member joins a club. If approval is required, this is fired after they are approved. onLeaveClub
    Fired when a member leaves or is removed from a club. onEventRsvp
    Fired when a member responds to an event. The response is included as a parameter to this method.  
    Commerce Package Listener
    The Commerce Package listener is fired on any implementation of \IPS\nexus\Invoice\Item. You must specify the class that you are observing.
    The methods are the same as those that are available in an item extension.
    onCancel onChange onDelete onExpireWarning onExpire onInvoiceCancel onPaid onPurchaseGenerated onReactivate onRenew onTransfer onUnpaid  
    Some Technical Notes
    All listener files will be generated in a “listeners” directory within your application. Your application’s data directory will include a listeners.json file that defines all your listeners. The json file is automatically generated when you add/remove a listener. All listener methods are optional. The default class that is generated will include all available methods, but they do not have to be present in your file. All listener methods are return type void. If a listener method fails, an exception will be thrown when IN_DEV is enabled. In production, the exception will be logged with a reference to the listener class and the event on which the exception occurred.  
    Firing Events
    Your code can fire any existing event using the Event::fire method.
    Event::fire( 'onBeforeCreateOrEdit', $comment, array( $values ) ); The Event::fire method is called statically and accepts an event name, the object on which the event will be fired, and an array of additional parameters (varies according to the event that you are triggering).
    This concludes our introduction to Listeners. We do intend to implement additional listener types and events based on your feedback and as the need arises.
  5. Like
    Jim M reacted to Matt for an entry, Introducing Invision Community 5's development tools   
    When planning Invision Community 5, we knew we had a unique opportunity to hit the reset button.
    It's hard to believe, but how we work with the framework has been the same since 2013. The priorities we held a decade ago no longer align with our current vision.
    The landscape of modern frameworks has evolved, and we have adapted accordingly.
    When we initially designed the Invision Community 4 framework all those years ago, our goal was to create an open development platform. We aimed to empower you with the ability to extend virtually every function we built, granting complete freedom to shape our UI, workflows, and functionality according to your needs.
    However, over the decade, we have realised that this freedom has inadvertently become a prison. While monkey patching allowed the overloading of any method we had written, it came at a significant cost. Even the slightest change to our original method signatures could break an entire community, forcing you to update your applications.
    Ironically, the more we strived to enhance our framework, the less stable your applications became.
    We dismissed requests for proper workflows like extensions, webhooks, and event listeners, urging you to rely solely on method overloading, often having to copy chunks of code just to add a few lines of your own.
    Invision Community 5 represents a much-needed reset. It is a moment to reassess everything we know about extending frameworks and construct definitive pathways and workflows that serve you better.
    Our aim is for you to continue crafting exceptional applications that bring fresh functionality to the Invision Community while protecting the integrity of our core functionality.
    Change can be intimidating, but let us embrace this opportunity to bid farewell to outdated and fragile tools and pave the way for a collaborative future with precision-designed resources instead.
    In the coming weeks, we will delve deeply into the new development tools offered by Invision Community 5, but today, I wanted to give you a brief overview of what's to come for code development. We will do a near-future entry on creating themes with Invision Community 5.
    Out with the old
    Monkey patching via code hooks was the primary way to add functionality to Invision Community. However, it meant that we could not update our code base without risking breaking many popular applications, a situation that will only get worse as PHP starts to lock down type hinting and casting.
    Furthermore, IDEs have a tough time working out relationships between classes requiring special tools to create alias files to allow full use of many advanced tools of PHPStorm and other editors. Finally, monkey patching relied on heavy use of eval() which is not a very efficient PHP method.
    Monkey patching has been removed in Invision Community 5.
    Your IDE with Invision Community 4.

    Your IDE with Invision Community 5.

    Template hooks, as you know them, have also been removed. I only mention this now as they often go hand-in-hand with code hooks to add items to menus, data-attributes to blocks and CSS classes to many areas. We will do a more thorough blog on theme editing soon, but we still retain a way to hook into key areas.
    In with the new
    We will write a series of developer blogs to look in more detail at the new systems, but here is a quick overview of the new tools and a brief description of what they are capable of.
    Content Menus
    We have removed much of the menu logic for content items and comments from templates and created a simple, extensible way to add links to commonly used menus, such as the item moderation menu and the per-post 'three dots' menu. You no longer need a template hook to perform such a basic task.

    This framework provides you with an easy way to add CSS, data-attributes and even templated HTML into specific areas within nodes and content items/comments. A common reason to create template hooks was to tweak the CSS classes or add data-attributes for client-side scripting.

    In the same way that we've stripped menus out of templates, we've removed the content item badges (pinned, hidden, etc.) and into the UIExtension making it easy to add your own badges to this area without the need for template or code hooks.
    Finally, UIExtension can add form fields into Invision Community content forms.
    Event Listeners
    The easiest way to describe this is like MemberSync but for content (items and comments), members, Commerce invoices and Commerce packages.
    Do you need to run your code each time a forum post is made? Not a problem. Do you need to run your code when a topic is locked? Perhaps when an item is viewed? All this and more is possible via the new listeners.
    The advantage is that you don't need to copy chunks of our code when overloading a single method in a hook. You write your clean code in an object-specific listener.

    What else?
    We have also undertaken a long overdue code clean-up. Every single file has been updated to update return types and function signature types and to use aliases instead of fully qualified names (for example, new Url() instead of new \IPS\Http\Url()).
    Many methods have been removed from the Content classes and moved into traits. Likewise, many interfaces are now traits to reuse code properly, reducing the behemoth-sized classes.
    Elsewhere, all the search indexing logic that was entwined in content and node classes has now been moved to the extension system, further reducing the noise and volume of key classes.
    A Quick Recap
    Generic broad reaching tools such as monkey patching and template overloading have been removed. New precision tools with a specific use-case have been created. There are less opportunities to overwrite and change our UI and functionality but easier ways to extend and create new functionality. The future
    We have worked hard on these development tools to ensure that most of what you do now can be achieved in Invision Community 5. We have had input from various stakeholders, including those who regularly create modifications for Invision Community to ensure our new tools are fit for purpose.
    Through the alpha and beta testing phase, we want your feedback, and we will listen to your suggestions. We cannot promise that you can do everything with Invision Community 5 that you currently do, which is intentional, but we are confident that you can still hit all the major beats. We want to protect our UI and functionality a little more but encourage you to build amazing new functionality to work alongside Invision Community 5.
    Together, we will shape the next era of Invision Community.
  6. Like
    Jim M reacted to Matt for an entry, Development update for April 2022   
    Welcome to our April developer's update!
    This month has seen the developers work on a variety of features coming to our cloud platform, some of which we've been testing here, which include real-time updates on what members are viewing and when they are typing replies and an image scanner which not only identifies what is in the image, it also tags it for search results. Furthermore it can also hold images for moderation if they contain nudity, etc. We've got more to come and will announce them as they are finished.
    The cloud platform features leverage multiple technologies such as node, JWT security, and AWS specific functionality, enabling us to build pretty impressive new features quickly. As we expect more sophistication and algorithmic crunching from our web apps, we're starting to break out of the PHP and MySQL limitations to deliver forward-thinking features.
    Of course, we have plenty of new features coming to all platforms, including the self-hosting version; I can talk about a few changes we've made but let's start with some housekeeping.
    There will not be a full release for May, although we will be releasing several betas throughout the month. We are taking this time to finalise a few bigger changes to our codebase.
    For those running their own servers, we are updating the minimum PHP requirement to 7.4 and the recommended version to 8.0. If you're not sure which version you currently use, now is a good time to check!
    We are working on PHP 8.1 compatibility still and are aiming to have that finished for June's release.
    The list of fixes already in the June release is as follows:
    Core - Fixed an issue that may prevent attaching audio files to content. - Fixed a minor typo in the forms.css template. - Fixed upload area not showing on minimised editors for guest users. - Fixed an issue where post counts were incremented even when a new item was held for approval via the profanity filters. - Fixed an issue where filters and sort options do not persist between deleting members in the Admin CP. - Fixed an issue where sitemap may show entries from offline applications. - Fixed an issue where support account may show as the latest registered member. - The Editor Preview Button was removed from ACP Editors. - Removed the deprecated FX Country code from the Geolocation class. - Removed the ability to rebuild existing attachment thumbnails due to an incompatibility with content attributes required for lazy-loading. Gallery - Fixed an issue with the followed Gallery Images page. - Fixed an issue with rebuilding thumbnails on legacy communities where the original image may no longer exist. Pages - Added the missing `__indefart_cms_page` language string. - Fixed an issue where sorting by a numerical field could duplicate the option with an incorrect label. - Fixed issue with 'image upload' block carousels not working in the sidebar - Fixed an issue where custom Yes/No fields, when used as a database filter, were ignored when further sorting. Converters - Fixed an issue rebuilding some profile photo images. Commerce - Improved performance when updating a large number of existing purchases. - Removed deprecated Amex Express checkout options. - Fixed a niche issue where a renewal invoice (for manual payment) would not be generated if a PayPal Subscription was cancelled on an active purchase. Calendar - Fixed an issue where the day view wouldn't show today's events when it's being used as the default calendar view. A few items still being finished before being sent for peer review include tweaks to search logging. Andy added the ability to specify which groups to log anonymous search sessions. We got some feedback that bot searches were polluting the results, making it hard to discern search trends from members over time. As we anonymise the search data, we can't pick out specific member groups once it's been written. Andy also moved the search logs to their own page to reduce confusion over what the data represents.
    Andy has also been working on some activity stream improvements to bring a "Solved/Unsolved" filter option to allow you and your members to find unsolved (or indeed solved) topics quickly. This will require a search index rebuild after upgrading.
    You may also find a few new hook points added, which are in the following locations:
    This is called from within processUploads and allows you to modify the data before it is saved into core_files_temp.
    This is called during manage() and allows you to modify the $topic before it is returned to \IPS\Content\Controller. If you have to overload manage() in your apps, you may find this a better hook point.
    \IPS\Content\Search\Index\indexData now allows $content modification before it is stored via an extension in /applications/{app}/extensions/core/SearchIndex
    That's it for this month!
  7. Like
    Jim M reacted to Daniel F for an entry, Introducing Webhooks   
    Webhooks allow other services and applications to stay in sync with your community data or to perform an action after a specific event occurs in your community.
    Webhooks are a performant alternative to continuously polling for changes to the IPS REST API.

    For example, a webhook can notify your service when a new topic is created so that your app can perform then any further actions.
    Webhooks can also be used to connect your community with Zapier, IFTTT or Integromat, so that any event which is covered by webhooks can trigger any further actions.
    Common webhook use cases
    Sync your member base with 3rd party newsletter lists Sync your Event RSVP with your Online Ticketing System Update your inventory after a purchase was made You can find the webhook functionality in the AdminCP, under the API section. There is also a useful webhook reference built in.

    Setting up a webhook
    Setting up a webhook is straightforward. Log into your AdminCP, then navigate to System > API.
    The target URL would be defined by the application you wish to fire events to. For example, in Zapier, you can set up a trigger to listen for a webhook event via a custom URL.

    Once you have entered the URL, simply check which events you'd like to fire to that URL. Zapier will ask you to test the URL, so to do this simply invoke the action which fires the webhook event, such as creating a test topic.
    If you are looking to add webhook events into your own custom code and applications, please see our documentation here.
    Webhooks will be implemented in 4.6.10 and will be enhanced frequently.
  • Create New...