MOTIVATION
----------
I am applying for a CVS account because I have written what I believe to be a useful module - Site Index - and want to make it available to other Drupal users as part of my contribution to Drupal. I and the organization I work for have benefited greatly over the last two years by using Drupal core and contributed modules to construct our intranet site and I'd like to start giving back what I can to the Drupal community.
I wrote the Site Index module after searching for but failing to find a module (or a configuration of CCK and Views) that allows manual creation of a 'book-style' alphabetical index - with headings, entries and redirect entries - of site content. We needed something that would allow the easy creation and management of index entries that linked to given items of content (node, view, basically anything with a functional and accessible path) using custom index text.
Our staff is multinational and multilingual and not always technologically savvy so the index needed to be simple and straightforward. All the available solutions we found produced indexes that were too complex, consisted of entries produced by progammatically retrieving and displaying node, view or page titles, taxonomy terms, etc. and, frankly, were too confusing to our average user to be beneficial in the way we needed.
GOAL
----
The Site Index module is intended to provide an easy to configure and easy to use public-facing alphabetical index of site content that allows site users to easily find content through a variety of descriptive index entries. It allows anyone with site index admin permission to create and manage index entries, index headings with subordinate entries and index entries that redirect to other index entries.
It provides an alternative to search functionality in that it allows intentional and informed guidance for users to what the organization, through its site admins, believes to be the most relevent and useful information to its users. It is intended to complement rather than replace search functionality.
FUNCTIONALITY
-------------
Displays a site index consisting of headings and entries in an alphabetical format that link to site content.
Provides display of a single page containing all site entries or a page of entries based on chosen index letter.
Periodically tests and updates site entry status (which determines inclusion in the site index) based on link functionality (which can be affected by link rot, node status changes, etc...).
Allows creation and deletion of index entry links through an admin page or from within the node edit form.
Provides optional notification, when editing nodes, if node is not listed in site index.
Provides report of non-functional entry links with edit and delete options.
CONFIGURABLE OPTIONS
--------------------
User-definable title of and path to the site index page.
Creation and deletion of site index entries directly from within node edit forms.
Notification on node edit forms for nodes that are not included in the site index.
Expanded or collapsed fieldset for index entry fields in node edit form.
Option of inclusion, by content type, of index entry fieldset in node edit form.
PAGES
-----
admin/build/siteindex (Adding, editing & deleting of index entries)
admin/settings/siteindex (Configuration settings)
admin/reports/siteindex (Report of non-functional entry links, if any)
admin/help/siteindex (Help page)
site_index (Default Index path)
FILES
-----
README.txt
siteindex.css
siteindex.info
siteindex.install
siteindex.module
STATUS
------
The module has been tested in-house and is in use on our intranet site. Because it hasn't yet been heavily tested by a number of different site index admins (we only have one at the moment) I would consider it to be a beta version at this point although I'm not aware of any outstanding bugs or problems with it (and, given that we're using it, I would be happy to fix any that are found).
COMPARABLE MODULES
------------------
IndexPage (http://drupal.org/project/indexpage)
Index (http://drupal.org/project/index)
Vocabulary Index (http://drupal.org/project/vocabindex)
Site Index IndexPage Index Vocabulary Index
------------------------------------------------------------------------------
User-facing Yes No Yes Yes
Index generation Manual Programmed Programmed Programmed
Drupal versions 6 5, 6, 7(dev) 6(dev) 5, 6 (Succeeded
by Index)
Index content Anything Content Comments, Vocabularies
accessible by content Nodes,
by a path type Content types,
Languages,
Roles,
Terms,
Users,
Vocabularies
Grouping/ordering Alphabetical Content Comments, Vocabularies
by content Nodes,
type Content types,
Languages,
Roles,
Terms,
Users,
Vocabularies
| Comment | File | Size | Author |
|---|---|---|---|
| #17 | siteindex.tar_.gz | 12.01 KB | james marks |
| #15 | siteindex.tar_.gz | 12.03 KB | james marks |
| #14 | siteindex.tar_.gz | 12.04 KB | james marks |
| #11 | siteindex_screenshot_garland.gif | 15.39 KB | james marks |
| #4 | siteindex.tar_.gz | 11.82 KB | james marks |
Comments
Comment #1
james marks commentedI'm attaching the Site Index code to the CVS account application.
James
Comment #2
james marks commentedChanging the status.
James
Comment #3
sunDrupal modules should not output such messages after performing (any) installation tasks. There are dedicated modules, which may be doing this. All other modules should follow practices of Drupal core modules.
These two constants need to be removed. variable_get() is enough of an abstraction.
siteindex-node-formlikely clashes with a possible node type name "sideindex".The cancel button should use a dedicated #submit handler, so as to not clobber the regular form submission.
minor: "confirm" in [_]siteindex_confirm_first_level_value() and other functions should be renamed to "validate". Ideally, they should get $form and $form_state as arguments, just like any other form validation handler.
It looks like _siteindex_test_path() should be a more common form validation handler, too. At least the error handling tied to it looks a bit weak currently.
You may also find the #element_validate Form API property interesting. It allows you to perform form element value validation on a per element basis, which might heavily simplify your form handling here. _siteindex_form_alter_validate() looks like you really could use #element_validate.
_siteindex_add_edit_entry_submit() performs identification and routing logic, which was already done in _siteindex_add_edit_entry() or elsewhere. That's a bit fragile and might impose security issues, since the form processing should not be able to entirely manipulate the target thing that is submitted. You can store originally identified properties in $form['#siteindex'] or in #type 'value' form elements; both ways are accessible in form validation and submit handlers.
The submit button label text should not have an effect on data storage and CRUD logic. You should check whether an entry needs to be created or updated, based upon whether the form resp. submitted form values contain an id or not. -- Ideally, you might want to consider to move the actual data storage into API functions, i.e. siteindex_entry_save(&$entry).
No way. :) First of all, menu_rebuild() is invoked immediately here, not as a submit handler. Thus, everytime you visit the admin settings, the entire menu is rebuild. You should be using a dedicated submit handler for the admin settings here, which performs that action.
minor: In general, in Drupal, we write SQL statements on one line and without needless variables (unless they are needed, of course):
The delete form needs to use confirm_form().
This should and must not happen. It would mean that user input and stored data can get lost mysteriously. I.e., this entire elseif needs to vanish.
This looks very very odd. Not sure what you were trying to do, but this is an illegal mix of sub-system APIs, which makes no sense. Is this supposed to be a form submit handler instead of a menu callback (as the PHPDoc states)? If it is, then the function gets $form and $form_state as arguments, so $destination can't work. If it's not, then it's indeed a menu callback that redirects to another path, which is needless, since you could specify 'page callback' => 'drupal_goto', 'page arguments' => array(1 [or 'static/destination'), in hook_menu() already. But in the end, a page callback that permanently and unconditionally redirects is entirely wrong in the first place. ;)
Thus, something is wrong here and this entire function needs to go.
$index_letter and eventually all other stored user input that is output in the index needs to be check_plain()ed, too. This in particular applies to headings that are output further below.
This entire configuration setting is very uncommon for a Drupal module and actually needless, since 'site_index' is the internal system path. One wants to have it on a different path, users are able to create a URL alias for it. Modules like Subpath Alias additionally introduce support for dynamic arguments after URL aliases.
Finally, the default path should be 'siteindex', not 'site_index', as the latter is not the module's namespace.
Comment #4
james marks commentedWith regard to whether siteindex_test_path() should be a validation handler, it performs two functions; 1) it tests paths submitted via forms (form validation) and 2) tests, on a periodic basis, existing siteindex entry paths (not form validation). For that reason, it doesn't seem right (to me) to call it a form validator if it does more than form validation.
When path data is pulled from the table, I need identify whether the path is to content or to a named anchor and, if so, convert the link to the named anchor back to index entry titles for the user to understand. So, I'm converting from literal paths on extraction and to them on submission, different kinds of conversion in different functions.
Originally, when the user entered an index entry title, I had the autocomplete function build and display the link to the named anchor in parenthesis that followed the index entry heading + entry in the submission form then just used the content in parenthesis upon submission but the display of the explicit path to the named anchor confused the users. (They didn't care about, and don't want to see, raw html links to named anchors when they were trying to identify an index entry.)
The weakest part of this that I see is the representation of the index heading + entry text using an arrow (->) as a delimiter. I need a reliable way to split the heading from the entry when testing the path but this admittedly seems (to me) to be a bit kludgy.
I hope I haven't misunderstood your point and have adequately addressed it. I'm sure you'll let me know if I haven't. :)
Comment #5
dman commentedHi. re #4. I'm responsible for the mixed messages you may have got there. I find it extremely useful for a module to say "Hi, I'm installed, here's how to use me" rather than silently hide itself deep in the menu tree making you search for it for the next 5 minutes. To me that's affordance. Sun appears to have a slight difference of opinion.
You can't please everyone :-)
Comment #6
sunThanks! No time for a full review, sorry.
Interesting. Not sure who put those up. In general, it's best to follow latest and greatest code in Drupal core. None of the core modules display a message after installing or uninstalling. And, I keep my major argument: To be really helpful, you should integrate with one of the existing "admin guide" modules instead, i.e., modules that allow other modules to expose structured information and ordered tasks to install and configure the module. Simple messages simply don't buy you anything useful, since they'll vanish, are only visible to one user, and stuff.
We should fix those guidelines.
Mad assumptions :) http://api.drupal.org/api/function/variable_get/6 does not query the database, it's a very fast function.
IIRC, I actually meant to drop the entire special destination handling. If you want a form to redirect to somewhere else (than the default page/path after submission), then you can simply pass a 'destination' query parameter to it:
http://example.com/path/to/form?destination=custom/redirect/path/to/end/on
Form API will respect this destination path and ignore any hard-coded path.
Good, modern, fancy: [subject]_[verb]
Old, ugly, bad: [verb]_[subject]
This concept is easily understandable and allows to quickly draft new APIs. Speaking of, any module/API should expose the base CRUD functions along with hooks, like many of core's APIs do:
Those user validation helper functions you mentioned (and others) date back to... Drupal 4.6 actually: http://api.drupal.org/api/function/user_validate_name/4.6 -- however, finding good names for such universal helper functions also is not an easy task. One could argue that "user" is the subject already (although it's the module name).
Comments are required to wrap at 80 chars. Arrays are treated kinda special; although there is no clear rule that forces you to wrap arrays (write them as multi-line), many people always do and prefer it. Any other code or string does not need to wrap, but if there is a sane method of making it wrap, it may be used. Overly (very very) long strings, for example, may simply be concatenated:
However, this really applies to text strings only. Code lines (most often conditions) may be split into multiple conditions, if possible.
If you want to change this standard in Drupal, then you are welcome to change it in Drupal core. :) Otherwise, when implementing "mainstream" functionality, you and everyone else is and should be following common module development practices. This ensures compatibility with other modules, simplifies theming for front-end developers, and in this case, also ensures security.
But truth to be told: Changing the link to a form button has been actively discussed for D7, but deferred to D8 due to missing consensus and activity on the issue. :)
IIRC, then this code was/is executed during editing (or similar) - and not during/after final form submission. The code needs to make sure that all stored data is persistent, and data is only deleted, when the user actively and actually requested the deletion. Just removing values during a multi-step form operation would not be a serious deletion request.
Comment #7
james marks commentedGood to know. (There's so much to learn... :) )
I did drop the entire special destination handling and am using the standard 'destination=' approach in links for any use of the siteindex_add_edit() form outside of the admin/build/siteindex URL. (The siteindex_add_edit_entry() form is also used for editing entries from the siteindex report, admin/reports/siteindex.) I'm using $form['#redirect'] as the default for the admin/build/siteindex URL. (Hope I'm still not misunderstanding your point.)
I'd be an enthusiastic supporter of the two button approach (if I ever get to the point where I get to have any input on changing core). :)
The code is executed upon submission, not editing. This code handles only fields that have been added to the node edit form (not added via a multi-step form) through the use of hook_form_alter() and only alters the stored data upon submission. Typically, when editing a node, altering or deleting values in non-required fields doesn't require the user to actively request or confirm the deletion of specific field values, does it? (I don't think it does but I obviously have much to learn. :) )
Comment #8
james marks commentedI found it useful as well. I thought it was a nice idea, given that the first place I usually go after installing a module is the module configuration settings. Having a link directly to it was handy.
Comment #9
james marks commentedThank you, by the way. Your review was extremely helpful. All the stuff I've developed to date has been for internal use and and doesn't get this kind of core-Drupal review. I'm going back to apply this stuff to some of the other internal modules I've written. (I have another module that I'd like to submit if this one gets accepted but that module needs some work at this point.)
Comment #10
sunStill no time for a full review, but:
You, me, everyone, can! Just pick yourself an issue + work on it! :) This issue, for example, is discussed in
#116939: Add a Cancel link on forms
#772758: Delete confirm form, make the cancel link to button
However, as mentioned before, that particular topic is too late for D7. But you can always play http://drupal.org/bug-bingo or http://drupal.org/patch-bingo :)
If you want to see D7 out of the door earlier, you can always help to fix remaining bugs. Writing patches for Drupal core makes you learn to write even more awesome code :)
Comment #11
james marks commentedUploading a screenshot.
James
Comment #12
avpadernoWhy did you decide to create a new module, rather than opening feature supports for the existing projects?
Comment #13
sunI think James already described in the original motivation message. Without having actually looked at the mentioned modules or otherwise knowing them, I actually think this module makes sense (to some extent). It looks like James is going to be a happy community citizen, and the only remaining thing missing here seems to be a final security review.
Comment #14
james marks commentedOk, all my function names are now "Good, modern, fancy: [subject]_[verb]":
siteindex_admin_list()
siteindex_admin_settings()
siteindex_cron()
siteindex_entries_get()
siteindex_entries_test_and_update()
siteindex_entry_add_edit()
siteindex_entry_add_edit_validate()
siteindex_entry_add_edit_submit()
siteindex_entry_cancel()
siteindex_entry_delete_submit()
siteindex_entry_get()
siteindex_entry_list()
siteindex_entry_path_autocomplete()
siteindex_entry_path_test()
siteindex_first_level_autocomplete()
siteindex_form_alter()
siteindex_form_alter_validate()
siteindex_form_alter_submit()
siteindex_help()
siteindex_invalid_entries_get()
siteindex_invalid_entries_report()
siteindex_menu()
siteindex_menu_rebuild()
siteindex_page()
siteindex_perm()
siteindex_test_for_duplicate_entries()
siteindex_theme()
theme_siteindex_entry_fieldset()
theme_siteindex_entry_list()
James
Comment #15
james marks commentedRefactored code for the following improvements:
James
Comment #16
james marks commentedThe functionality we were looking for was so different from that provided by the existing modules that I felt it would be a better solution to create a separate module than to try to modify the functionality of existing modules:
The site this module was written for is an intranet that serves as the primary portal for our staff to access information about our agency. Consequently, there is a fairly long and carefully maintained list of topics and content that we want our staff to have ready access to in a familiar and simple-to-use format.
Obviously, this module isn't the best solution for every web site but I'd think it could be for some.
James
Comment #17
james marks commentedFixed a bug that interfered with deleting index entries that appeared after switching to using confirm_form().
James
Comment #18
james marks commentedOK! I think that marks the end of my last-minute adjustments. As far as I know this has everything sun asked for, could someone let me know if there's anything else I need to do?
James
Comment #19
avpadernoI approved the application as maintainer of Profile Plus (see http://drupal.org/node/866142).