Jump to content

Daniel F

Invision Community Team
  • Joined

Everything posted by Daniel F

  1. It was brought to our attention that this application requires manually uploaded files. As of 4.4.3 you're able to hook into IPS\nexus\Purchase\LicenseKey::licenseKeyTypes() to register your own LicenseKey class within your applications namespace.
  2. Daniel F replied to Spanner's post in a topic in Marketplace
    Did you take a look at our GroupLimit extensions? https://invisioncommunity.com/developers/docs/development/extensions/coregrouplimits-r141/
  3. One of our clients has a huge system log database table full with following error: SELECT * FROM `chatapp_chatrooms` LEFT JOIN `core_permission_index` ON core_permission_index.app='chatapp' AND core_permission_index.perm_type='chatroom' AND core_permission_index.perm_type_id=chatapp_chatrooms.id WHERE (( FIND_IN_SET(2,perm_) ) OR perm_='*' ) Unknown column 'perm_' in 'where clause'
  4. This lesson will guide you through setting up your first custom application and getting output to show on the screen. It is also intended to help you familiarize yourself with the structure of an application and with the tools you will use to build complex modifications. Topics Creating an application Overview of application structure Overview of development center Creating a module and controller Page output Before you begin You must be in Developer's Mode in order to create a new application. Details on enabling Developer's Mode can be found at: Creating an application Login to the ACP and go to System -> Applications. Press "Create New" Enter the following field values: Application Title: IPS Tutorial Application Directory: ipstutorial Author Name: your name Press Save Directory Structure Once you create your application, a folder with your Application Directory name will be created in the "applications" directory of your installation. It will have the following folders: data contains json and XML files used to build and install your application. These files should NEVER be edited manually (with the exception of furl.json) unless you are 100000000% certain you know what you are doing. dev Used only in developer mode. This contains all language strings, HTML templates, JavaScript, email templates, and resources specific to your application. This directory is discussed in more detail later in this article. extensions All extension classes (such as navigation, membersync, etc) for your application. hooks Any hooks used by your application. You can find more information on hooks at interface Any code that needs to be accessible externally. Not used often. modules The modules directory contains two folders - admin and front. admin contains all the modules and controllers used by the ACP, front contains modules and controllers used by the front end. setup Installation and upgrade scripts, as well as SQL queries required to upgrade between versions. Most files here are automatically generated. sources Classes specific to your application tasks Any tasks that will be executed by the System Scheduler Other folders may be generated in your application directory, depending on what functionality you add. These include: api Contains any methods that will be exposed via the REST API. This directory would be created manually by you (the developer). widgets Class files for all widgets created for your application dev folder The dev folder for an application is where you will create most of your client-side code. It contains the following sub-directories: css All CSS files for your application. The css directory can contain up to 3 sub-folders: admin, global, and front. Be sure you create your CSS file in the appropriate location. email Email templates (both plain-text and HTML) for any notifications and/or digests that will be sent by your application. For more information, see html HTML templates for your application. This directory can contain up to 3 sub-folders: admin, global, and front. For more information on template creation, see https://invisionpower.com/4guides/themes-and-customizations/template-syntax/. js All JavaScript files required by your application. This does not include any 3rd-party JavaScript, that should be packaged in your interface folder. For details on how to create IPS JavaScript files, see https://invisionpower.com/4guides/themes-and-customizations/javascript-framework/ resources Any other files (e.g. images) required by your application. The dev folder also contains 2 files: jslang.php and lang.php. These files include all language strings used by your application. For more information on language strings, see https://invisioncommunity.com/developers/docs/development/plugins/creating-language-strings-in-plugins-r48/ Developer Center Most of your work will begin in the Developer Center. The Developer Center will assist you in setting up your database structure, as well as generating the proper PHP templates for various Classes. To access the Developer Center Login to the ACP Go to System -> Applications Find your application in the list From the menu on the right, choose Developer Center The Developer Center contains several tabs. Each of the tabs is briefly described below; for additional information, please find the appropriate documentation article or post a question in the forums. Admin CP Menu Defines the ACP menu items for this application. This tab is automatically populated when you create Admin modules and the appropriate language strings, however, you can use it to rearrange or create non-default menu items. Admin CP Restrictions Any ACP restrictions that will be checked by the application. Restrictions defined here will appear when adding a new Administrator under Members -> Staff -> Administrators. Database Schema Used to create and modify database tables used by your application. Extensions Create and manage any extension files used by your application. The Extensions tab contains a line for each application that accepts extensions; currently this is only "core" and "nexus". Here you will define things like custom advertisement locations, profile tabs, front navigation menu items, custom nexus items, file storage, and more. When you create an extension here, a class template is generated in the corresponding folder in your "extensions" directory. These templates are well commented and usually relatively easy to understand. Hooks Define code or theme hooks used by your application. For more information about hooks, see https://invisionpower.com/4docs/advanced-usage/development/plugins-r71/. Modules - Admin Define modules and controllers used in the ACP for your application. Files and folders will be generated in your modules/admin directory. Recommended: Unless your application requires a large number of menu items (like Commerce or Pages), it is preferable to create a single admin module with all your controllers. Additionally, when creating the controller, you should set the "menu tab" field to "community" (or another appropriate existing tab). Modules - Front Defines modules and controllers used on the front end of your application. Files and folders will be generated in your modules/front directory. Settings Define all system settings used by your application. Typically, you will also need to create a settings controller in your admin module to allow the Administrator to modify these settings. (Unlike previous versions of IPS, there is no central location for Administrators to view and edit all system settings.) Tasks Any scheduled tasks run by your application. Files will be generated in your tasks directory. Versions Manage versions of your application. You can also use this tab to enter custom SQL queries that will be executed when upgrading to a specific version (queries that do NOT pertain to the tables in your Database Schema, for example, if you add a field to the groups table). If you require more complex processes to be run on upgrade, use this tab to create an upgrade.php file. Widgets Create widgets that can be used in the sidebar or in Pages. Widgets created here generally relate to content within your application. Files will be generated in your widgets directory. Modules & Controllers All pages that are accessible within the IPS suite are generated by modules and controllers. A module is a directory within an application and it contains several controllers. A controller is a class that accepts input from the browser, calls the source classes to handle business logic, and generates page output. Every action that can be performed by a user must have an associated method within a controller. The default method for a controller is manage. There are two kinds of modules: admin and front. Admin modules are accessible from within the ACP. Front modules are accessible from the public site. Create a front module and controller: Open the Developer Center for the IPS Tutorial application Click on the Modules - Front tab Press Add Module In the Module Key field, type hello Press Save From the menu to the right of the new module, click the “+” icon to add a controller In the Filename field, type hello Press Save The above steps will have generated a file in your application. You can find it under applications/ipstutorial/modules/front/hello/hello.php. A default controller contains the following: class _hello extends \IPS\Dispatcher\Controller { /** * Execute * * @return void */ public function execute() { parent::execute(); } /** * ... * * @return void */ protected function manage() { // This is the default method if no 'do' parameter is specified } // Create new methods with the same name as the 'do' parameter which should execute it } Key points: Your controller can be accessed by http://localhost/index.php?app=ipstutorial&module=hello&controller=hello. Substitute http://localhost/index.php for the root URL of your development environment. The controller extends \IPS\Dispatcher\Controller. This is the simplest controller class and handles basic routing. All controllers must have a manage method. This is the method that will be called if no action has been specified. Actions are called using the “do” query parameter. Example: http://localhost/index.php?app=ipstutorial&module=hello&controller=hello&do=sayhi will look for a method called sayhi http://localhost/index.php?app=ipstutorial&module=hello&controller=hello will use the default manage method Page Output Page output is handled using templates. All templates have a .phtml extension and are created in the dev/html folder of your application. The dev/html folder can contain 3 directories: admin - templates specific to the ACP front - templates specific to the public pages global - templates used by both the ACP and the public pages Within each subdirectory, you can create any number of directories. Each of those directories is called a “template group”. Creating a template Create a new folder called front under applications/ipstutorial/dev/html/front/ Create a new folder called hello under applications/ipstutorial/dev/html/front/hello Create a new file called hello.phtml under applications/ipstutorial/dev/html/front/hello Paste the following into your new hello.phtml file <ips:template parameters=""/> <div class="ipsType_center ipsType_large cHello">{lang="hello_world"}</div> Every template must begin with the <ips:template> tag, and it must be on its own line. Failure to include this line will generate an error. {lang="hello_world"} tells the suite to look for a language string with this key. You must have a corresponding language key defined within your application. Adding a language string Open applications/ipstutorial/dev/lang.php Current contents of the file: <?php $lang = array( '__app_ipstutorial' => "IPS Tutorial" ); Add another element to the array <?php $lang = array( '__app_ipstutorial' => "IPS Tutorial", 'hello_world' => "Hello World" ); The key is the language string referenced in your template (or elsewhere in your application). The value is the text that will be displayed on the screen. Language strings must be unique across the entire suite. When creating a new language string, you should try to use a prefix that will ensure it will be unique. Example: ipstutorial_hello_world. For more common language strings, you should also check that your key does not match an existing one within the IPS suite. Language strings can also be called from within a PHP class, as follows: \IPS\Member::loggedIn()->language()->addToStack( 'hello_world' ); We’ll also need one more language string for the module title. <?php $lang = array( '__app_ipstutorial' => "IPS Tutorial", 'module__ipstutorial_hello' => "Hi", 'hello_world' => "Hello World" ); All modules are automatically added to the breadcrumbs on the page. The language string key will be module__application_module. Calling the template The final step is to have the controller use the template to show output on the page. Open your hello.php controller and modify the manage method as follows: protected function manage() { \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'hello_world' ); \IPS\Output::i()->breadcrumb[] = array( null, \IPS\Member::loggedIn()->language()->addToStack( 'hello_world' ) ); \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'hello', 'ipstutorial', 'front' )->hello(); } Let’s examine the above code in detail. \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'hello_world' ); This sets the page title. You’ll notice that it uses the same language string we created previously for the template. You can create an additional language string in your lang.php file if you would like to use a different value for your page title. \IPS\Output::i()->breadcrumb[] = array( null, \IPS\Member::loggedIn()->language()->addToStack( 'hello_world' ) ); This adds a breadcrumb to the page. Each breadcrumb is an array with two elements. The first element is a URL or a null value to make the breadcrumb non-clickable. The second element is the title of the breadcrumb. \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'hello', 'ipstutorial', 'front' )->hello(); The final piece calls the template we created. The getTemplate method accepts 3 parameters: template group, application, and location. The template group is the name of the folder (dev/html/front/hello). The application is your application directory. The location can be admin, front, or global (depending on where your template is stored). Only the template group is required. If unspecified, the application will default to the current application, and the location will default to the current location (admin or front), depending on where your controller is located. Therefore, the same template can be called as follows: \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'hello' )->hello(); Testing You can now call your controller at http://localhost/index.php?app=ipstutorial&module=hello&controller=hello. You should see a page similar to this: Making it pretty You may wish to add custom CSS to improve the display of your page. All CSS is contained in the dev/css folder of your application. The dev/css folder can contain 3 directories: admin front global The directories above use the same logic as the directories under dev/html. Create a folder called front under applications/ipstutorial/dev/css Create a file called hello.css under applications/ipstutorial/dev/css/front Paste the following into your new hello.css file .cHello { font-size: 24px; color: red; } You’ll notice we added a new line to our method. protected function manage() { \IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'hello.css', 'ipstutorial', 'front' ) ); \IPS\Output::i()->title = \IPS\Member::loggedIn()->language()->addToStack( 'hello_world' ); \IPS\Output::i()->breadcrumb[] = array( null, \IPS\Member::loggedIn()->language()->addToStack( 'hello_world' ) ); \IPS\Output::i()->output = \IPS\Theme::i()->getTemplate( 'hello', 'ipstutorial', 'front' )->hello(); } \IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'hello.css', 'ipstutorial', 'front' ) ); The above adds our new CSS file to the list of CSS files that are already loaded. \IPS\Theme::i()->css() accepts 3 parameters: the name of the file, the application, and the location. The logic is similar to the HTML output, where the second and third parameters are optional. Therefore, the above is identical to \IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'hello.css' ) ); When you re-test your page, it should now look similar to this: Congratulations! You’ve created your first application.
  5. Daniel F replied to DawPi's post in a topic in Marketplace
    Hi, please see https://invisioncommunity.com/forums/topic/429557-error-codes/ This app contains an error which references to "S" which is reserved ( 2S163/4 and https://invisioncommunity.com/files/file/8001-dp42-guest-view-limits/ has the same issue;) There was a ticket today, where our staff was trying to locate the issue in our code, while it was caused by the plugin 🙂
  6. Yea, that's an issue in this plugin. We've mentioned several times that 3rd parties shouldn't remove/replace such huge template blocks because it's going to result in conflicts.
  7. You can use the richText template now for the ACP and Frontend 🙂
  8. According to your first 2 example links, it seems that this are all the profiles without any conten, which were removed.
  9. No, there’s no way to have custom links based on the language, but the menu names are translatable
  10. No idea, a clients error log had more then 50 pages with almost only this error, so I reported it.
  11. Daniel F replied to Michael.J's post in a topic in Marketplace
    Following error is being generated by the app:
  12. Following error is being generated by the app:
  13. Regarding the missing images: If you're seeing the spacer.png image, it means that lazy load is enabled, but probably not yet supported in the app. Did you implement the Lazy Load changes @TheJackal84 ? 🙂
  14. There's no need for a separate block, the topic feed has a filter for this. Same here:)
  15. We've improved this for a future release 🙂 I'm not going to mention any version yet😇, please pay attention to the dev change topics , but in the future you'll be able to use a generic template for this. {template="richText" group="global" app="core" location="global" params="the content which includes the media "} Template parameters: $value, $extraClasses=array(), $extraControllers=array(), $extraAttributes=array() and the template will include all the necessary code. This is also going to make it future proof, so if anything else changes, we'll only need to adjust this template 🙂
  16. Daniel F replied to Adriano Faria's post in a topic in Marketplace
    Guys, it's enough 🙂 Topic cleaned up. Please resolve your issues in private
  17. Invision Community 4.4 has introduced the new AdminCP Notification, which allow you to programmatically send a notification to the admin. To implement this within your custom application, create the new extension via the ACP Application Developer Center, and then you can send it using the following: \IPS\core\AdminNotification::send( 'demo', 'Test'); if you want to remove a notification, you can use following code: \IPS\core\AdminNotification::remove( 'demo', 'Test' ); Similar to the frontend notifications, the send method accepts the following additional parameters /** * Send Notification * * @param string $app Application key * @param string $extension Extension key * @param string|null $extra Any additional information which persists if the notification is resent * @param bool|null $resend If an existing notification exists, it will be bumped / resent * @param mixed $extraForEmail Any additional information specific to this instance which is used for the email but not saved * @param bool|\IPS\Member $bypassEmail If TRUE, no email will be sent, regardless of admin preferences - or if a member object, that admin will be skipped. Should only be used if the action is initiated by an admin making an email unnecessary * @return void */ public static function send( $app, $extension, $extra = NULL, $resend = TRUE, $extraForEmail = NULL, $bypassEmail = FALSE )
  18. Club Navbar IPS 4.4.0 provides a new method /** * Can be used by 3rd parties to add own club navigation tabs before they get sorted * * @param array $tabs Tabs * @param \IPS\Node\Model|NULL $container Container * @return array */ protected function _tabs( array $tabs, \IPS\Node\Model $container = NULL ) : array which allows hooks to add own tabs to club navigation bar. Changes to the queue/task system: We've created 3 new constants 'REBUILD_SLOW' => 50, // Number of items to be rebuit per-cycle for routines that take a while 'REBUILD_NORMAL' => 250, // Number of items to be rebuit per-cycle for most routines 'REBUILD_QUICK' => 500, // Number of items to be rebuit per-cycle for routines that are fast which should be used in your queue extensions depending on the task and the time it takes. Editor Buttons: It's now easier to add or remove buttons to the editor within the \IPS\Helpers\Form\Editor class. Additional plugins are handled via $defaultOptions['ipsPlugins'] New useful methods: Item::lastModificationDate() - The sitemap generation uses this method to get the last modification date. Email Templates Change: If your custom application includes email templates, please create also emailstats__key language strings for each email template. This language strings are used for the email statistics which were introduced in IPS 4.4.0 New Form Helper: Interval/TimeFrame Selector New Traits: Content\ItemTopic - implements the logic to allow content items to create, update and delete their topic ( pages app & downloads app) Core BC Breaks (warnings): Node\Model::canOnAny and Node\Model::can() got a new parameter Node\Model::modPermission 3rd parameter is required, there's no default value anymore Member::moderateNewContent got a new parameter Member::postRegistration got a new parameter Content\Item::followers() & containerFollowers - method signature changed, the last parameter was replaced Content\Item::can() , canComment ,canReview , canCommentReview, moderateNewItems, moderateNewComments, moderateNewReviews- got a new parameter $considerPostBeforeRegistering which is used to determine if the content was created by a guest public static function canOnAny( $permission, $member=NULL, $where = array(), $considerPostBeforeRegistering = TRUE ) Additional Information: ActiveRecord - new property $caches allow you to define datastore keys which will automatically be cleared after save&delete was called. There's no need to implement this logic anymore.. The \IPS\Helpers\Table\Content constructor got a new parameter for a callback function, which is executed at the end of the getRows method. This way you don't need to implement an own Content Table Helper just to prepare the data for the output. Most of the not extensible classes like share services, file storage engines, package types, payment gateways, license key generation methods, server types, converters, and widget types or classes which were required to be placed in a specific directory are extensible now...
  19. To support lazy loading in your content, first of all, the container of the image needs either to utilize the ipsLazyLoad module or if you're using the Lightbox, it's enough to have your content wrapped by an element utilizing the core.front.core.lightboxedImages controller. <div data-ipsLazyLoad> {{if settings.lazy_load_enabled}} <img src='{expression="\IPS\Text\Parser::blankImage()"}' data-src='{$coverPhoto->file->url}' class='ipsCoverPhoto_photo' data-action="toggleCoverPhoto" alt=''> {{else}} <img src='{$coverPhoto->file->url}' class='ipsCoverPhoto_photo' data-action="toggleCoverPhoto" alt=''> {{endif}} </div> If you are loading html content which could contain lazy loaded images via JS, you can call ips.utils.lazyLoad.loadContent( elem ); in your controller to load the elements, or alternatively ips.utils.lazyLoad.observe( elem ); to attach the lazy load observer to the new element. Since IPS 4.4.2 you can also use the richText template to parse your content. {template="richText" group="global" app="core" location="global" params="Content containing the lazy load images", array('ipsType_normal')"}
  20. There's a bug in the SendDirectNote hook. \IPS\Output::i()->redirect( \IPS\Http\Url::createFromString( $_SERVER['HTTP_REFERER'] ), 'sticky_note_sent' ); won't work for some people. https://stackoverflow.com/questions/5551094/http-referer-coming-back-with-null-key-does-not-exist-in-server You should use \IPS\Request::i()->referrer() which was introduced in 4.4 to get the referrer, but keep in mind that this method could still return NULL, so you'll need to take care of this before you send it to the createFromString method.
  21. Exactly 🙂
  22. Daniel F replied to Adriano Faria's post in a topic in Marketplace
    That's not an IPS core error.
  23. Daniel F replied to Faqole's post in a topic in Marketplace
    This application is broken and inserts duplicate entries into the deletion log which literally is going to break your board. If you're using this app, I would suggest to disable it until the author releases a new version.
  24. @TAMAN My merry Christmas weekend suggestion: Either update/delete such data when a forum is deleted, or wrap your code always into a try-catch block:) To make it easier for the admin to see what's going on, you could e.g. use IPS\Log::log() to log an error inside the catch block, or with 4.4 you could also use our new admin notification system ( ) to send a notification to the admin to notify him about the deleted node which is used in the footer..
  25. Daniel F replied to kmk's post in a topic in Feedback
    It's just the pages app with some custom templates and js code.