drupal--hook_menu - drupal

the info file is right,the following is my module file code. when i access the http://localhost/drupal/mymenu why it can't work.
<?php
function mymenu(){
$item = array();
$item['mymenu'] = array(
'description'=>'test1',
'page callback'=>'mymenu_test',
'access arguments' => array('access mymenu'),
'type'=>MENU_CALLBACK,
);
return $item;
}
function mymenu_perm(){
return array('access mymenu');
}
function mymenu_test() {
$output = 'hello world';
return $output;
}
i have gave the 'access mymenu' permission to the anonymous.

It should be
function mymenu_menu() {
...
}
You don't need the $item = array(); there also.

whenever you see a api function with hook_something, you have to replace the 'hook' part with the name of your module
in this case it's indeed mymenu_menu

Try the following: use function name as modulename_menu and use 'access arguments' => array('access content').
<?php
function test_menu(){
$item = array();
$item['mymenu'] = array(
'description'=>'test1',
'page callback'=>'mymenu_test',
'access arguments' => array('access content'),
'type'=>MENU_CALLBACK,
);
return $item;
}
function mymenu_test() {
$output = 'hello world';
return $output;
}

you need to flush menu cache(at least two times in drupal 7) after adding menu item with hook_menu.

Related

Drupal - custom module - Generate dynamic URL alias

I have a custom drupal module. I have a demo pages for different APIs I have. (Like, host.com/demo/abc or host.com/demo/bcd or host.com/demo/def ...)
hook_menu()
$items['demo/%'] = array(
'page callback' => 'xxx',
'page arguments' => array(1),
'access callback' => 'xxx',
....
);
I want to change the URL to host.com/abc/demo for all the demo pages. Since I cannot a wild card at the beginning of the hook (Like %/demo) I am considering URL alias. But how can I generate url alias dynamically for all the demo pages?
The best solution :
http://www.zyxware.com/articles/3636/drupal-how-to-create-url-alias-for-custom-menu-implementation-of-hook-pathauto
Otherwise :
Before you need to know that all dynamical solution available is not totally safe , take care before using it.
With url_alias you can try this, but you have to restrict by defined path to avoid flood insertion :
function mymodule_menu(){
$items= array();
$items['demo/%'] = array(
'page callback' => 'xxx',
'page arguments' => array(1),
'access callback' => 'xxx',
);
return $items;
}
function mymodule_init(){
global $language;
$path_allowed = array(
'abc',
'dbe'
); // restrict to avoid flood
if(arg(1) == 'demo' && in_array(arg(0), $path_allowed)) { // detect demo mode
$path = arg(1).'/'.arg(0);
$alias = arg(0).'/'.arg(1);
$a = db_query('SELECT alias FROM url_alias WHERE source = :source AND alias = :alias', array(':source' => $path, ':alias' => $alias))->fetchField();
if($a == null) ) {
db_insert('url_alias')->fields(array(
'source' => $path,
'alias' => $alias,
'language' => $language->language
))->execute();
}
}
}
Otherwise, I'm not sure but you can try this too , you can handle it from hook_init but it can cause some issue form all module loading init
function mymodule_init(){
if(arg(1) == 'demo') { // detect demo mode
$mycallbacks = array( // define your callback related
'abc' => 'mymodule_callback1',
'dbe' => 'mymodule_callback2',
);
if(isset($mycallbacks[arg(0)]) && function_exists($mycallbacks[arg(0)])) { // if callback is available
call_user_func($mycallbacks[arg(0)]); // call it
}
}
}
function mymodule_callback1(){ //do what you want }
function mymodule_callback2(){ //do what you want }
So , mysite.com/abc/demo will execute mymodule_callback1() and mysite.com/dbe/demo will execute mymodule_callback2()
Etc..
Clear all caches and see :)

Drupal - using views_embed_view with an external Drupal site

I have two Drupal sites hosted on different servers. In the main they need to operate separately however site1 has one specific content type which I'd like to show in a list on site2.
I can't simply use feeds to import as the original has to remain and if edited, the changes be instantly reflected on both sites. Site2 has no requirement to edit the content - only show it.
The content is already being presented in a list on site1. The list was created using views.
My intention was to call the view on site2 using the following code in a custom module.
function site2_menu() {
$items = array();
$items['content-from-site1'] = array(
'title' => 'Content from Site1',
'page callback' => 'site_two_list',
'access arguments' => array('access content'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
function site2_list() {
db_set_active('site1');
$content = views_embed_view('articles', 'default');
db_set_active('default');
return $content;
}
site1 DB is defined in the settings.php file.
However this isn't returning any data. Using the same approach on Site1 (without switching DBs) works fine.
Was I being over-optimistic in hoping this approach would work or am I missing something obvious?
If this isn't likely to work, what would the alternative be? I can do my own SQL query, but I'd prefer to use views for built in arguments, pagination, templates, etc.
Thanks.
I've not been able to use views_embed_view, however I have been able to use views_get_view to retrieve everything I need and iterate over the results myself. It's a very close second.
function site2_menu() {
$items = array();
$items['content-from-site1'] = array(
'title' => 'Content from Site1',
'page callback' => 'theme_site2_list',
'access arguments' => array('access content'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
function site2_theme() {
return array (
'site2_list_page' => array(
'arguments' => array('content' => NULL),
'template' => 'templates/site2-list-page'
)
);
}
function theme_site2_list() {
db_set_active('site1');
$view = views_get_view('articles');
$view->base_database = "site1";
$view->init_display();
$view->pre_execute();
$view->execute();
db_set_active('default');
foreach ($view->result as $key => $data) {
$content[$key]['nid'] => $data->nid;
$content[$key]['title'] => $data->node_title;
$content[$key]['body'] => $data->field_body;
$content[$key]['image'] => $data->field_field_image;
}
return theme('site2_list_page', array('content' => $content));
}
Then in site2-list-page.tpl.php I can use the $content array to do what I need. It's not quite as clean as a simple views_embed_view, but it's a close second and allows the content from one site to be pulled to another fairly easily.

Drupal 7 Hook_forms not working

Can anyone tell me why this is not working?
The drupal_render(drupal_get_form) is dynamically created in a foreach loop and put into a table theme.
Everything loads except the form fields. I've tried debugging by adding echos and exits to each form function call, but the page continues to load. I am not sure if these functions are simply not being called or if there is some other issue.
foreach( $w as $k => $v ) {
$r[] = array(
'$'.number_format($v->amount, 2),
date('F d, Y', $v->created),
filter_xss($v->paypal_email),
drupal_render(drupal_get_form(('toefl_tutors_admin_withdrawl_request_form_'.$v->id), $v->id))
);
}
function toefl_tutors_admin_withdrawl_request_forms($form_id, $args) {
$forms = array();
if (!empty($args) && $form_id == 'toefl_tutors_admin_withdrawl_request_form_' . $args[0]) {
$forms[$form_id] = array(
'callback' => 'toefl_tutors_admin_withdrawl_request_form',
'callback arguments' => array($args[0]),
);
}
return $forms;
}
function toefl_tutors_admin_withdrawl_request_form($form, &$form_state, $id = 0) {
$form['twid'] = array(
'#type' => 'hidden',
'#value' => $id
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Send Money'),
'#attributes' => array('class' => array('btn', 'btn-success'))
);
return $form;
}
I've solved the problem.
I needed to rename the hook_forms function to toefl_tutors_forms() because My module name is actually toefl_tutors not toefl_tutors_admin_withdrawl_request
Apparently and correct me if I am wrong, in order to use hook_forms you must name it mymodulename_forms, not mymodulename_xx_forms.
What confused me was hook_form works perfectly when you name the form function mymodulename_xx_form().

drupal module and php file

I'm trying to create a test module in drupal 6.x that loads php pages. I made a test.module and test.info file and also put inside the .php page. Below is the test.module code. But it doesnt work on my drupal_site/test I get page not found.
function test_perm() {
return array('access test content');
}
function test_contents() {
module_load_include('php', 'test', 'index');
}
function test_menu() {
$items = array();
$items['test'] = array(
'title' => t('Test'),
'description' => t('Test desc'),
'page callback' => 'test_page',
'access arguments' => array('access test content'),
'type' => MENU_NORMAL_ITEM
);
return $items;
}
function test_page() {
$page_array['test_arguments'] = array(
'#markup' => test_contents(),
);
return $page_array;
}
I'll take a guess that your test_contents() outputs HTML directly to the page buffer? This isn't the way Drupal works, it expects you to build up a string and return that in your $page_array variable.
Either change your test_contents() function to return the string not output it, or store the output in a temporary buffer and assign that to a string:
function test_page() {
// Start your buffer
ob_start();
// Output into the buffer
test_contents();
// Save the result to a string and close the buffer
$contents = ob_get_clean();
$page_array['test_arguments'] = array(
'#markup' => $contents,
);
return $page_array;
}

returning untemplated output in drupal from menu callback function

I have a drupal module with a function that returns an attachment text/plain,
function mymodule_menu() {
$items = array();
$items[MY_PATH] = array(
'title' => 'some page',
'page callback' => 'myfunction',
'type' => MENU_CALLBACK,
);
}
function myfunction()
{
drupal_set_header('Content-Type: text/plain');
return "some text";
}
But it returns the page in the page.tpl.php template, however I want it untemplated, how do I over-ride the theme to make it return plain text?
Thanks,
Tom
This will return plain text
function myfunction() {
drupal_set_header('Content-Type: text/plain');
print "some text";
exit(0);
}
Alternatively you can use the 'delivery callback' setting in your menu callback definition. Now your page callback function will be run through a custom function that just prints and exits, rather than calling drupal_deliver_html_page(), which is what outputs all the typical theme markup, etc.
function mymodule_menu() {
$items = array();
$items['MY_PATH'] = array(
'title' => 'some page',
'page callback' => 'myfunction',
'type' => MENU_CALLBACK,
'delivery callback' => 'mymodule_deliver_page',
);
return $items;
}
function mymodule_deliver_page($page_callback_result) {
print $page_callback_result;
exit(0);
}
The best and simplest solution is to just have your callback print your html and return nothing.
For example,
// Hooks menu to insert new url for drupal
function MYMODULE_menu() {
$items = array();
$items['member-stats.php'] = array(
'page callback' => '_MYMODULE_menu_callback',
'access callback' => TRUE,
);
return $items;
}
// Callback prints and doesn't return anything
function _MYMODULE_menu_callback() {
print "Hello, world";
}
if you'd create a template like html--barebones.tpl.php, containing just
<?php
drupal_set_header('Content-Type: text/plain');
print $barebones;
?>
you could hook that template to YOURTHEME_preprocess_html(), like so:
function YOURTHEME_preprocess_html(&$variables) {
if (array_key_exists('barebones',$_REQUEST)) {
$variables['barebones'] = $variables['page']['foo']['bar'];
$variables['theme_hook_suggestions'][] = 'html__barebones';
}
}
now, if you call your page with the additional query ?barebones, like drupal/foo/bar?barebones, it will return the barebones version.
theres a tricky bit in getting your result back. var_dump($variables['page']) to see where drupal left your text. Its been tucked inside the render array surrounded by all kind of info used to render the text, which you are not using. Making me wonder if it wouldnt be more efficient to just print it and exit() inside myfunction :-)
Your module can define template files (reference):
<?php
function mymodul_preprocess_page(&$variables) {
foreach ($variables['template_files'] as $file) {
$template_files[] = $file;
if ($file == 'page-node') {
$template_files[] = 'page-'. $variables['node']->type;
}
}
$variables['template_files'] = $template_files;
}
?>
By creating a new .tpl.php file for the page in question. E.g.
page-module.tpl.php
page-module.tpl.php would only need to be a simple page, e.g.
<?php
print $content;
?>

Resources