From 88f228b8e7437482acd818739a804d1b9b3b99fa Mon Sep 17 00:00:00 2001 From: QuackieMackie Date: Tue, 12 Aug 2025 03:56:58 +0100 Subject: [PATCH 1/6] Initial Commit --- docs/demo-tooltip-addon.md | 222 +++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+) create mode 100644 docs/demo-tooltip-addon.md diff --git a/docs/demo-tooltip-addon.md b/docs/demo-tooltip-addon.md new file mode 100644 index 0000000..645d1a6 --- /dev/null +++ b/docs/demo-tooltip-addon.md @@ -0,0 +1,222 @@ +# Demo/ToolTip +This is a step by step tutorial, explaining in detail how we'll be adding a new permission that will let you control what users / user groups will be able to see the pop up you get when hovering over someones name. + +## Creating the addon +To start off, just like the other addon Demo/Portal we will need to run a command and input a bit of data. +```sh title="Terminal" +php cmd.php xf-addon:create +``` + +!!! example "Terminal output" + **Enter an ID for this add-on:** Demo/ToolTip + + **Enter a title:** Demo - ToolTip + + **Enter a version ID:** This integer will be used for internal variable comparisons. + Each release of your addon should increase this number: 1000010 + + Version string set to: 1.0.0 Alpha + + **Does this add-on supersede a XenForo 1 add-on? (y/n)** n + + The addon.json file was successfully written out to /var/www/src/addons/Demo/ToolTip/addon.json + + **Does your add-on need a Setup file? (y/n)** y + + **Does your Setup need to support running multiple steps? (y/n)** y + + The Setup.php file was successfully written out to /var/www/src/addons/Demo/ToolTip/Setup.php + +After this has been done, we can do a couple of things to make our development a little easier. All we need to do is make sure this exists: +```php title="config.php" +$config['development']['enabled'] = true; +$config['development']['defaultAddOn'] = 'Demo/ToolTip'; +``` + +## Adding elements +Now the actual addon is created we'll need to create a few elements using the admin control panel. + +This is usually done throughout development, unless your very organised, but this addon was planned and documented, so we can just do it all at once. + +### Phrases +We're only going to need two actual phrases for this, the rest of them will be created when we define the permission. + +To create a phrase go onto your admin control panel, click on the side bar `Appearance` and then click on `Phrases`. The top right of your screen you will see a button called `Add phrase` click that, and you will see where we can input our phrase information. + +The phrases will be using are: + +```txt title="demo_tooltip_title" +Cannot Load +``` + +```txt title="demo_tooltip_text" +You lack the permission to view user tooltips. If you believe this be an error, please contact a site administrator. +``` + +Now you can notice in the phrase title I use the addon name, and sub name. This is a way of standardising your addons. This is a personal preference and up to you. + +### Permission Definition +Now to create the permission, we have to have this in our config.php `$config['development']['enabled'] = true;` otherwise this development tab will not appear in our admin control panel. + +Once again look at your side bar, and scroll down until you see `Development`, click on that and then click on `Permission definitions`. This will open up a screen showing every permission a user / user group can have. +I suggest taking a look to get an idea of what permissions exist already, but for now we only need to find the section titled `General permissions` on the right of that we need to click on the `Add permission` button. + +Now we need to input a bit of information about this permission. + +| Field | Value | Reason | +|------------------------|--------------------------|-----------------------------------| +| **Permission group** | general | Default group for general perms | +| **Permission ID** | viewProfileToolTip | Unique ID for this permission | +| **Title** | View Profile Tool Tip | Display name shown in UI | +| **Depends on permission ID** | *(empty)* | No dependency set | +| **Permission type** | Flag | Boolean flag type permission | +| **Interface group** | General permissions | Grouping for permission categories | +| **Display order** | 55 | Position in UI order | +| **Add-on** | Demo - ToolTip | The Addon it's being added to | + +### Template +Next we'll be creating the template. So first off, let's have a look at the `member_tooltip` template. To do this again go onto the side bar and click on the `Appearance` tab, next click on the `Templates` section. +You can see we have Public templates, Email templates, and Admim templates. Right now we're going to be adding a template that users will be able to see, so we'll be creating a public template. + +In the public tab you can filter (top right) for the text `member_tooltip`, when you click on it you'll be able to see the template that gets loaded every time someone hovers over a username. + +On the top right click `Add template`, ad the top of your area you'll see the Type, make sure that is on Public. +Next fill in the template with this: + +```txt title="Template name" +no_permission_member_tooltip +``` + +```txt title="Template context" +
{{ phrase('demo_tooltip_title') }}
+
+

{{ phrase('demo_tooltip_text') }}

+
+``` + +Looks simple, right? And it is that simple, we now have something we can load if the user lacks permission to view member tool tips. + +## Modifying the controller +Actions on the site, can be found by looking for something called a controller, if you want to learn more about this I'd suggest looking at [Controller Basics](controller-basics.md). + +First off head into your IDE, we're going to have to actually code something now. But have no fear! This will be easy. + +In the root of your project so `src/addons/Demo/ToolTip` we'll need to create a few folders with the goal of mirroring xenforo a little. +We want our project to end up looking like this: +```title="Folder structure" +├── Setup.php +├── XF +│ └── Pub +│ └── Controller +│ └── MemberController.php +├── _output +│ ├── permissions +│ │ ├── _metadata.json +│ │ └── general-viewProfileToolTip.json +│ └── phrases +│ ├── _metadata.json +│ ├── permission.general_viewProfileToolTip.txt +│ ├── demo_tooltip_text.txt +│ └── demo_tooltip_title.txt +└── addon.json +``` +As you can see Add the folders `XF/Pub/Controller` Now this is not required, but I find it easier to work with. + +Now entering our `MemberController.php` we want to start off by doing a little bit of set up: +```php +assertNotEmbeddedImageRequest(); + + $user = $this->assertViewableUser($params->user_id, [], true); + + $viewParams = [ + 'user' => $user, + ]; + + return $this->view('XF:Member\Tooltip', 'member_tooltip', $viewParams); +} +``` + +Let's go back to our MemberController and create something similar +```php +public function actionTooltip(ParameterBag $params): View +{ + $this->assertNotEmbeddedImageRequest(); + + // Fetch the current visitor + $visitor = XF::visitor(); + + // Perform a check on that visitor to see if they have the permission we defined earlier + $hasPermission = $visitor->hasPermission('general', 'viewProfileToolTip'); + + if ($hasPermission) { + // If the visitor does have permission to view the tool tip. + // We run the original logic, as it works great as is. + $user = $this->assertViewableUser($params->user_id, [], true); + + $viewParams = [ + 'user' => $user, + ]; + + return $this->view('XF:Member\Tooltip', 'member_tooltip', $viewParams); + } else { + // If the visitor doesn't have permission, this is where we change what happens. + + // This loads in a different template. + // Parameter1 = $viewClass, Parameter2 = $templateName, Parameter3 = $params + // 1. We still need to load it as a Tooltip, + // 2. We are changing the template to the template we created earlier, + // 3. We don't need to pass the user data, so we just send an empty array instead. + return $this->view('XF:Member\Tooltip', 'no_permission_member_tooltip', []); + } +} +``` + +## Finial element + +Finally most of the addon is complete. All that is left is for us to go back into the admin control panel, head on down to `Development`, then into `Class extensions`. + +At the top right of your screen you'll see `Add class extension`, click that. Your going to want to fill in this class extension with: +```title="Base class name" +XF\Pub\Controller\MemberController +``` + +```title="Extension class name" +Demo\ToolTip\XF\Pub\Controller\MemberController +``` + +The rest of it can be left as is, now just save it. + +## Checking it's working +One final time, head into your admin control panel. Click on `Groups & Permissions` then onto `User group permissions`. We want to set the `Guest` group to have `View Profile Tool Tip` set to `No`. Then we want to go into `Registered` and change `View Profile Tool Tip` to `Yes` for them. + +Now when you go onto your site, if your logged in you should have no problem viewing user profile tooltips. And if you log out of your account and try again, you should see your template pop up instead. + +Congratulations, you've no created an addon that uses; permissions, templates, phrases, and class extensions. :) From effebf808231fede3d3d06529115fd8585243bd4 Mon Sep 17 00:00:00 2001 From: QuackieMackie Date: Tue, 12 Aug 2025 17:40:27 +0100 Subject: [PATCH 2/6] Made fixes to language, and overall just improved upon my work from this morning. --- docs/demo-tooltip-addon.md | 162 ++++++++++++++++------ static/files/Demo-ToolTip-1.0.0 Alpha.zip | Bin 0 -> 21560 bytes 2 files changed, 121 insertions(+), 41 deletions(-) create mode 100644 static/files/Demo-ToolTip-1.0.0 Alpha.zip diff --git a/docs/demo-tooltip-addon.md b/docs/demo-tooltip-addon.md index 645d1a6..b9c0440 100644 --- a/docs/demo-tooltip-addon.md +++ b/docs/demo-tooltip-addon.md @@ -1,8 +1,8 @@ # Demo/ToolTip -This is a step by step tutorial, explaining in detail how we'll be adding a new permission that will let you control what users / user groups will be able to see the pop up you get when hovering over someones name. +This step-by-step tutorial explains how to add a custom permission that controls which users and user groups can view the tooltip popup when hovering over usernames. -## Creating the addon -To start off, just like the other addon Demo/Portal we will need to run a command and input a bit of data. +## Creating the add-on +To begin, similar to the Demo/Portal add-on, we'll run a command and provide some basic information. ```sh title="Terminal" php cmd.php xf-addon:create ``` @@ -34,14 +34,15 @@ $config['development']['defaultAddOn'] = 'Demo/ToolTip'; ``` ## Adding elements -Now the actual addon is created we'll need to create a few elements using the admin control panel. - -This is usually done throughout development, unless your very organised, but this addon was planned and documented, so we can just do it all at once. +With the add-on framework in place, we'll now create several elements through the admin control panel. +This is usually done throughout development, but we can add everything at once since this add-on was planned beforehand. ### Phrases We're only going to need two actual phrases for this, the rest of them will be created when we define the permission. -To create a phrase go onto your admin control panel, click on the side bar `Appearance` and then click on `Phrases`. The top right of your screen you will see a button called `Add phrase` click that, and you will see where we can input our phrase information. +To create a phrase go onto your admin control panel, click on the sidebar `Appearance` and then click on `Phrases`. +The top right of your screen you will see a button called `Add phrase` click that, +and you will see where we can input our phrase information. The phrases will be using are: @@ -53,35 +54,45 @@ Cannot Load You lack the permission to view user tooltips. If you believe this be an error, please contact a site administrator. ``` -Now you can notice in the phrase title I use the addon name, and sub name. This is a way of standardising your addons. This is a personal preference and up to you. +Now you can notice in the phrase title I use the add-on name and sub name. +This is a way of standardising your add-ons. +This is a personal preference and up to you. ### Permission Definition -Now to create the permission, we have to have this in our config.php `$config['development']['enabled'] = true;` otherwise this development tab will not appear in our admin control panel. +To create the permission, ensure that `$config['development']['enabled'] = true;` is set in your config.php file, +otherwise the Development tab will not appear in your admin control panel. -Once again look at your side bar, and scroll down until you see `Development`, click on that and then click on `Permission definitions`. This will open up a screen showing every permission a user / user group can have. -I suggest taking a look to get an idea of what permissions exist already, but for now we only need to find the section titled `General permissions` on the right of that we need to click on the `Add permission` button. +Once again look at your sidebar, and scroll down until you see `Development`, +click on that and then click on `Permission definitions`. +This will open up a screen showing every permission a user / user group can have. +I suggest taking a look to get an idea of what permissions exist already, +but for now we only need to find the section titled `General permissions` on the right of that we need to click on the `Add permission` button. Now we need to input a bit of information about this permission. -| Field | Value | Reason | -|------------------------|--------------------------|-----------------------------------| -| **Permission group** | general | Default group for general perms | -| **Permission ID** | viewProfileToolTip | Unique ID for this permission | -| **Title** | View Profile Tool Tip | Display name shown in UI | -| **Depends on permission ID** | *(empty)* | No dependency set | -| **Permission type** | Flag | Boolean flag type permission | -| **Interface group** | General permissions | Grouping for permission categories | -| **Display order** | 55 | Position in UI order | -| **Add-on** | Demo - ToolTip | The Addon it's being added to | +| Field | Value | Reason | +|------------------------------|-----------------------|------------------------------------| +| **Permission group** | general | Default group for general perms | +| **Permission ID** | viewProfileToolTip | Unique ID for this permission | +| **Title** | View Profile Tool Tip | Display name shown in UI | +| **Depends on permission ID** | *(empty)* | No dependency set | +| **Permission type** | Flag | Boolean flag type permission | +| **Interface group** | General permissions | Grouping for permission categories | +| **Display order** | 55 | Position in UI order | +| **Add-on** | Demo - ToolTip | The add-on it's being added to | ### Template -Next we'll be creating the template. So first off, let's have a look at the `member_tooltip` template. To do this again go onto the side bar and click on the `Appearance` tab, next click on the `Templates` section. -You can see we have Public templates, Email templates, and Admim templates. Right now we're going to be adding a template that users will be able to see, so we'll be creating a public template. +Next, we'll create our custom template. +First, let's examine the existing `member_tooltip` template for reference. +To do this again go onto the sidebar and click on the `Appearance` tab, next click on the `Templates` section. +You can see we have Public templates, Email templates, and Admin templates. +Right now we're going to be adding a template that users will be able to see, so we'll be creating a public template. -In the public tab you can filter (top right) for the text `member_tooltip`, when you click on it you'll be able to see the template that gets loaded every time someone hovers over a username. +In the public tab you can filter (top right) for the text `member_tooltip`, when you click on it, +you'll be able to see the template that gets loaded every time someone hovers over a username. -On the top right click `Add template`, ad the top of your area you'll see the Type, make sure that is on Public. -Next fill in the template with this: +On the top right click `Add template`, at the top of your area you'll see the Type, make sure that is on Public. +Next, fill in the template with this: ```txt title="Template name" no_permission_member_tooltip @@ -94,12 +105,14 @@ no_permission_member_tooltip ``` -Looks simple, right? And it is that simple, we now have something we can load if the user lacks permission to view member tool tips. +Simple, isn't it? +With this template in place, we now have content to display when users lack permission to view member tooltips. ## Modifying the controller -Actions on the site, can be found by looking for something called a controller, if you want to learn more about this I'd suggest looking at [Controller Basics](controller-basics.md). +Site actions are managed through controllers. +For more information on how controllers work, refer to the [Controller Basics](controller-basics.md) page. -First off head into your IDE, we're going to have to actually code something now. But have no fear! This will be easy. +Open your IDE. It's time to write some code. Don't worry, this part is straight forward as well! In the root of your project so `src/addons/Demo/ToolTip` we'll need to create a few folders with the goal of mirroring xenforo a little. We want our project to end up looking like this: @@ -122,7 +135,7 @@ We want our project to end up looking like this: ``` As you can see Add the folders `XF/Pub/Controller` Now this is not required, but I find it easier to work with. -Now entering our `MemberController.php` we want to start off by doing a little bit of set up: +Now entering our `MemberController.php` we want to start off by doing a little bit of set-up: ```php hasPermission('general', 'viewProfileToolTip'); if ($hasPermission) { @@ -191,19 +204,48 @@ public function actionTooltip(ParameterBag $params): View // This loads in a different template. // Parameter1 = $viewClass, Parameter2 = $templateName, Parameter3 = $params - // 1. We still need to load it as a Tooltip, - // 2. We are changing the template to the template we created earlier, + // 1. We still need to load it as a Tooltip. + // 2. We are changing the template to the template we created earlier. // 3. We don't need to pass the user data, so we just send an empty array instead. return $this->view('XF:Member\Tooltip', 'no_permission_member_tooltip', []); } } ``` -## Finial element +## Customising the addon.json +When we created our add-on, XenForo automatically generated a basic addon.json file for us. +This file contains information about our add-on and is used by XenForo to identify and display information about it in the Admin control panel. + +Let's modify this file to include information that will make our add-on more professional and user-friendly. +Open the file located at src/addons/Demo/ToolTip/addon.json in your IDE: + +```json title="Default addon.json" +{ + "legacy_addon_id": "", + "title": "Demo - ToolTip", + "description": "", + "version_id": 1000010, + "version_string": "1.0.0 Alpha", + "dev": "", + "dev_url": "", + "faq_url": "", + "support_url": "", + "extra_urls": [], + "require": [], + "icon": "" +} +``` -Finally most of the addon is complete. All that is left is for us to go back into the admin control panel, head on down to `Development`, then into `Class extensions`. +Here's what you need to know when customising this file [add-on structure properties](add-on-structure.md/#properties). -At the top right of your screen you'll see `Add class extension`, click that. Your going to want to fill in this class extension with: +## Registering the class extension + +Our add-on is nearly complete. +All that is left is for us to go back into the admin control panel, +head on down to `Development`, then into `Class extensions`. + +At the top right of your screen you’ll see `Add class extension`, click that. +You’re going to want to fill in this class extension with: ```title="Base class name" XF\Pub\Controller\MemberController ``` @@ -214,9 +256,47 @@ Demo\ToolTip\XF\Pub\Controller\MemberController The rest of it can be left as is, now just save it. -## Checking it's working -One final time, head into your admin control panel. Click on `Groups & Permissions` then onto `User group permissions`. We want to set the `Guest` group to have `View Profile Tool Tip` set to `No`. Then we want to go into `Registered` and change `View Profile Tool Tip` to `Yes` for them. +## Checking the add-on works +One final time, head into your admin control panel. +Click `Groups & Permissions` then onto `User group permissions`. +We want to set the `Guest` group to have `View Profile Tool Tip` set to `No`. +Then we want to go into `Registered` and change `View Profile Tool Tip` to `Yes` for them. + +Now when you go onto your site, if you’re logged in, you should have no problem viewing user profile tooltips. +And if you log out of your account and try again, you should see your template pop up instead. + +## Building the add-on +Now that your add-on is fully functional, let's package it for distribution. +To build a release ZIP file that you can share or install on other XenForo installations, +you need to run the following command: + +```sh title="Terminal" +php cmd.php xf-addon:build-release Demo/ToolTip +``` + +!!! example "Terminal output" + Performing add-on export. + + Exporting data for Demo - ToolTip to /var/www/html/src/addons/Demo/ToolTip/_data. + 27/27 [============================] 100% + Written successfully. + Attempting to validate addon.json file... + JSON file validates successfully! + + Building release ZIP. + + Writing release ZIP to /var/www/html/src/addons/Demo/ToolTip/_releases. + + Release written successfully. + +### What Just Happened? +This command performs several important tasks: + +1. Exports all your add-on data to the _data directory +2. Validates your add-on configuration in addon.json +3. Creates a ZIP file in the _releases directory that contains everything needed to install your add-on -Now when you go onto your site, if your logged in you should have no problem viewing user profile tooltips. And if you log out of your account and try again, you should see your template pop up instead. +Congratulations on completing your XenForo add-on from start to finish! +You have learned how to create permissions, templates, phrases, and extend classes. -Congratulations, you've no created an addon that uses; permissions, templates, phrases, and class extensions. :) +You are welcome to download a copy of the completed add-on here: [Demo-ToolTip-1.0.0 Alpha.zip](files/Demo-ToolTip-1.0.0 Alpha.zip). diff --git a/static/files/Demo-ToolTip-1.0.0 Alpha.zip b/static/files/Demo-ToolTip-1.0.0 Alpha.zip new file mode 100644 index 0000000000000000000000000000000000000000..5182179dfbc090b8c5504688aa17739ce4d7a374 GIT binary patch literal 21560 zcmcIs2RIe{_cya6q)7I5xgj%|8Q0#MYjb5>J0l~J6&YFCBO%F1W$$bm5kf|hl3610 zzxRC`m+qDK{l7oY^L6p`oX#ynA8~1any~%v9Ph66P%n}YgQXJ$t zF*R{q5YWXnrRvvSP3n~!WO7G0zxb2%4W0Ds@i)LN?Z+veGz>=M*w%V-g>Y4p5Sf{7 zNPF?4%e<*-dfKZcQsUcPKa17WyZ%Z$@>& z%qEc;>D8SRC(ot3#@Q&lz;K6$^876oDQo;|UzWw7aZ-(+gkSjxjJt56MKXdURjuVL zJOt(~E%Y&!q^w_7b6;ny{>Wg^e_2(e)~wk(&m|?PfJTp8v+QIJw}MTSKje)8&vR9b z47C>DWul4OLZOiC*XTukLmEAVmFuoAS(?_d;ik^qa=UZ`W-8#Psqknz7;q#9P1Tb{ z8ZgLX@1QhtB+}H}&HsVKgCR(ZLZY;jqnnG9y}gwSQsGC7Z@xbZSGIC6w{rP~c9bAU z(^6L*mmu_8E?L3U2qzB@5ImiB{un87CVnYVSmt7iP{++KV-HVA0m?X3*E$^Nd3_tiPl||(F?ru1c=ik$B-YzFkLzs3Wk;;|E?2Np+JOiPs_E++ zALQ;Obg;8W$C#m>)y?Gf<*u}SO(b;b7W=$`GmMVJ$`q95s7~yH_RI>0qgq$|k=TOY#ML?&s;nh<$gkB1szFRCG`s$1w3| z0BmmtaG2s{r`3zhY2?%m-}+sC*H0I6riNHT=E5d0?s?$U*<&Y_MDO`L?CfWV z;OGtRU5I#-6j63bxp+dxf6lNIcT5Fz1~*Je^ZsU|g*wNyvs3nXt0-h6w20H>>qFPn z;dQ&^skq|#3l?C$QsdWgctx#V1?0B5?sS1X{5p8-(h}oC7iIH5$(W6&Z1R}!AK zfxdnFa8hji3B}s|5GBIL-pzS)8D}tG#424sMK9EBThBQU>2t@B!n9hwY;Mt-;=L#u zZn@^)*>63me5EcwXFjpccd;b8{}~uwFSJ=rILk25(8Q1ZD2?!XaWEgr4yFv)(#*{a zX%6;(Ut@ZIE?3BE?Qc2ww?H!sH;4zs%?s@6?%-hN;sv&}vW7T9+#pVluH07~?2#2> zIN*;_URu)Lqt2$t#nIc{SFX)F#HXeq-=o;8+R?4}Set_jH26rZ?D1?FNQt`x&;=-n z1akNEC<6*3RYA&K-CY3mMULUevly^N0teS2VcbX_<_kI4K)q}ciz zu`z>d|KBR#(bFB#rwHg$QU#!My!fFobbz={6sGKjf3Gmq%EbZV>iR!X7%0!x*#kJn z{!`x(X?icXu7~RjK;>W$D;GD2E5y+T40Uq-UxWyHA$tel82+4ReE7Q{u#fj=1!S{ zFb(++)$+HM_U}YAHwRldS^md5Dum&8Q!Q%`*P_I8I(!&C_QHJ>z?B)fv0$W3@>@ELO zwL!gooS+`gFkk^d{-$b|QV)pzXWc1Mu2z3n#8oI&Al7u0Lzzp9JeoqdBp7RWi< zsumuYX23%|ilT1YTG>OvP&1qVw$60O_ppZo<&{)_)opED>jZARq&bNK7v0(NyX z`)~8AL%By;fh!!y4Fdd{X;VE7Q(>4d;o72(P!#_B^WNy+%y-9+UD3dgNvG|O(154@ z;maTma(6mG58ZnHD-D5c=p1Z6v&G`{*9!Oo$a|;{nGRDAY~$kO4*gH_y92Ids4B1% z$n{Ir2c?V*@aYyhR8*v)|G%eS(2~v25ifRmaQW zB<5FQS=ZPmrZzq;e!l3X2jYE}x#Hzdr*=AL`ZYOsd2Q`Ohj5V?rPOG3NBn?@8=A*e zW@3*C;Ge}NU0NNZ+3KutC*|^4wAi?qpV3jns$pB}flF;oS|qn!zobHi)hz5)ORP>9 z)>PQEMqp$TdS?a`zTB~SD`!N*OrJm0d|u=;^~-!P1Xh_{tj#Q}{s;5M{(X-f-q+0u z;!;plQn`6x5?>HR$jQPifDhC;iy|GMwk~F_M=OANw-6wmb`6B;q$5@87kc{!?t?XKozo6LIBoh2~%Iw%a_XW_sWfw9n_SX$8!_!p4u!vdq0+3 zf$y`y$*JRPBVrr<0 z`AQf{%)gvyvOQNOU@s$xK_v=GdW@-$&t&kD`G#~%vA@)}JHXEm@ShA0mo<>R|LioS z_+>7XB2B=(rlEW`ickmrUiKFX&4}4WbtsRQJtgD-sy%iYh0z1pVPGUz3i=*!2 z*trY3K{tVHov;%PM~BicjU7eWg)YLh{a1&^eHwfHFY*sj?SjYyxmPaE>m~)$UE)x0 z(;<%qH!BCIz1b1N!TpxFYO@4k>!u(6Y~HzCWxs3V!{aNmL*oGc;M5R1RAY>u=}9XXysJzVV|0O)2PwnCm23u^+}i(mH% z#YDH&Bw@P42Ws8fk?ZaWv9z&rJIY1bzuB#@_bGu?xx#*2j}`t(M1O||Dex^mJQ-0d zjiPjXSNe|^H~$Znf$hLv0D2+d=T1vIiL!P7^%zX^-)=fj{^n&^4TieAA-(H_s|SCY z>w%5GeSl0P3o4NZF9Qz6IQ%~K>X9+@WVv8(GhDykHnmN z{L*ERm{g9Uoui+UlDwavioCU?5+Uequ1+pXVnS}){HZ)N>|%04qD<1T4(4R50*RQ| z>;bI@2C#6%!96doDQXX!jWXCk9iHcp>^9g%lbad*()%A+iz_%0Fu-K|(>ey@@5V{g zz^tls{M)ENZnIC``mI}D3Oe{C1Puw6OcXX~GV$Fv2S|Im2VzNyVwDI1np~u0aR6mP zr5B!GZV&1G}eo=x|$k*je`MV0NY*YU}T*_&u_J-bR6KVSCe~JasulHQK>8 zcOiZ2nz-IwSzdvSROb2oxs@Q_cDi$~lmO_@1f21M20X!KO&;>W+yi^x>NmD2wk70K znjAGVRck`>_=I>H3zhirv4Nvx9?F@d*M}O|MkKsiU5x9NX>-JQ+Pm&Q2;@%*OHnLk zig;#%Z`?tu#iI8V><1#nz@tv3H6nc36Xcn>-B8>Lw9rm*!ey57!k7#19-anpx5bm#$VN80;gZWu*)12-NR5*hSDB2xs`gsz+6sHsuK4(_ zq~_e>Y~(C_T)rm$*YQ*YcW+giYBIUw2l3p zg@9=R2Hx)c>G#7U#2WltHzTlL=80@#u(`aRn&6Y^amIjq^9|7hMKhTH!eIk-asrQH z?!U>)jiH*M>=x>YvhJa^fb5-$?$n`MJ3Fbjx-n|+&+Lf8N>ixR!3l1cRxxpcYysyQqsOvMH;ldOK41^eN* zAo+c-|078LK3)Ak0_69@=K;}{u*wd0gLR0wL7-qaSmJZLU2#M9sD`-k5_L5a1xXNI z>eso8c8QifFh`#yytT|^G=y#9*|YqT`q7)*OPBmYLG|aQ9O#Im*CH+~V81Wm)2W&K z@}jhylXf^)J%I4}gm2@Ac)FCE@d+f?tv}5UWW{hp>URICUyPbmO2#lxx&8DTvgrT) z$?#C)Aa3?nN3qUTrMs&OsJ_yns`U5k4q4#&W+Ip-1cz!Pi!wOB&*HC~niUzk*>zl4ylzk!+v3z{a$ezg@AOXr{Tb{gAp<&4G)7#MCNitu(L`CQfRj^QI zAAWfALy)d8RNv>HL#0f&wq#^~ADMZB*g&uRGQ|uI}0S-#anM-GIZG{AkRj zD7AIVgrLJmB@fz=y90bEDHgo;B`eJ=I8wR~ojXH#i)1>~`q{(UiGo2b^vqjxb?=2_ zy#!ZOj*rdceRUq2sQ=5a0u!yTr(izS{ds7I{qkEP|NeCL-LF57YDY|EWWrHy8h;6g zx|`cWERKkQETiO5#qe(!j!xiT@eB(Wcz4W?I>K%1hWue3UPFG2a!?0AQ@$4j;I7nG z=BK-wc(_lh6&7B6AqFS*narHGDekFREVRWl-jY*6#$E#a!FrWt-w%hs&F4SM6sw4?<4ttr*qh(NLmo9M8g4`96GS=W(rz)>>v$JZMGh-PlwNwd3aDRJj`$991 zCB<+8PYXA7ciAX*b+eG}8oIRqBX!peM!WP+^T+T86>d16sE$W-p?N1z?2@@I0KC3@ zk6F&M=CAT9zXCWG1hc&Ir}eNOev9Vcy8gf}R`yo#>%RX-g#BK#e+u1q$l&2V$9;}Y z(jIDS#_bLHW4~RoKAvd&_!%0X(K29gZab;P&3I=0GOGxZHp^o{JQmjWcrl?Q_#h+w zGTj6y`vvx|1~IizMx#p%yE)ZLVk5P(dwt7Lzl`Op>6@wRbyJ>`>kF6TV#)*LC4D4l z=qpaiF+d9?=|~n% z1@m4WmJcWq^07+ z!qpR9ZynOScS$=06L5~lhtHKNPHg0Ns-GW7$f}+)*txW>AiNOWXm4~T$m{CcTk{}a z|D3ch%Z(DIYSiR=v`kHu*Fr3A;Q}ZET`1NiMA9^x_Ga9JECd|cRzRU)>#I#^4r=GF zm#1N5aQ5nGMX7>fw#lDU+?TH%&FTM^5TWs9S2pftfm|ZD~gXRo)u3`8n^A zDGVs=;}GTX9>EWB-&368{Dt2jercwVT8Skf-@EJSpBv1DSHL8sdAd!q@J!0%Amj5 z4Fr>RDb~MRNxH-j!Zo23dU7Lg(nRH>cMci;2l5QxkGShkHq)*QWNkK|7;#L@-3~6W z{Zina#_^dW(btbxNOrosWu!&r2@^+B>kf|~M9paFSv$YhD1Rr%hA`(4WddJ^YFYaI z*p{;B072D9j|#FL0qW}eEj>g;nW(++q5@5w)u`3^zU53L$OzVT>C3s{S23D;K&i2A zHZef`dp@hwqK`SQhT@6x0ak6c13ec{h=oI2m|xRU7`{w84yT)%E=93#)x=K6T|+nHVpRf2dX=T6uZYrfJR z_WC$Owh@hH=zHO%+u*GQT-T5)`VVzC06fP}+^@W{x~ON7IFLbk@8PTiy59}-!0N^{ zXA)K{3LMWiABiD>Y1$8ueGAE`n0VP&s@3T=7$#M1eF(|F%5CS#C@j1P|~(s%7SYp}|B-j^f^Z)X@AzI1&uwA^`BV_~9JVc3;y_}IFS>eC(< ze8LKz3N6Y-b^|uB7LETP*a7HAxy90wY&6Db=Mg}|!Zc#S<#CO(<=vU}XN{a*AKPx@ z$?%Ye-EFOl(|IAskI#zFC&y0qbiz#a9%k^ScyES8L0ZDo}O0udV!zc zs%_ofS*nNo3X_(?e|fFB zX?-P_D`G4*Iz=uy%>KFb#|yo?HutW@pGZ6PnPxRLqH0#tF;lhGj ziIc25xK6irN^daQ?QL8QeQ-j-n;-TBs3MR=-XpD>P=BKe|A*+yZ9In^rg25egS1#f$L zW~w0L&g`cq4G8NgW?XV9Vhp@J!Rr^vFGmw=;s82@r>}8yQTo<2xP)J*tC}^0-T1@E9da{j#(YE5F_nVa zwNe}XNF|Xd%i9V!h%UaG|7!Jo($kN(mhaxW3~OGPH}~Fq@90VHVp&G2(q{dU30b0B zP01dseT2lrJZ7}-O=RN}?yuHR8iBv989423X7;!B=|1=Z=#7@rX{|Tbr%Vxzg?>m2 z4#KT4JZTIG=_=(C+SFk2>)p9Kk2A@WD@9p)Pnl@$^x$HiF%wCIRE`W*CFAGg;T&!SZ_UYht2+8yD( z;urVs>!S_M(rU9do~+e)Ij3+liojXk$KtROsHZT05g0q&4O#a&hNT`o!Xm#gAW9X&>q&?c5UI z>zd_{%pV!Ad@AUfH$>!lNX9=OwTN#}RO#QZQvK)eM+*U-R(-{1$-ge@BjpbXC?c6Mo z)_P+#!_%o0ANP>tvm)#!4U}mUIV>0JhWA9kJ*u16l|{4A1)}Lj1|HJR6VT$6@IKh; zlf`{*ML4~aaK}77L326*8ZNf>4W#yQw4WnFp3lwnoYKn+-b}?~EIC#TG5AVln`&9% zRq~GVeM_(3*)*RjKBh(BWmv68`|92!|5jm^$u`q({WNc>w6SbnXhmuW$5bZjBn-(d z+IPBoM9*Zl3}3u4Qq7K?xKNx>Opte1FLA6eoj`E3(^Y03Px}mItctg}V*PX}K%;BHeLR8pp5R(tzVDw@GgqCyKKKnR=KD=Vd$OoV^%%S_D)5oS;UTWmZF*DZ;Ncb+%hq? zOzeST76k^AaSvu_WXkO|Pj@<3;xZ^URhvRU#A{TwL{3V#R_{r6$?5m+s!}51!O470a1H&s}R? zl9FQIfR z-e2~{^F0P8F;!DhffDL%eobbXZVPFNflf-4s3s5Fyj=w(o8c<9YwJg0K@{#@1r2$* zHG*iDJ8B6pSGc*#S@PcZsg^lAVt=1ql)3o%;|imdC9GW0w)Gaj>yojd1`7Z|qVlF) zavGt0sd~FW%pB(Vd?U<7Rrk;Hs#v+tri|u3o;v&Jl+bX!CHTaL^KplxlWz)wymMetUXd zIi+vQNRdIeMCP4xpUcFf4elZ;suJqu*TW}cc{XK=JAH+^a%Yvugq122Mk{x|W_=bT z5N>V2B;ei%rxLtGO;n@wC`znv)&p8ocyVTl@7BUw^UF?_(#;L$detSVE=KlfGD>UH ztc?h-dW*A^=uGlFVaslPQ!J16RQ)a%UPPGn^b%CN)KmC;-_)C~sT^_sP9K(TrXaxv z1I>-}QHSF9Pmk}0M={2VGKxlQPJVu3Vo4JkHrLS4wf@91n9}_#GjGgw`gI6}ZK0Av zGqaLC5roa8k?CEJipNlmw`(AW%F^s^#PVs`2glCKJ3ntLSS?fkS}8dt9644W-qMEM z{eXAtR5`cxh0C_gmUlmVn{c(=xaW>04={d=({t{Qs`a>EBi0*w9@b}HB~rE%gx}W~ z$(PIx$SfJglP-tUNH*2hZ?|DTFHwoG(Th&~SZ__;Ywa;9LzrLZNVQv(>7lDz^5&YX zmx1j-{)J$_6GQ{AutBU=Ka^2?M)x`lx@S{(SkWZR$CmO_?eaumd z^fC7n*XdH7NDU8bZf6mZimg$5Jax?GxEXsV|JS6!scgUG#f%VMmcF6OI;*D!T*Wi+ zctM0u$gm0=GHo~uKGY<_6+86833~tiVD5`ZmKmM}C9X0~jxKFrEp$`&gm-nl0cO zYhYHoec~GHEsT4Xq-+}<{!$}Y188qR7(KYc{pQRh)c3?l8;aTeq#|H{W|qO|p~hat zU?e%qcAE4#PrNu6t)sqsz^)vfMdsLTDqJQs1s|+yrwcPkw*xLoJc^QVv+vsjRby&k zSP5cS^`&Q=oDMLOpj^6f?`1WoI*~k@Ry!^h`15YA$uVCr1~U*to1A|Y<1~~`;?s?Q z-N3i36?Ak&Y6JAopA7D%HejZ5XUa>Pj>&D7#}YxcBwhqJ+?ILFNpwseja&;CYi2{7 zwFE7nh%JUBiE6=L>Kyt2+9x~=<=wi8dnX(4FlnaAR%}jtcxDn?qS5s3k#t1vW#nvg zS-^JNds%z$HYD$!rLA%@Irh5rf*DC-QmF8CoEeO01KcN{sQ2=N68-O-4O1>3^fcAA zTKc?#ap!gLQxB83j?o>D@dmwYk^=N`DC(~3`?ttkqTF$EqmgwWzq0I51QYVa} z+1nTdrxI2Cey9sYR?g8T2D;gvWv?)(MQY=z<$%FEV-k~B~~iBvWF44 z``5$g#wW^;He_gM8eH(JQ*;b+OjH!+)9_oxzrOY);UCBe&Ddz@e-oL1i8@F&BSJ$I zCH+GbN@6oiB>bBBhju@1x)Djgrw~L|21Xqec?iK7g>XcgEyX_JA?V*t|Di8x7V!bu zaHk!l){-E|-jj5Oy+{1z)*rHw(RPt|_@GqseNyX@NJUEDMI!m&+|llnd;;@#ec_US zHJ|)`w|u}UKV}n=r^tr@QW@y@XOM#(E=YSE4gkYvm7^y*jU}m9!K_o9R?z4lB1S!lPsZ}U|5D7^8?U_Ih^ao}X3K&Ep5zRh(uAM+? z&tcpq6c~sMAf|m7^rVMi9M))$0tu09vp-$Ckt6+DFp&3cqrgF=!|?92s0+5~MUt++ zaE?agL4k`%3)w$gF|hqLGTcL`Hz+U=$sK3+*@jMm6yp%O2?_{AHpc!Eo`D=<9|Hpw zX9NWpB7I{2>aGrJfiBgL{@EA9xTO*smgBRR&5?qcGz)tUvee|2Mt<2i*1J%!b&Petw?` zUT2SL!XG-WP#`0=Ywr&@D;gBYN9ck-0ER5!5EuA8$#z;4V82!oB;8d9V19TLv1wXj zpEp_QjsWvd`@&IZf!N~=+@}Qv{SmbIXVZzy!-y-{p5zirP*ly-DC|P)LEgU+kY_+; z*LMiZBQ;f{z(wpf-hT_g%=nLRQT98d07mQ`mfbgz<$nVH6}|towHbvji2b(v4^1Xa ze{jP8KcEoL(|eMY%qReVF71D;;K-tO|7t Date: Sat, 7 Feb 2026 00:25:36 +0000 Subject: [PATCH 3/6] Update: Added the sidebar structure, organised the md files showing add-on examples, and changed mkdocs admonitions to Docusaurus admonitions. --- .../add-on-examples}/demo-tooltip-addon.md | 13 ++++++++++--- .../lets-build-an-add-on.md | 16 ++++++++-------- sidebars.ts | 9 ++++++++- 3 files changed, 26 insertions(+), 12 deletions(-) rename docs/{ => devs/add-on-examples}/demo-tooltip-addon.md (99%) rename docs/devs/{ => add-on-examples}/lets-build-an-add-on.md (97%) diff --git a/docs/demo-tooltip-addon.md b/docs/devs/add-on-examples/demo-tooltip-addon.md similarity index 99% rename from docs/demo-tooltip-addon.md rename to docs/devs/add-on-examples/demo-tooltip-addon.md index b9c0440..da5ae59 100644 --- a/docs/demo-tooltip-addon.md +++ b/docs/devs/add-on-examples/demo-tooltip-addon.md @@ -7,12 +7,13 @@ To begin, similar to the Demo/Portal add-on, we'll run a command and provide som php cmd.php xf-addon:create ``` -!!! example "Terminal output" +:::note Terminal output **Enter an ID for this add-on:** Demo/ToolTip **Enter a title:** Demo - ToolTip **Enter a version ID:** This integer will be used for internal variable comparisons. + Each release of your addon should increase this number: 1000010 Version string set to: 1.0.0 Alpha @@ -26,6 +27,7 @@ php cmd.php xf-addon:create **Does your Setup need to support running multiple steps? (y/n)** y The Setup.php file was successfully written out to /var/www/src/addons/Demo/ToolTip/Setup.php +::: After this has been done, we can do a couple of things to make our development a little easier. All we need to do is make sure this exists: ```php title="config.php" @@ -110,7 +112,7 @@ With this template in place, we now have content to display when users lack perm ## Modifying the controller Site actions are managed through controllers. -For more information on how controllers work, refer to the [Controller Basics](controller-basics.md) page. +For more information on how controllers work, refer to the [Controller Basics](docs/devs/controller-basics.md) page. Open your IDE. It's time to write some code. Don't worry, this part is straight forward as well! @@ -274,13 +276,17 @@ you need to run the following command: php cmd.php xf-addon:build-release Demo/ToolTip ``` -!!! example "Terminal output" +:::note Terminal output Performing add-on export. Exporting data for Demo - ToolTip to /var/www/html/src/addons/Demo/ToolTip/_data. + 27/27 [============================] 100% + Written successfully. + Attempting to validate addon.json file... + JSON file validates successfully! Building release ZIP. @@ -288,6 +294,7 @@ php cmd.php xf-addon:build-release Demo/ToolTip Writing release ZIP to /var/www/html/src/addons/Demo/ToolTip/_releases. Release written successfully. +::: ### What Just Happened? This command performs several important tasks: diff --git a/docs/devs/lets-build-an-add-on.md b/docs/devs/add-on-examples/lets-build-an-add-on.md similarity index 97% rename from docs/devs/lets-build-an-add-on.md rename to docs/devs/add-on-examples/lets-build-an-add-on.md index 1e2af14..c72d425 100644 --- a/docs/devs/lets-build-an-add-on.md +++ b/docs/devs/add-on-examples/lets-build-an-add-on.md @@ -76,7 +76,7 @@ Let's fill in some of these details: We have now added a `description`, the developer's name (`dev`) and specified that we want to display an icon (`icon`). The icon can either be a path (relative to your add-on root) or the name of a [Font Awesome icon](http://fontawesome.io/icons/) as we've done here. -As we're not superceding a XenForo 1 addon, we can disregard `legacy_addon_id`. For a full explanation of all of the properties in the `addon.json` file, refer to the [Add-on structure section](add-on-structure.md#addonjson-file). +As we're not superceding a XenForo 1 addon, we can disregard `legacy_addon_id`. For a full explanation of all of the properties in the `addon.json` file, refer to the [Add-on structure section](../add-on-structure.md#addonjson-file). ## Creating the Setup class @@ -102,7 +102,7 @@ class Setup extends AbstractSetup We talked a little bit already about the Setup class. We're going to be breaking the install, upgrade and uninstall processes into separate steps. -Let's start by importing some useful Schema classes. If you want to learn more about them, you can refer to the [Managing the Schema section](managing-the-schema.md). +Let's start by importing some useful Schema classes. If you want to learn more about them, you can refer to the [Managing the Schema section](../managing-the-schema.md). Just after the last `use` declaration, add the following lines: ```php title="src/addons/Demo/Portal/Setup.php" @@ -195,7 +195,7 @@ php cmd.php xf-addon:install-step Demo/Portal 3 So far we've added a column to the `xf_forum` table, it's now time to extend the Forum entity structure. We need to do this so that the entity knows about our new column, and so that data can be read from and written to it via the entity. :::note -The following steps will require [Development mode](development-tools.md#enabling-development-mode) to be enabled. Remember to set `Demo/Portal` as the `defaultAddOn` value in `config.php`. +The following steps will require [Development mode](../development-tools.md#enabling-development-mode) to be enabled. Remember to set `Demo/Portal` as the `defaultAddOn` value in `config.php`. ::: @@ -279,7 +279,7 @@ $structure->relations['FeaturedThread'] = [ ]; ``` -See [Relations](entities-finders-repositories.md#relations) for more information about relations. Hit "Save" to save the listener. +See [Relations](../entities-finders-repositories.md#relations) for more information about relations. Hit "Save" to save the listener. ## Creating a new entity @@ -385,9 +385,9 @@ class Forum extends XFCP_Forum } ``` -See [Extending classes](general-concepts.md#extending-classes) and [Type hinting](general-concepts.md#type-hinting) for more information. +See [Extending classes](../general-concepts.md#extending-classes) and [Type hinting](../general-concepts.md#type-hinting) for more information. -Click save to save the Class extension. Now we can add some code. The particular method we need to extend is a protected function called `saveTypeData`. When extending any existing method in any class, it is important to inspect the original method for a couple of reasons. The first being we want to make sure the arguments we use in the extended method, match that of the method we're extending. The second being that we need to know what this method actually does. For example, should the method be returning something of a particular type, or a certain object? This is certainly the case in most controller actions as we mentioned in the [Modifying a controller action reply (properly)](controller-basics.md#modifying-a-controller-action-reply-properly) section. However, although this method is within a controller, it isn't actually a controller action itself. In fact, this particular method is a "void" method; it isn't expected to return anything. However, we should always ensure we call the parent method in our extended method so let's just add the new method itself, without the new code we need to add: +Click save to save the Class extension. Now we can add some code. The particular method we need to extend is a protected function called `saveTypeData`. When extending any existing method in any class, it is important to inspect the original method for a couple of reasons. The first being we want to make sure the arguments we use in the extended method, match that of the method we're extending. The second being that we need to know what this method actually does. For example, should the method be returning something of a particular type, or a certain object? This is certainly the case in most controller actions as we mentioned in the [Modifying a controller action reply (properly)](../controller-basics.md#modifying-a-controller-action-reply-properly) section. However, although this method is within a controller, it isn't actually a controller action itself. In fact, this particular method is a "void" method; it isn't expected to return anything. However, we should always ensure we call the parent method in our extended method so let's just add the new method itself, without the new code we need to add: ```php title="src/addons/Demo/Portal/XF/Admin/Controller/Forum.php" protected function saveTypeData(FormAction $form, \XF\Entity\Node $node, \XF\Entity\AbstractNode $data) @@ -546,7 +546,7 @@ public function actionIndex() Now, this won't exactly work, yet, because we haven't created the template, yet, but this is enough, for now, to at least demonstrate our route and controller are talking to each other. So visiting `index.php?portal` should at the very least display a 'Template error'. -As was mentioned in the [View reply](controller-basics.md#view-reply) section, the first argument is a view class, but we don't need to actually create this class. This class could be extended by other add-ons, if necessary, even if it doesn't exist. The second argument is the template, which we need to create now in the path `src/addons/Demo/Portal/_output/templates/public/demo_portal_view.html`. That template, for now, should simply contain the following: +As was mentioned in the [View reply](../controller-basics.md#view-reply) section, the first argument is a view class, but we don't need to actually create this class. This class could be extended by other add-ons, if necessary, even if it doesn't exist. The second argument is the template, which we need to create now in the path `src/addons/Demo/Portal/_output/templates/public/demo_portal_view.html`. That template, for now, should simply contain the following: ```html title="src/addons/Demo/Portal/_output/templates/public/demo_portal_view.html" Portal @@ -1181,7 +1181,7 @@ To: ## Unfeaturing on visibility changes -To approach this, we are going to need to modify the Thread entity again but this time we'll be doing that with the `entity_post_save` event. As we mentioned in [The Entity life cycle](entities-finders-repositories.md#the-entity-life-cycle), the `_postSave()` method is where actions can be performed as a result of an entity being inserted or updated. Initially we will be unfeaturing a thread when that thread is no longer visible. +To approach this, we are going to need to modify the Thread entity again but this time we'll be doing that with the `entity_post_save` event. As we mentioned in [The Entity life cycle](../entities-finders-repositories.md#the-entity-life-cycle), the `_postSave()` method is where actions can be performed as a result of an entity being inserted or updated. Initially we will be unfeaturing a thread when that thread is no longer visible. So, head back into the "Add code event listeners" page, and this time listen to the `entity_post_save` event. The event hint this time will be `XF\Entity\Thread`. For the execute callback, we will use the same class as we did before (`Demo\Portal\Listener`) but we will add a new method here named `threadEntityPostSave`. Let's add that method now so it's there when we save the listener: diff --git a/sidebars.ts b/sidebars.ts index f3b0eb2..f467471 100644 --- a/sidebars.ts +++ b/sidebars.ts @@ -328,7 +328,14 @@ const sidebars: SidebarsConfig = { 'devs/entities-finders-repositories', 'devs/criteria', 'devs/managing-the-schema', - 'devs/lets-build-an-add-on', + { + type: 'category', + label: 'Add-on examples', + items: [ + 'devs/add-on-examples/lets-build-an-add-on', + 'devs/add-on-examples/demo-tooltip-addon', + ], + }, { type: 'category', label: 'Appendix', From d31c99671d4a701e0f37b5fceeac81b1b8f7b22b Mon Sep 17 00:00:00 2001 From: QuackieMackie Date: Sat, 7 Feb 2026 00:31:06 +0000 Subject: [PATCH 4/6] Fix: Updated broken relative links in "Let's Build an Add-On" guide --- .../devs/add-on-examples/lets-build-an-add-on.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/devs/add-on-examples/lets-build-an-add-on.md b/docs/devs/add-on-examples/lets-build-an-add-on.md index c72d425..d658130 100644 --- a/docs/devs/add-on-examples/lets-build-an-add-on.md +++ b/docs/devs/add-on-examples/lets-build-an-add-on.md @@ -76,7 +76,7 @@ Let's fill in some of these details: We have now added a `description`, the developer's name (`dev`) and specified that we want to display an icon (`icon`). The icon can either be a path (relative to your add-on root) or the name of a [Font Awesome icon](http://fontawesome.io/icons/) as we've done here. -As we're not superceding a XenForo 1 addon, we can disregard `legacy_addon_id`. For a full explanation of all of the properties in the `addon.json` file, refer to the [Add-on structure section](../add-on-structure.md#addonjson-file). +As we're not superceding a XenForo 1 addon, we can disregard `legacy_addon_id`. For a full explanation of all of the properties in the `addon.json` file, refer to the [Add-on structure section](docs/devs/add-on-structure.md#addonjson-file). ## Creating the Setup class @@ -102,7 +102,7 @@ class Setup extends AbstractSetup We talked a little bit already about the Setup class. We're going to be breaking the install, upgrade and uninstall processes into separate steps. -Let's start by importing some useful Schema classes. If you want to learn more about them, you can refer to the [Managing the Schema section](../managing-the-schema.md). +Let's start by importing some useful Schema classes. If you want to learn more about them, you can refer to the [Managing the Schema section](docs/devs/managing-the-schema.md). Just after the last `use` declaration, add the following lines: ```php title="src/addons/Demo/Portal/Setup.php" @@ -195,7 +195,7 @@ php cmd.php xf-addon:install-step Demo/Portal 3 So far we've added a column to the `xf_forum` table, it's now time to extend the Forum entity structure. We need to do this so that the entity knows about our new column, and so that data can be read from and written to it via the entity. :::note -The following steps will require [Development mode](../development-tools.md#enabling-development-mode) to be enabled. Remember to set `Demo/Portal` as the `defaultAddOn` value in `config.php`. +The following steps will require [Development mode](docs/devs/development-tools.md#enabling-development-mode) to be enabled. Remember to set `Demo/Portal` as the `defaultAddOn` value in `config.php`. ::: @@ -279,7 +279,7 @@ $structure->relations['FeaturedThread'] = [ ]; ``` -See [Relations](../entities-finders-repositories.md#relations) for more information about relations. Hit "Save" to save the listener. +See [Relations](docs/devs/entities-finders-repositories.md#relations) for more information about relations. Hit "Save" to save the listener. ## Creating a new entity @@ -385,9 +385,9 @@ class Forum extends XFCP_Forum } ``` -See [Extending classes](../general-concepts.md#extending-classes) and [Type hinting](../general-concepts.md#type-hinting) for more information. +See [Extending classes](docs/devs/general-concepts.md#extending-classes) and [Type hinting](docs/devs/general-concepts.md#type-hinting) for more information. -Click save to save the Class extension. Now we can add some code. The particular method we need to extend is a protected function called `saveTypeData`. When extending any existing method in any class, it is important to inspect the original method for a couple of reasons. The first being we want to make sure the arguments we use in the extended method, match that of the method we're extending. The second being that we need to know what this method actually does. For example, should the method be returning something of a particular type, or a certain object? This is certainly the case in most controller actions as we mentioned in the [Modifying a controller action reply (properly)](../controller-basics.md#modifying-a-controller-action-reply-properly) section. However, although this method is within a controller, it isn't actually a controller action itself. In fact, this particular method is a "void" method; it isn't expected to return anything. However, we should always ensure we call the parent method in our extended method so let's just add the new method itself, without the new code we need to add: +Click save to save the Class extension. Now we can add some code. The particular method we need to extend is a protected function called `saveTypeData`. When extending any existing method in any class, it is important to inspect the original method for a couple of reasons. The first being we want to make sure the arguments we use in the extended method, match that of the method we're extending. The second being that we need to know what this method actually does. For example, should the method be returning something of a particular type, or a certain object? This is certainly the case in most controller actions as we mentioned in the [Modifying a controller action reply (properly)](docs/devs/controller-basics.md#modifying-a-controller-action-reply-properly) section. However, although this method is within a controller, it isn't actually a controller action itself. In fact, this particular method is a "void" method; it isn't expected to return anything. However, we should always ensure we call the parent method in our extended method so let's just add the new method itself, without the new code we need to add: ```php title="src/addons/Demo/Portal/XF/Admin/Controller/Forum.php" protected function saveTypeData(FormAction $form, \XF\Entity\Node $node, \XF\Entity\AbstractNode $data) @@ -546,7 +546,7 @@ public function actionIndex() Now, this won't exactly work, yet, because we haven't created the template, yet, but this is enough, for now, to at least demonstrate our route and controller are talking to each other. So visiting `index.php?portal` should at the very least display a 'Template error'. -As was mentioned in the [View reply](../controller-basics.md#view-reply) section, the first argument is a view class, but we don't need to actually create this class. This class could be extended by other add-ons, if necessary, even if it doesn't exist. The second argument is the template, which we need to create now in the path `src/addons/Demo/Portal/_output/templates/public/demo_portal_view.html`. That template, for now, should simply contain the following: +As was mentioned in the [View reply](docs/devs/controller-basics.md#view-reply) section, the first argument is a view class, but we don't need to actually create this class. This class could be extended by other add-ons, if necessary, even if it doesn't exist. The second argument is the template, which we need to create now in the path `src/addons/Demo/Portal/_output/templates/public/demo_portal_view.html`. That template, for now, should simply contain the following: ```html title="src/addons/Demo/Portal/_output/templates/public/demo_portal_view.html" Portal @@ -1181,7 +1181,7 @@ To: ## Unfeaturing on visibility changes -To approach this, we are going to need to modify the Thread entity again but this time we'll be doing that with the `entity_post_save` event. As we mentioned in [The Entity life cycle](../entities-finders-repositories.md#the-entity-life-cycle), the `_postSave()` method is where actions can be performed as a result of an entity being inserted or updated. Initially we will be unfeaturing a thread when that thread is no longer visible. +To approach this, we are going to need to modify the Thread entity again but this time we'll be doing that with the `entity_post_save` event. As we mentioned in [The Entity life cycle](docs/devs/entities-finders-repositories.md#the-entity-life-cycle), the `_postSave()` method is where actions can be performed as a result of an entity being inserted or updated. Initially we will be unfeaturing a thread when that thread is no longer visible. So, head back into the "Add code event listeners" page, and this time listen to the `entity_post_save` event. The event hint this time will be `XF\Entity\Thread`. For the execute callback, we will use the same class as we did before (`Demo\Portal\Listener`) but we will add a new method here named `threadEntityPostSave`. Let's add that method now so it's there when we save the listener: From e7b89751eb7cf44d6f7eeb8c87389cda59397f4a Mon Sep 17 00:00:00 2001 From: QuackieMackie Date: Sat, 7 Feb 2026 00:35:23 +0000 Subject: [PATCH 5/6] Fix: Corrected broken relative link in demo tooltip add-on example --- docs/devs/add-on-examples/demo-tooltip-addon.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/devs/add-on-examples/demo-tooltip-addon.md b/docs/devs/add-on-examples/demo-tooltip-addon.md index da5ae59..cdf149b 100644 --- a/docs/devs/add-on-examples/demo-tooltip-addon.md +++ b/docs/devs/add-on-examples/demo-tooltip-addon.md @@ -238,7 +238,7 @@ Open the file located at src/addons/Demo/ToolTip/addon.json in your IDE: } ``` -Here's what you need to know when customising this file [add-on structure properties](add-on-structure.md/#properties). +Here's what you need to know when customising this file [add-on structure properties](docs/devs/add-on-structure.md#properties). ## Registering the class extension From 1e76f1c6894d581421e3a317767ab1fcec1ed5f0 Mon Sep 17 00:00:00 2001 From: QuackieMackie Date: Sat, 7 Feb 2026 00:40:56 +0000 Subject: [PATCH 6/6] Fix: Escaped spaces in file download links for add-on examples --- docs/devs/add-on-examples/demo-tooltip-addon.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/devs/add-on-examples/demo-tooltip-addon.md b/docs/devs/add-on-examples/demo-tooltip-addon.md index cdf149b..2a22229 100644 --- a/docs/devs/add-on-examples/demo-tooltip-addon.md +++ b/docs/devs/add-on-examples/demo-tooltip-addon.md @@ -306,4 +306,4 @@ This command performs several important tasks: Congratulations on completing your XenForo add-on from start to finish! You have learned how to create permissions, templates, phrases, and extend classes. -You are welcome to download a copy of the completed add-on here: [Demo-ToolTip-1.0.0 Alpha.zip](files/Demo-ToolTip-1.0.0 Alpha.zip). +You are welcome to download a copy of the completed add-on here: [Demo-ToolTip-1.0.0 Alpha.zip](/files/Demo-ToolTip-1.0.0%20Alpha.zip).