I'm having a conceptual sort of roadblock.
So, I'd like to make a custom Drupal module, with several different pages, each of which "does stuff".
I'm not understanding how to make/integrate different pages into my module, and what their URLS would be.
I do have this :
/* FILE : mymodule.module */
function mymodule_menu() {
$items = array();
$items['mymodule/landingpage'] = array(
'page callback' => 'mymodule_landing',
'access arguments' => array('access content'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
function mymodule_landing() {
$title = 'Hello World';
$content ='This is a simple Hello World Proof of Concept';
return theme_box($tile, $content);
}
And when I go to mysite.com/mymodule/landingpage, I see the content generated by mymodule_landing().
But this doesn't seem like what I want to do because the content for landingpage is generated inside the mymodule.module, and it leaves me super confused about how I'd go about making my mysite.com/mymodule/step2, ... , mysite.com/mymodule/step99 pages
I have the gut feeling that the code for each page should be in it's own corresponding file, and I'm not understanding how to do it, this doesn't seem like the right way.
Can you explain how I should be doing it, where the file should go (with my other module files, right?), and what URL it would be viewable at?
What you are doing so far is mostly correct (The "title" key is required for each item, so be sure to include that). Since the page callback is directed at mymodule_landing(), the content returned from that function will be displayed as your content on the page.
To make more pages (like step2, step99, etc) you would continue with creating more paths in mymodule_menu() like:
$items['mymodule/step2'] = array(
'title' => 'Step 2', // Required
'page callback' => 'mymodule_step2',
'access arguments' => array('access content'),
'type' => MENU_NORMAL_ITEM,
);
And so forth... You could use the same page callback mymodule_landing() and simply pass "page arguments" or each can have its own page callback.
To put your function mymodule_landing() in a separate file, you can use the file and file path keys (see below)
$items['mymodule/landingpage'] = array(
'title' => 'Landing Page', // Required
'page callback' => 'mymodule_landing',
'access arguments' => array('access content'),
'type' => MENU_NORMAL_ITEM,
'file' => 'mymodule.pages.inc',
'file path' => drupal_get_path('module', 'mymodule'),
);
You should put these files in your module directory (or sub-directory inside module directory and set the correct file path) and can access each page at mysite.com/mymodule/landingpage, mysite.com/mymodule/step2, etc.
Best Practices for Page Handler Include Files (read more at http://drupal.org/node/146172):
Module developers are free to split off page handlers for their modules however they choose. However, the following guidelines and standards are recommended:
Any module that has more than ~50 lines of code for page handler functions (including form handling functions if applicable) should split them off into a separate file. That reduces the overhead for PHP when loading modules, and therefore speeds up every single request on the site.
Page include files should be named in the form modulename.key.inc, where "modulename" is the name of the module and "key" is a one-word descriptive term for the types of page handlers it includes.
For most modules, splitting page handlers into two files -- example.admin.inc (for administrator-only pages) and example.pages.inc (for pages accessible by non-administrator users) -- is sufficient, and is the recommended practice. If a module has no non-administrator pages, it should just have a single example.admin.inc file. If a module has no administrator-only pages, it should just have a single example.pages.inc file.
Modules that have a large number of page handlers may choose to separate out page handlers even further. If so, each file should be grouped logically by function (for instance, admin pages related to theming, admin pages related to logging, other admin pages, and user-accessible pages) and clearly marked. Remember that splitting the module's page handlers up too far makes maintenance more difficult, and only one page handler include file is ever loaded regardless of how finely-grained the handler functions are separated.
Added just for reference: hook_menu() documentation
The page_example.module may also be of help to you.
Related
I want to create a full page, custom module. By this, I mean a module that is not wrapped into the main Drupal sites them. Here is my code:
myapp.module:
function myapp_menu()
{
$result = array();
$result['myapp/home'] = array(
'title' => 'My App Title', // Title of our page
'description'=> 'My App Web Site', // Description of our page
'page callback' => 'myapp_function',
'access arguments' => array('access content'), // permission to access this page
'type' => MENU_NORMAL_ITEM, // type of menu item
);
return $result;
}
function myapp_function(){
return theme('my_custom_template');
}
function myapp_theme(){
return array(
'my_custom_template' => array(
'template' => 'myapp-page',
),
);
}
myapp-page.tpl.php
Hello World
The problem is that, when the page is displayed, it is still kept within the main Drupal Sites main theme. I would like to make this page its own, full page, site. Can anyone help with doing this?
thanks
You can hack like this :
function myapp_function(){
print theme('my_custom_template');
exit;
}
Also you can use declaration options listed in https://api.drupal.org/api/drupal/modules%21system%21system.api.php/function/hook_theme/7.x
Parameters
array $existing: An array of existing implementations that may be used
for override purposes. This is primarily useful for themes that may
wish to examine existing implementations to extract data (such as
arguments) so that it may properly register its own, higher priority
implementations.
$type: Whether a theme, module, etc. is being processed. This is
primarily useful so that themes tell if they are the actual theme
being called or a parent theme. May be one of:
'module': A module is being checked for theme implementations.
'base_theme_engine': A theme engine is being checked for a theme that
is a parent of the actual theme being used. 'theme_engine': A theme
engine is being checked for the actual theme being used. 'base_theme':
A base theme is being checked for theme implementations. 'theme': The
actual theme in use is being checked. $theme: The actual name of
theme, module, etc. that is being being processed.
$path: The directory path of the theme or module, so that it doesn't
need to be looked up.
I am trying to make a module which generates output at a specific relative path say mysite.com/newcomment/
What I am trying to do:
On client side I have coded JS which makes ajax request to "mysite.com/newcomment/". If there is any new comment, on "mysite.com/newcomment/" output " have done comment on " is generated and same is shown on client side in a pop-up.
What I have done previously:
If I am making a page/article, header and footer code is coming with output.
I have also made a endpoint for it via web service but i don't want that-much complexity.
Am I doing it the right way any pointers or clues will be helpful.
Your question is very confusing but from the title it sounds like your looking for hook_menu
Check out: api.drupal.org
Your custom url will be created with code that looks like:
function my_module_menu() {
$items['example/feed'] = array(
'title' => 'Example RSS feed',
'page callback' => 'my_module_page',
'access arguments' => array('access content'),
'type' => MENU_CALLBACK,
);
return $items;
}
Then output the code on the page callback:
my_module_page {
return '<h2 class=test>Hello World</h2>';
}
While you normally want html to be generated using theme functions for better caching this should at least get you started.
Edit:
To print only the data such as in an ajax call the function should look like this. Of course only include the code for your version of Drupal:
my_module_page {
// Drupal 7
print 'string';
drupal_exit();;
// Drupal 6
print 'string';
module_invoke_all('exit');
exit;
}
You can't use wildcards in menu paths? A quick summary of my problem (which I've made sure makes sense, so you're not wasting your time): I have a menu which i'm showing on node pages of a certain content-type. My path to a node page would be like...
events/instal2010
...where instal2010 would be the name of an event (event is the content-type).
I'm using the Context and Menu Block modules to place a menu in the sidebar on that page...
Event (the default active item)
Programme
Visitor info
Book tickets
... where the path for Programme would be
events/instal2010/programme
So for this to work for many different events, those menu items need a wildcard in their path, e.g.
events/*/programme
Perhaps it's time to ditch menus and just use a block with php to determine what page we're on from the URL.
Any advice from experienced hands would be awsome, thanks.
You cannot create menu items with wildcards from the administrative interface of Drupal, but you can create menu items with wildcards in a module. I would recommend creating a custom module that uses hook_menu() to create the menu items. An example implementation would look something like:
function YOURMODULE_menu() {
$items = array();
$items['events/%/programme'] = array(
'title' => 'Programme',
'description' => 'Loads a program page',
'page callback' => 'YOUR CUSTOM FUNCTION NAME', // Custom function used to perform any actions, display the page, etc
'page arguments' => array(1), // Passes wildcard (%) to your page callback function
'access callback' => TRUE, // Change if you want to control access
'type' => MENU_NORMAL_ITEM, // Creates a link in the menu
'menu_name' => 'primary-links' // Adds the link to your primary links menu, change if needed
);
return $items;
}
In $items['events/%/programme'] = array(, the % is the wildcard and it will be passed to your page callback function. It may be helpful to read more about hook_menu() and the Anatomy of hook_menu may also help as well.
Kind-of a crazy question here...
I have a view display that's set up as a page. It looks great in theme A (desktop), but terrible in theme B (mobile). So I made a different version of the view for theme B. Since the desktop/mobile 'sites' are the same just with different themes, the url for this page will be the same regardless of hte theme selected.
So I would like to be able to point the user to:
mysite/this_crazy_view
and have the returned page select the proper view depending on which theme it's in. I know that if I were using blocks I would just assign the appropriate blocks to the page in question on a theme-by-theme basis, but since the displays are using page display I don't know what the right approach would be.
I would rather not rebuild the views as blocks if I can help it (if it can't be helped, so be it...) so I was hoping there was some way to conditionally load the view via the tpl.php file or something like that...
The code I'm using in my module (per #Clive 's recommendation below) is:
<?php
function bandes_custom_hook_menu() {
$items['charley_test'] = array(
'title' => 'Title',
'access arguments' => array('access content'),
'page callback' => 'bandes_custom_set_page_view',
'type' => MENU_NORMAL_ITEM );
return $items;
}
function bandes_custom_set_page_view() {
global $theme_key;
$view_name = $theme_key == 'mobile_jquery' ? 'course_views_mobile' : 'course_views';
$display_id = 'page_5';
return views_embed_view($view_name, $display_id);
}
?>
I've cleared the cache a number of times and tried a variety of different paths in the $items array. The course_views and course_views_mobile both definitely work on their own.
I was also wondering if I could just create a views-view--course-views--page-5.tpl.php which contains almost nothing aside from the views_embed_view(course_views_mobile, page_5) part? (Only on one of the two themes...)
Actually I think the answer was simpler than all of the above. The redirect thing was giving me fits, so I removed the module, reset the paths to what I had been using, and tried the template/theme approach instead.
This is: views-view--course-views--page-5.tpl.php, only used on the mobile theme, but referring to the non-mobile view (kinda gives me a headache, but it works)
<?php
//get the view
print "IM IN YR VUE, MESSING THNGZ UP!"; //yeah, I'm going to remove this part...
$view_name="course_views_mobile";
$display_id="page_5";
print views_embed_view($view_name, $display_id);
?>
Any reason that shouldn't work? (Or why it is a really bad idea?)
Me again :)
I just thought of an easy-ish way around this actually; if you can change the URL of your views to something other than the path you want to access them at (any path would do) you could implement a hook_menu() function in a custom module for that path, to make the choice depending on your theme:
function MYMODULE_hook_menu() {
$items['this_crazy_view'] = array(
'title' => 'Title',
'access arguments' => array('access content'),
'page callback' => 'MYMODULE_crazy_view_page',
'type' => MENU_CALLBACK // or MENU_NORMAL_ITEM if you want it to appear in menus as usual
);
return $items; // Forgot to add this orginally
}
function MYMODULE_crazy_view_page() {
global $theme_key;
$view_name = $theme_key == 'foo' ? 'theView' : 'theOtherView';
$display_id = 'page_1'; // Or whatever the page display is called
return views_embed_view($view_name, $display_id);
}
That should do the trick
I have a custom Drupal module displaying some data in a table. Each row has a link which if clicked will delete the relevant row. Specifically, when the link is clicked it will take the user to a confirmation page. This page is really just a drupal form which says 'are you sure' with two buttons: 'Yes', 'No'. I figure I will need to pass the rowID to the confirmation page.
My question: What is the typically way to pass data to a new page in Drupal 7? I guess I could just add the rowID to the URL and use the $_GET[] from the confirmation page... I don't think this is very safe and was wondering if there was a better 'Drupal' way.
Thanks!
You'd use something like the following
<?php
function yourmod_menu() {
// for examlple
$items['yourmod/foo/%/delete'] = array(
'title' => 'Delete a foo',
'page callback' => 'drupal_get_form',
'page arguments' => array('youmode_foo_delete_confirm', 2), // 2 is the position of foo_id
'access arguments' => array('delete foo rows'),
'type' => MENU_CALLBACK,
);
return $items;
}
function yourmod_foo_delete_confirm($form, &$form_state, $foo_id) {
// load the row
$foo = yourmod_get_foo($foo_id);
// build your form, if you need to add anything to the confirm form
// ....
// Then use drupal's confirm form
return confirm_form($form,
t('Are you sure you want to delete the foo %title?',
array('%title' => $foo->title)),
'path/to/redirect',
t('Some description.'),
t('Delete'),
t('Cancel'));
}
?>
You can look here for examples of how core modules do it (have look at node_delete_confirm)
The simplest solution would be to use an existing module created for this purpose:
http://drupal.org/project/entityreference_prepopulate (for entity references)
http://drupal.org/project/nodereference_url (for node references)
http://drupal.org/project/prepopulate (for other form values)
You can configure which form values can be set from the URL, then rewrite the fields displayed in your table to generate the necessary links.
If the data are nodes, you can make the link node/%/delete where % is the nid. Drupal knows how to handle the delete page, as its a core path. Then, the delete confirmation follows the rest of the system and is very 'Drupal'.
I am not sure if this changed at all in Drupal 7, but this is what I did for countless modules.