SlideShare a Scribd company logo
1 of 50
Download to read offline
The History and Future of Drupal
Theming
by Carl Wiedemann (c4rl)
Wednesday 2013-09-25 • 14:15
Hi!
c4rl
Carl Wiedemann
Where have we been?
Where are we going?
Discussion and
planning :)
2000
OO-based(!) theming,
somewhat overridable.
2001
Default markup in
core provides more
scalability.
2002
The well-known
theme() function
appears.
2003
Template-based
theming (xtemplate)
to avoid string
concatenation
(in some cases).
2005
PHPTemplate arrives.
Template variable
overrides exist.
FormAPI and altering
arrives in concept.
2007
Theme registry.
Preprocess functions,
.tpl.php file
overrides.
2007
hook_elements()
appears. "Structured"
vs "rendered" data
bring together modern
RenderAPI.
ALTER ALL
OF THE
THINGS
ALTER ALL
OF THE
THINGS
http://drupal.org/node/134478#comment-538674
Posted by bjaspan on October 15, 2007 at 1:39pm
"menu callbacks ought to return
structured data, not rendered data"
<?php
// OLD
return theme('foo', $bar);
<?php
// NEW
return array(
'#theme' => 'foo',
'#bar' => $bar,
);
hook_page_alter()
template_preprocess_foo()
template_preprocess()
template_process_foo()
template_process()
Templates can be overridden...
Preprocessors can be overridden...
Processors can be overridden...
Theme functions still exist...
hook_theme_registry_alter()...
by 2009
Many APIs. Theme
system is brittle,
inconsistent,
difficult to grok.
Based on what we’ve
built…
What do we need?
What do we need? (1)
Template-based markup that
can be extended and
overridden.
hook_theme(),
template_preprocess(), hook
suggestions, theme registry, Twig
(PHPTemplate).
What do we need? (2)
Abstracted, alterable
structure.
Render arrays, hook_node_view(),
hook_page_alter()
What do we need? (3)
Sensible, accessible, API.
theme(), drupal_render(), render()
/hide()/show().
2012
DrupalCon Denver Core
Convo, Twig
initiative, yay!
2012-2013
Twig conversion,
Portland Sprints,
killed process layer,
markup cleanup, yay.
So where are
we going?
8.x
Kill concatenation 1757550
Theme system architecture 2004872
Theme registry service 1886448
theme() deprecation 2006152
PRESENT
1. I believe the
biggest issue with
Theming is a brittle
RenderAPI.
PRESENT
2. I believe Render
API must move to an
OOP design.
9.x
Refactor RenderAPI
to be OO
1843798
http://lb.cm/arrays-of-doom
What does
might OO
RenderAPI look
like?
Influential design
patterns
Builder
Decorator
Builder
Builder pattern
Object creation is delegated
to a series of steps, then
finally invoked.
This fulfills the data
storage component of a
Renderable.
<?php
$car_builder = new CarBuilder();
$car_builder->setDoors(4);
$car_builder->setColor('red');
$car_builder->setMake('ford');
$car = $car_builder->createCar();
Builder pattern
Builder-esque Drupalisms
hook_node_view()
hook_page_alter()
Decorator
Decorator pattern
Behavior added to object
dynamically at runtime
without affecting other
objects of the same class.
This fulfills runtime
variable preparation.
<?php
class Coffee() {
function say() {
return 'I am coffee';
}
}
<?php
class CoffeeDecorator() extends Coffee {
function __construct($coffee) {
$this->coffee = $coffee;
}
function say() {
return $this->coffee->say();
}
}
<?php
class Coffee_Cream() extends CoffeeDecorator {
function say() {
return parent::say . ' with cream';
}
}
class Coffee_Sugar() extends CoffeeDecorator {
function say() {
return parent::say . ' with sugar';
}
}
$c = new Coffee_Cream(new Coffee_Sugar(new
Coffee()));
Decorator pattern
Decorator-esque Drupalisms
comment_preprocess_node()
mytheme_preprocess_node()
Getting markup
1. Get data.
-- START RENDER PROCESS --
2. Define renderable.
3. Alter renderable.
4. Render renderable.
A. Call theme callbacks.
i. Call preprocessors.
ii. Invoke template.
-- END RENDER PROCESS --
5. Send markup to client.
Disclaimer:
Let’s not get
hung-up on
implementation
:)
Renderable definition
<?php // D7/D8
return array(
'#theme' => 'node',
'#node' => $node,
);
<?php // D9?
return new RenderableBuilder('ThemeNode', array(
'node' => $node,
));
Altering
<?php // D7/D8
function mymodule_node_view(&$node) {
$node->content['image']['#theme'] = 'foo';
}
<?php // D9?
function mymodule_node_view_alter($builder) {
$builder->get('image')->setBuildClass('ThemeFoo');
}
Variable prepare (1)
<?php // D7/D8
function template_preprocess_foo(&$vars) {
$new_title = $vars['title'] .
' overridden by foo';
$vars['title'] = $new_title;
}
Variable prepare (2)
<?php // D9
/**
* @file Theme class for foo.tpl.php.
*/
class ThemeFoo extends Renderable {
function prepare() {
$new_title = $this->get('node')->get('title')
. ' overridden by foo;
$this->set('title', $new_title);
}
}
MOAR
http://github.com/c4rl/renderapi
Discussion and
planning :)
THANK YOU!
WHAT DID YOU THINK?
Locate this session at the
DrupalCon Prague website:
http://prague2013.drupal.org/node/1863
Click the “Take the survey” link

More Related Content

Viewers also liked

Leanmetings
LeanmetingsLeanmetings
LeanmetingsAtrendia
 
Atrendia - Who should you believe? - email mythbusters 2 7
Atrendia - Who should you believe? - email mythbusters 2 7Atrendia - Who should you believe? - email mythbusters 2 7
Atrendia - Who should you believe? - email mythbusters 2 7Atrendia
 
Basic Drupal Recipes - BADCamp 2009
Basic Drupal Recipes - BADCamp 2009Basic Drupal Recipes - BADCamp 2009
Basic Drupal Recipes - BADCamp 2009c4rl
 
jQuery and_drupal
jQuery and_drupaljQuery and_drupal
jQuery and_drupalBlackCatWeb
 
Drupal.js: Best Practices for Managing Javascript in Drupal
Drupal.js: Best Practices for Managing Javascript in DrupalDrupal.js: Best Practices for Managing Javascript in Drupal
Drupal.js: Best Practices for Managing Javascript in DrupalBryan Braun
 
Intro To jQuery In Drupal
Intro To jQuery In DrupalIntro To jQuery In Drupal
Intro To jQuery In DrupalMatthew Farina
 
Render API - Pavel Makhrinsky
Render API - Pavel MakhrinskyRender API - Pavel Makhrinsky
Render API - Pavel MakhrinskyDrupalCampDN
 
Drupal Javascript for developers
Drupal Javascript for developersDrupal Javascript for developers
Drupal Javascript for developersDream Production AG
 

Viewers also liked (8)

Leanmetings
LeanmetingsLeanmetings
Leanmetings
 
Atrendia - Who should you believe? - email mythbusters 2 7
Atrendia - Who should you believe? - email mythbusters 2 7Atrendia - Who should you believe? - email mythbusters 2 7
Atrendia - Who should you believe? - email mythbusters 2 7
 
Basic Drupal Recipes - BADCamp 2009
Basic Drupal Recipes - BADCamp 2009Basic Drupal Recipes - BADCamp 2009
Basic Drupal Recipes - BADCamp 2009
 
jQuery and_drupal
jQuery and_drupaljQuery and_drupal
jQuery and_drupal
 
Drupal.js: Best Practices for Managing Javascript in Drupal
Drupal.js: Best Practices for Managing Javascript in DrupalDrupal.js: Best Practices for Managing Javascript in Drupal
Drupal.js: Best Practices for Managing Javascript in Drupal
 
Intro To jQuery In Drupal
Intro To jQuery In DrupalIntro To jQuery In Drupal
Intro To jQuery In Drupal
 
Render API - Pavel Makhrinsky
Render API - Pavel MakhrinskyRender API - Pavel Makhrinsky
Render API - Pavel Makhrinsky
 
Drupal Javascript for developers
Drupal Javascript for developersDrupal Javascript for developers
Drupal Javascript for developers
 

Similar to The History and Future of Drupal Theming.

Drupal Best Practices
Drupal Best PracticesDrupal Best Practices
Drupal Best Practicesmanugoel2003
 
D7 theming what's new - London
D7 theming what's new - LondonD7 theming what's new - London
D7 theming what's new - LondonMarek Sotak
 
Convert modules from 6.x to 7.x
Convert modules from 6.x to 7.xConvert modules from 6.x to 7.x
Convert modules from 6.x to 7.xJoão Ventura
 
Learning the basics of the Drupal API
Learning the basics of the Drupal APILearning the basics of the Drupal API
Learning the basics of the Drupal APIAlexandru Badiu
 
The Render API in Drupal 7
The Render API in Drupal 7The Render API in Drupal 7
The Render API in Drupal 7frandoh
 
8 things to know about theming in drupal 8
8 things to know about theming in drupal 88 things to know about theming in drupal 8
8 things to know about theming in drupal 8Logan Farr
 
Advanced Php - Macq Electronique 2010
Advanced Php - Macq Electronique 2010Advanced Php - Macq Electronique 2010
Advanced Php - Macq Electronique 2010Michelangelo van Dam
 
Migrating Legacy Data (Ruby Midwest)
Migrating Legacy Data (Ruby Midwest)Migrating Legacy Data (Ruby Midwest)
Migrating Legacy Data (Ruby Midwest)Patrick Crowley
 
Валентин Мацвейко та Владислав Мойсеєнко — D8: Migrate Yourself: code->module...
Валентин Мацвейко та Владислав Мойсеєнко — D8: Migrate Yourself: code->module...Валентин Мацвейко та Владислав Мойсеєнко — D8: Migrate Yourself: code->module...
Валентин Мацвейко та Владислав Мойсеєнко — D8: Migrate Yourself: code->module...LEDC 2016
 
Migrate yourself. code -> module -> mind
Migrate yourself. code -> module -> mindMigrate yourself. code -> module -> mind
Migrate yourself. code -> module -> mindValentine Matsveiko
 
JQuery In Drupal
JQuery In DrupalJQuery In Drupal
JQuery In Drupalkatbailey
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasminePaulo Ragonha
 
In-depth changes to Drupal 8 javascript
In-depth changes to Drupal 8 javascriptIn-depth changes to Drupal 8 javascript
In-depth changes to Drupal 8 javascriptThéodore Biadala
 
HTML5 for the Silverlight Guy
HTML5 for the Silverlight GuyHTML5 for the Silverlight Guy
HTML5 for the Silverlight GuyDavid Padbury
 
Upgrade your javascript to drupal 8
Upgrade your javascript to drupal 8Upgrade your javascript to drupal 8
Upgrade your javascript to drupal 8Théodore Biadala
 
Working with databases in Perl
Working with databases in PerlWorking with databases in Perl
Working with databases in PerlLaurent Dami
 
Drupal II: The SQL
Drupal II: The SQLDrupal II: The SQL
Drupal II: The SQLddiers
 
JDay Deutschland 2015 - PHP Design Patterns in Joomla!
JDay Deutschland 2015 - PHP Design Patterns in Joomla!JDay Deutschland 2015 - PHP Design Patterns in Joomla!
JDay Deutschland 2015 - PHP Design Patterns in Joomla!Yves Hoppe
 

Similar to The History and Future of Drupal Theming. (20)

Drupal Best Practices
Drupal Best PracticesDrupal Best Practices
Drupal Best Practices
 
D7 theming what's new - London
D7 theming what's new - LondonD7 theming what's new - London
D7 theming what's new - London
 
Convert modules from 6.x to 7.x
Convert modules from 6.x to 7.xConvert modules from 6.x to 7.x
Convert modules from 6.x to 7.x
 
Learning the basics of the Drupal API
Learning the basics of the Drupal APILearning the basics of the Drupal API
Learning the basics of the Drupal API
 
The Render API in Drupal 7
The Render API in Drupal 7The Render API in Drupal 7
The Render API in Drupal 7
 
8 things to know about theming in drupal 8
8 things to know about theming in drupal 88 things to know about theming in drupal 8
8 things to know about theming in drupal 8
 
Advanced Php - Macq Electronique 2010
Advanced Php - Macq Electronique 2010Advanced Php - Macq Electronique 2010
Advanced Php - Macq Electronique 2010
 
Migrating Legacy Data (Ruby Midwest)
Migrating Legacy Data (Ruby Midwest)Migrating Legacy Data (Ruby Midwest)
Migrating Legacy Data (Ruby Midwest)
 
Валентин Мацвейко та Владислав Мойсеєнко — D8: Migrate Yourself: code->module...
Валентин Мацвейко та Владислав Мойсеєнко — D8: Migrate Yourself: code->module...Валентин Мацвейко та Владислав Мойсеєнко — D8: Migrate Yourself: code->module...
Валентин Мацвейко та Владислав Мойсеєнко — D8: Migrate Yourself: code->module...
 
Migrate yourself. code -> module -> mind
Migrate yourself. code -> module -> mindMigrate yourself. code -> module -> mind
Migrate yourself. code -> module -> mind
 
JQuery In Drupal
JQuery In DrupalJQuery In Drupal
JQuery In Drupal
 
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and JasmineSingle Page Web Applications with CoffeeScript, Backbone and Jasmine
Single Page Web Applications with CoffeeScript, Backbone and Jasmine
 
In-depth changes to Drupal 8 javascript
In-depth changes to Drupal 8 javascriptIn-depth changes to Drupal 8 javascript
In-depth changes to Drupal 8 javascript
 
HTML5 for the Silverlight Guy
HTML5 for the Silverlight GuyHTML5 for the Silverlight Guy
HTML5 for the Silverlight Guy
 
Upgrade your javascript to drupal 8
Upgrade your javascript to drupal 8Upgrade your javascript to drupal 8
Upgrade your javascript to drupal 8
 
Fatc
FatcFatc
Fatc
 
Working with databases in Perl
Working with databases in PerlWorking with databases in Perl
Working with databases in Perl
 
Drupal 8 Services
Drupal 8 ServicesDrupal 8 Services
Drupal 8 Services
 
Drupal II: The SQL
Drupal II: The SQLDrupal II: The SQL
Drupal II: The SQL
 
JDay Deutschland 2015 - PHP Design Patterns in Joomla!
JDay Deutschland 2015 - PHP Design Patterns in Joomla!JDay Deutschland 2015 - PHP Design Patterns in Joomla!
JDay Deutschland 2015 - PHP Design Patterns in Joomla!
 

Recently uploaded

08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking MenDelhi Call girls
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CVKhem
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Servicegiselly40
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024Rafal Los
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 

Recently uploaded (20)

08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men08448380779 Call Girls In Greater Kailash - I Women Seeking Men
08448380779 Call Girls In Greater Kailash - I Women Seeking Men
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
CNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of ServiceCNv6 Instructor Chapter 6 Quality of Service
CNv6 Instructor Chapter 6 Quality of Service
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024The 7 Things I Know About Cyber Security After 25 Years | April 2024
The 7 Things I Know About Cyber Security After 25 Years | April 2024
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 

The History and Future of Drupal Theming.