blog.rst 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. Building a Blog Plugin
  2. ######################
  3. Build a simple blogging plugin using Elgg.
  4. This duplicates features in the bundled blog plugin,
  5. so be sure to disable that while working on your own version.
  6. .. contents:: Contents
  7. :local:
  8. :depth: 1
  9. Create the plugin skeleton
  10. ==========================
  11. The name of the directory under "mod" becomes the id of your plugin::
  12. /mod/my_blog/pages/my_blog/
  13. /mod/my_blog/actions/my_blog/
  14. /mod/my_blog/views/default/my_blog/
  15. You'll need to add a manifest file in ``/mod/my_blog/manifest.xml``.
  16. This file stores basic information about the plugin. See :doc:`/guides/plugins` for the template.
  17. You can also just copy the manifest file from another plugin and then change the values to fit your new plugin.
  18. Be sure to change the author and website, and remove the “bundled” category!
  19. Create a page for composing the blogs
  20. =====================================
  21. Create the file ``add.php`` in ``/mod/my_blog/pages/my_blog/``.
  22. .. code:: php
  23. <?php
  24. // make sure only logged in users can see this page
  25. gatekeeper();
  26. // set the title
  27. // for distributed plugins, be sure to use elgg_echo() for internationalization
  28. $title = "Create a new my_blog post";
  29. // start building the main column of the page
  30. $content = elgg_view_title($title);
  31. // add the form to this section
  32. $content .= elgg_view_form("my_blog/save");
  33. // optionally, add the content for the sidebar
  34. $sidebar = "";
  35. // layout the page
  36. $body = elgg_view_layout('one_sidebar', array(
  37. 'content' => $content,
  38. 'sidebar' => $sidebar
  39. ));
  40. // draw the page
  41. echo elgg_view_page($title, $body);
  42. Create the form for creating a new my\_blog post
  43. ================================================
  44. Create a file at ``/mod/my_blog/views/default/forms/my_blog/save.php``
  45. that contains the form body. This corresponds to view that is called above:
  46. ``elgg_view_form("my_blog/save")``.
  47. The form should have input fields for the title, body and tags.
  48. Because you used ``elgg_view_form()``, you do not need to include form tag markup.
  49. The view will be automatically wrapped with:
  50. * a ``<form>`` tag and the necessary attributes
  51. * anti-csrf tokens
  52. The form's action will be ``"<?php echo elgg_get_site_url() ?>action/my_blog/save"``,
  53. which we will create in a moment. Here is the content of
  54. ``/mod/my_blog/views/default/forms/my_blog/save.php``:
  55. .. code:: php
  56. <div>
  57. <label><?php echo elgg_echo("title"); ?></label><br />
  58. <?php echo elgg_view('input/text',array('name' => 'title')); ?>
  59. </div>
  60. <div>
  61. <label><?php echo elgg_echo("body"); ?></label><br />
  62. <?php echo elgg_view('input/longtext',array('name' => 'body')); ?>
  63. </div>
  64. <div>
  65. <label><?php echo elgg_echo("tags"); ?></label><br />
  66. <?php echo elgg_view('input/tags',array('name' => 'tags')); ?>
  67. </div>
  68. <div>
  69. <?php echo elgg_view('input/submit', array('value' => elgg_echo('save'))); ?>
  70. </div>
  71. Notice how the form is calling input views like ``input/longtext``.
  72. These are built into Elgg and make it easy to add form components.
  73. You can see a complete list of input views in the ``/views/default/input/`` directory.
  74. .. warning::
  75. The above code is not accessibility-friendly.
  76. The action file
  77. ===============
  78. Create the file ``/mod/my_blog/actions/my_blog/save.php``.
  79. This will save the blog post to the database.
  80. .. code:: php
  81. <?php
  82. // get the form inputs
  83. $title = get_input('title');
  84. $body = get_input('body');
  85. $tags = string_to_tag_array(get_input('tags'));
  86. // create a new my_blog object
  87. $blog = new ElggObject();
  88. $blog->subtype = "my_blog";
  89. $blog->title = $title;
  90. $blog->description = $body;
  91. // for now make all my_blog posts public
  92. $blog->access_id = ACCESS_PUBLIC;
  93. // owner is logged in user
  94. $blog->owner_guid = elgg_get_logged_in_user_guid();
  95. // save tags as metadata
  96. $blog->tags = $tags;
  97. // save to database and get id of the new my_blog
  98. $blog_guid = $blog->save();
  99. // if the my_blog was saved, we want to display the new post
  100. // otherwise, we want to register an error and forward back to the form
  101. if ($blog_guid) {
  102. system_message("Your blog post was saved");
  103. forward($blog->getURL());
  104. } else {
  105. register_error("The blog post could not be saved");
  106. forward(REFERER); // REFERER is a global variable that defines the previous page
  107. }
  108. A few fields are built into Elgg objects. Title and description are two of these.
  109. It makes sense to use description to contain the my\_blog text.
  110. Every entity can have a subtype and in this we are using ``"my_blog"``.
  111. The tags are stored as metadata.
  112. Every object in Elgg has a built-in URL automatically,
  113. although you can override this if you wish.
  114. The ``getURL()`` method is called to get that unique URL.
  115. The object view
  116. ===============
  117. Elgg will automatically call the ``object/my_blog`` view to view the
  118. my\_blog post so we need to create the object view.
  119. Objects in Elgg are a subclass of something called an “entity”.
  120. Users, sites, and groups are also subclasses of entity.
  121. All entities can (and should) have a subtype,
  122. which allows granular control for listing and displaying.
  123. Here, we have used the subtype "``my_blog``\ " to identify a my\_blog post,
  124. but any alphanumeric string can be a valid subtype.
  125. When picking subtypes, be sure to pick ones that make sense for your plugin.
  126. In ``/mod/my_blog/views/default/``, create a folder ``/object/`` and
  127. then create a file ``my_blog.php`` in it.
  128. Each my\_blog post will be passed to this PHP file as
  129. ``$vars['entity']``. (``$vars`` is an array used in the views system to
  130. pass variables to a view.) The content of ``object/my_blog.php`` can
  131. just be something like:
  132. .. code:: php
  133. <?php
  134. echo elgg_view_title($vars['entity']->title);
  135. echo elgg_view('output/longtext', array('value' => $vars['entity']->description));
  136. echo elgg_view('output/tags', array('tags' => $vars['entity']->tags));
  137. The last line takes the tags on the my\_blog post and automatically
  138. displays them as a series of clickable links. Search is handled
  139. automatically.
  140. (If you're wondering about the '``default``\ ' in ``/views/default/``,
  141. you can create alternative views. RSS, OpenDD, FOAF, mobile and others
  142. are all valid view types.)
  143. Plugin start.php
  144. ================
  145. Every plugin has a ``start.php`` that initializes it.
  146. For this example, we just need to register the action file we created earlier:
  147. Also see a related guide about :doc:`/guides/actions`.
  148. .. code:: php
  149. <?php
  150. elgg_register_action("my_blog/save", elgg_get_plugins_path() . "my_blog/actions/my_blog/save.php");
  151. The action will now be available as ``/action/my_blog/save``.
  152. By default, all actions are available only to logged in users.
  153. If you want to make an action available to only admins or open it up to unauthenticated users,
  154. you can pass 'admin' or 'public' as the third parameter of ``elgg_register_action()``, respectively.
  155. Registering a page handler
  156. ==========================
  157. In order to be able to serve the page that generates the form, you'll
  158. need to register a page handler. Add the following to your start.php:
  159. .. code:: php
  160. elgg_register_page_handler('my_blog', 'my_blog_page_handler');
  161. function my_blog_page_handler($segments) {
  162. if ($segments[0] == 'add') {
  163. include elgg_get_plugins_path() . 'my_blog/pages/my_blog/add.php';
  164. return true;
  165. }
  166. return false;
  167. }
  168. Page handling functions need to return ``true`` or ``false``. ``true``
  169. means the page exists and has been handled by the page handler.
  170. ``false`` means that the page does not exist and the user will be
  171. forwarded to the site's 404 page (requested page does not exist or not found).
  172. In this particular example, the URL must contain
  173. ``/my_blog/add`` for the user to view a page with a form, otherwise the
  174. user will see a 404 page.
  175. Trying it out
  176. =============
  177. If you have not enabled the plugin yet, you will need to go to
  178. Administration => Configure => Plugins => Advanced.
  179. Scroll to the bottom until you see your plugin. Click the Enable button.
  180. The page to create a new my\_blog post is accessible at http://yoursite/my_blog/add.
  181. Try it out.
  182. Displaying list of my\_blogs
  183. ============================
  184. Let's also create a page that lists my\_blog entries that have been created.
  185. Create ``/mod/my_blog/pages/my_blog/all.php``.
  186. To grab the latest my\_blog posts, we'll use ``elgg_list_entities``.
  187. Note that this function returns only the posts that the user can see,
  188. so access restrictions are handled transparently:
  189. .. code:: php
  190. $body = elgg_list_entities(array(
  191. 'type' => 'object',
  192. 'subtype' => 'my_blog',
  193. ));
  194. The function \`elgg\_list\_entities\` (and its cousins) also
  195. transparently handle pagination, and even create an RSS feeds for your
  196. my\_blogs if you have defined these views.
  197. Finally, we'll draw the page:
  198. .. code:: php
  199. $body = elgg_view_layout('one_column', array('content' => $body));
  200. echo elgg_view_page("All Site Blogs", $body);
  201. We will then need to modify our my\_blog page handler to grab the new
  202. page when the URL is set to ``/my_blog/all``. So, your new
  203. ``my_blog_page_handler()`` function in start.php should look like:
  204. .. code:: php
  205. function my_blog_page_handler($segments) {
  206. switch ($segments[0]) {
  207. case 'add':
  208. include elgg_get_plugins_path() . 'my_blog/pages/my_blog/add.php';
  209. break;
  210. case 'all':
  211. default:
  212. include elgg_get_plugins_path() . 'my_blog/pages/my_blog/all.php';
  213. break;
  214. }
  215. return true;
  216. }
  217. Now, if the URL contains just ``/my_blog`` or ``/my_blog/all``,
  218. the user will see an "All Site Blogs" page.
  219. A user's blog page
  220. ==================
  221. If we grab the Global Unique IDentifier (GUID) of the logged in user, we
  222. can limit the my\_blog posts to those posted by specifying the
  223. owner\_guid argument in the list function above.
  224. .. code:: php
  225. echo elgg_list_entities(array(
  226. 'type' => 'object',
  227. 'subtype' => 'my_blog',
  228. 'owner_guid' => elgg_get_logged_in_user_guid()
  229. ));
  230. The end
  231. =======
  232. There's much more that could be done for this plugin,
  233. but hopefully this gives you a good idea of how to get started with your own.