Classified
Battle plan for multiple node types
Node types
As per #195494, the goal is to support multiple node types.
- The included node type must remain for ease of use
- Other existing node types must be supported
- Since extra fields are per-node-type, this implies replacing the extra
fields by a proper field
- Ad lists can therefore no longer be built by node type.
- Take advantage of the change to replace custom lists by default Views
- Enabled node types can either be defined by module settings, or (better ?)
automatically be identified by the presence of an instance of the
expiration field
Extra fields to Field
The module defines two form extra fields, expires_fs
on forms
and expires
for display
- Kill both extra fields
- Add a new Field replacing both, this means:
- Done. Field is now available on Field UI only for node entities.
Adding field info/CRUD hooks
- Hooks implemented. Actual logic to be done. Adding a new widget to replace the form logic for
expires_fs
- Hooks implemented. Actual logic to be done. Adding a new formatter to replace the node view logic for
expires
Custom lists to Views
The module has inner knowledge of the specifics of the expiration extra
fields.
Lists are built either using custom built lists including it, or using
the new custom view mode introduced in 7.3. With multiple node types, this
is no longer doable so we replace these lists by taxonomy-filtered views.
With the extra field gone, its Views field handler no longer works.
- Replace the expiration field handler
- Replace the home page list with a view. Keep the various counters.
- Replace the per-term list with a view. Keep the various counters,
sub-category links, and breadcrumbs generation. This is likely to
involve attached views and/or new specific handlers.
- Replace the per-user profile list with a view. Handle the empty case.
- Replace the per-user rendered and raw token with two displays of a view.
- Replace the per-user link token, possibly still by manual code.
Configuration
- Simplify configuration: reduce the number of variables by grouping lifetimes in a single variable
- Remove maxlength logic: use maxlength module instead of maintaining it here.
Custom logic
Most of the module complexity lies in the expiration handling: automatic
expires generation and update. This needs to be adapted for the additional
complexity of a field over an extra field. Existing node form hooks and
handlers must be replaced by field hooks since we no longer know which forms
to intercept.
i18n
A number of users have expressed frustration at the lack of i18n support
in the module. Switching the extra fields to a field and the custom lists
to Views will help with this. New code should be i18n-compatible, so that
later changes can bring full i18n compliance
Testing
The code currently has 100% S0 test coverage. This should not go down, but
increase towards 100% C0.
- Rewrite tests to match the new code structures
- Add tests for each new function/method introduced
Drupal 8
Any significant work should take into account the directions taken by D8.
The move from an extra field to a normal field is in the right direction. Other significant
changes regard code placement outside the module file and the use of
autoloaded namespaced classes, one per file.
- Strip all non-hook code from the module file and move it to class
methods
- Extract all logic from hook implementations to class (static) methods, leaving only the "glue" bits in the hook implementation, to ease unit testing.
- Action code externalized in so doing should be considered for being made
usable at the admin level by exposing it as a core action, typically for
the user or node entities
- Done: converted to
classloader
. Consider using xautoload
or classloader
to apply PSR-0, or declare classes the D7 way, manually in the info file.
Services provided by the module
- 1 specific vocabulary: `classified_categories`, supplied with 2 sample terms (Wanted and For Sale)
- 1 specific node type: `classified` equipped with
a taxonomy_term_reference field pointing to the module vocabulary
a body field
- 3 blocks:
recent ads (public)
popular ads (public)
ad stars (admin)
- 1 Context Condition plugin
- 1 CTools “content type” plugin to expose the `expires` pseudo field
- 2 permissions
`administer classified ads`
`reset classified ads expiration`
- 2 extra fields
`expires_fs`: a form extra field allowing selection of an expiration type and optionally a manual expiration date for ad nodes
`expires`: a display extra field formatting the expiration date for ad nodes
- 1 notifications submodule: send notifications
at half-life
before|on expiration
before|on purge
- 3 drush commands
`classified-purge` to purge expired nodes
`classified-expire` to expire nodes
`classified-notify` to send notifications
- 1 custom view mode for `node`
- 2 menu loaders
notify kind
taxonomy term, only accepting terms from the module vocabulary
- 3 user tokens
`[classified-ads]` themed list of user ads
`[classified-ads-plain]` raw list of user ads
`[classified-ads-url]` url of a user's ads list
- 2 theme items
`classified_admin_lifetimes`
`classified_expires` for the `expires` extra field
- 1 field formatter for term_reference fields, linking to the per-term ad list instead of the default term page, with an optional link title
- node form logic
handle the extra field
provide fieldset-level access control for expiration type
maxlength JS
auto-hiding manual expiration date when irrelevant
- node access logic
- requirements logic
detect incompatible older version
detect missing Statistics module
detect misconfigured Statistics module
detect non-tree hierarchy in the module vocabulary
- taxonomy change logic for terms and vocabularies
- URL outbound rewriting logic to redirect term links to ad lists when applicable
- Views integration logic
expose virtual fields:
`expires`: field, sort, filter
`purge`: field
1 field handler for `purge`
default views logic scanning the `views/` folder, but no views provided
- configuration variables
`classified-max-length` for the maxlength JS
`classified-list-body` List display format
`classified-edit-modr8` (obsolete) modr8 integration
`classified-lifetime-default` default lifetime
`classified-lifetime-<tid>` per-tid lifetime overrides
`classified-grace` grace delay before purge
- 100% S0 Simpletest coverage
- pages
an overview page
term pages listing ads and ad counts
per-user ads profile tab page
- 7 advanced help pages
- custom CSS
specific formatting for `expires`
advanced help improvements
ads list custom formats
OK Paths
admin/content/node/ed-classified: ed_classified_admin_overview() = an admin page listing ads: redundant with admin/content
admin/content/ed-classified: ed_classified_admin_overview() = an admin page listing ads (duplicate): idem
ed-classified: ed_classified_page() = a page listing ads
user/%user/ed-classified: ed_classified_by_user() now at user/%user/classified = per-user ads list
admin/settings/ed-classified: dgf/ed_classified_admin_settings() = settings form
ad duration
default
per-ad_term override
grace period from expiration to purge
expiration notification
max body length
ad site contact link on posts: useless
In lists, show ad teaser OR body
rename field attachments: useless
New: activate modr8 on updates
admin/ed-classified/purge: _ed_classified_user_purge() = scheduled expiration: separated purge / expiration / notification
classified/scheduled/purge: purge expired node beyond the grace period
classified/scheduled/expire: unpublish nodes past their expiration date
classified/scheduled/notify/[half-life|pre-expire|pre-purge]: notify pre-expiration/purge
cron.php:
New: Drush commands
OK classified-purge / cl-p: trigger a purge
OK classified-expire / cl-e: trigger expiration
classified-notify [half-life|pre-expire|pre-purge] / cl-n (same): trigger notifications
OK Blocks
popular: ed_classified_get_popular_ads_list()
latest: ed_classified_get_latest_ads_list()
statistics: ed_classified_get_ad_stats()
OK Alterations
HFA classified node form: rename uploads as images.: doesn't seem worth keeping, imagefield/emfield is better
HF classified node form:
add JS ad size checker/blocker: non-jQuery ⇒ Reimplemented on jQuery
add hidden field to keep expire date: can be overriden in the browser, inserted in the submit handler instead
Add checkbox if user permissions allow it to reset expiration. Ignores administer ads: should be honored. Redone differently, with 3 update modes.
submit handler does validation job on expiration reset: moved to validation handler instead
classified node links:
HL add link to ad author page: redundant with author info on node
HL add link to contact
: titled as a way to suggest new categories, duplicates the normal contact link
HLA replace taxonomy/term/<tid>
links with ed_classified/<tid>
when <tid> belongs in the module vocabulary, in order to have a specific page take over instead of the default taxonomy term page for these. Done with hook_term_path() instead, for more generality.
HV build breadcrumbs trail
New: jQuery
OK Security
Permissions
'create classified ads'
'edit own classified ads'
'reset classified ad expiration'
'administer classified ads'
Missing, to match node.module
Note that “administer” right should include “reset expiration” and all the other rights.
Access
OK Views 2 integration
default Views: 2 created, then replaced by custom code. Still in the repository, but nothing specific to learn from them.
1 “time remaining” data definition, for field, argument, filter and sort, defining 2 distinct fields (date or duration)
add 1 field handler definition for purge date
Future features
add “remaining” format to both fields
create a better display plugin, or style the existing one better
New features
OK Active modr8 integration: resend updated nodes to moderation
-1 on grace means never delete
0 on grace means delete upon expire
Themeing
OK 'ed_classified_body' ⇒ array('arguments' ⇒ array('node')),: unneeded, use theme(node)
OK 'ed_classified_teaser' ⇒ array('arguments' ⇒ array('node')),: unneeded, use theme(node)
OK 'ed_classified_ending_date' ⇒ array('arguments' ⇒ array('ad_expiration_date')), ⇒ classified_expires($node)
'ed_classified_ads_block' ⇒ array('arguments' ⇒ array('ads', 'display_timestamp' ⇒ TRUE, 'display_counter' ⇒ FALSE, 'display_ad_category' ⇒ FALSE)),: theme_item_list used instead
'ed_classified_taxonomy' ⇒ array('arguments' ⇒ array('cats' ⇒ NULL, 'ads' ⇒ NULL)),
'ed_classified_adcount' ⇒ array('arguments' ⇒ array('count' ⇒ NULL)),
'ed_classified_taxonomy_catlist' ⇒ array('arguments' ⇒ array('cats' ⇒ NULL)),
'ed_classified_category_list_row' ⇒ array('arguments' ⇒ array('cat' ⇒ NULL, 'row_count' ⇒ NULL)),
'ed_classified_taxonomy_ads' ⇒ array('arguments' ⇒ array('ads' ⇒ NULL)),
'ed_classified_category_list_ad_row' ⇒ array('arguments' ⇒ array('ad' ⇒ NULL, 'rowcount' ⇒ NULL)),
'ed_classified_category_name' ⇒ array('arguments' ⇒ array('cat' ⇒ NULL)),
'ed_classified_category_description' ⇒ array('arguments' ⇒ array('cat' ⇒ NULL)),
'ed_classified_ads_stats' ⇒ array(): theme_table used instead
All currently as themeable functions, redo as templates
New
A “ad list” CCK build mode, used by lists generated by the module
Lifetimes in settings form formatted as a table