Override callback function in Drupal7 - php

I am using blog module. I can access it using this URL: http://localhost/drupal/blog. I have put some posts.
In the blog content type, I have added a field such as posted date. When I open the same URL http://localhost/drupal/blog, blog posts are coming using ordering on submitted date.
Now I want that posts should be list out using order by newly added field "posted_date". I don't want to change default functionality defined in the blog.pages.inc page.
please suggest!

Create this function in module_name.module file in the custom module.
Ex: sites/all/modules/custom/module_name/moduleName.module
/**
* Implements hook_menu().
*/
function moduleName_menu() {
$items['blog'] = array(
'title' => 'Blogs',
'page callback' => 'blog_list',
'access callback' => TRUE,
'file' => 'page_name.inc',
'type' => MENU_CALLBACK
);
}
Create a file moduleName.pages.inc and define callback function.
Exm: sites/all/modules/custom/moduleName/moduleName.pages.inc
function blog_list() {
return t('welcome blog');
}
I hope it will work for you cheers!

Related

How to call Custom Module in Drupal

I am new to Drupal, I have made a custom module using PHP, which shows List of Student's with Information, and want to call it, on click of Submenu item, named, student Info. Please guide me by step wise step procedure.
The starting place to look for generating a "page callback" (essentially making a url active in drupal) would be hook_menu. As suggested take a look at the documentation but a starting point to actually make your callback work would be this in a my_module.module file:
/**
* Implements hook_menu().
*/
function my_module__menu() {
$items = array();
$items['student-info'] = array(
'title' => 'Student Info', // This becomes the page title
'description' => 'Information about students.', // this is the link description
'page callback' => 'function_name_that_outputs_content', // this is the page callback function that will fire
'type' => MENU_CALLBACK, // this is the type of menu callback, there are several that you can use depending on what your needs are.
);
return $items; // make sure you actually return the items.
}
/**
* Output the page contents when someone visits http://example.com/student-info.
*/
function function_name_that_outputs_content() {
$output = 'My page content'
return $output;
}

CakePHP prepopulate form with data from a link

Assume I'm in my items controller.
Ok say I am in my view action (the url would be something like /items/view/10012?date=2013-09-30) which lists a list of items that belongs to a client on a given date.
I want to link to add a new item. I would use the htmlhelper like so:
echo $this->Html('action'=>'add');
In my add action I have a form which has fields like client_id and item_date.
When I'm in my view action I know these values as I am viewing the items for a specific client on a specific date. I want to pass these variables to my add action so it will prefill those fields on the form.
If I add a query string in my link ('?' => array('client_id'=>$client_id)) it breaks the add action as it will give an error if the request is not POST. If I use a form->postLink I get another error as the add action's POST data must only be used for adding the record, not passing data to prefill the form.
I basically want to make my link on the view page pass those 2 variables to the add action in the controller so I can define some variables to prefill the form. Is there a way to do this?
Here is my add controller code. It may differ in content a bit from my question above as I have tried to simplify the question a bit but the concept should still apply.
public function add(){
if ($this->request->is('post')) {
$this->Holding->create();
if ($this->Holding->save($this->request->data)) {
$this->Session->setFlash(__('Holding has been saved.'), 'default', array('class' => 'alert alert-success'));
return $this->redirect(array('action' => 'index'));
}
$this->Session->setFlash(__('Unable to add your holding.'), 'default', array('class' => 'alert alert-danger'));
}
$this->set('accounts', $this->Holding->Account->find('list'));
$sedol_list = $this->Holding->Sedol->find('all', array(
'fields' => array(
'id', 'sedol_description'
),
'recursive' => 0,
'order' => 'description'
)
);
$this->set('sedols', Hash::combine($sedol_list, '{n}.Sedol.id', '{n}.Sedol.sedol_description') );
}
Why not use proper Cake URL parameters?
echo $this->Html->link('Add Item', array(
'action' => 'add',
$client_id,
$item_date
));
This will give you a much nicer URL like:
http://www.example.com/items/add/10012/2013-09-30
And then in your controller, you modify the function to receive those parameters:
public function add($client_id, $item_date) {
// Prefill the form on this page by manually setting the values
// in the request data array. This is what Cake uses to populate
// the form inputs on your page.
if (empty($this->request->data)) {
$this->request->data['Item']['client_id'] = $client_id;
$this->request->data['Item']['item_date'] = $item_date;
} else {
// In here process the form data normally from when the
// user has submitted it themselves...
}
}

Add product selection widget to custom attribute in Magento

Does anyone know how can I add a custom product attribute with a widget renderer?
You can see this in Promo rules if you select SKU you'll got an Ajax popup with product selection.
so how would I go about it?
in :
$installer->addAttribute(Mage_Catalog_Model_Product::ENTITY...
In other words, how can I use a widget to select custom attribute values?
EDIT:
The scenario is as follows:
I would like to create a product attribute that will, upon a button click, open a product selection widget.
After the selection, the selected SKU's will go in in a comma delimited format.
This behavior can be seen in the catalog and shopping cart price rules.
If you filter the rule by SKU (SKU attribute must be enabled to "apply to rules"), you'll get a field and a button that will open the product selection widget.
Here is some thoughts that should get you going on the right track:
First, in a setup script, create your entity:
$installer->addAttribute('catalog_product', 'frontend_display', array(
'label' => 'Display Test',
'type' => 'varchar',
'frontend_model' => 'Test_Module/Entity_Attribute_Frontend_CsvExport',
'input' => 'select',
'required' => 0,
'user_defined' => false,
'group' => 'General'
));
Make sure to set the frontend_model to the model that you are going to use. The frontend model affects the display of the attribute (both in the frontend and the adminhtml sections).
Next, create yourself the class, and override one or both of the following functions:
public function getInputType()
{
return parent::getInputType();
}
public function getInputRendererClass()
{
return "Test_Module_Block_Adminhtml_Entity_Renderer_CsvExport";
}
The first (getInputType()) is used to change the input type to a baked in input type (see Varien_Data_Form_Element_* for the options). However, to set your own renderer class, use the latter function - getInputRendererClass(). That is what I am going to demonstrate below:
public function getElementHtml()
{
return Mage::app()->getLayout()->createBlock('Test_Module/Adminhtml_ExportCsv', 'export')->toHtml();
}
Here, to clean things up, I am instantiating another block, as the element itself doesn't have the extra functions to display buttons and the like.
Then finally, create this file:
class Test_Module_Block_Adminhtml_ExportCsv extends Mage_Adminhtml_Block_Widget
{
protected function _prepareLayout()
{
$button = $this->getLayout()->createBlock('adminhtml/widget_button')
->setData(array(
'label' => $this->__('Generate CSV'),
'onclick' => '',
'class' => 'ajax',
));
$this->setChild('generate', $button);
}
protected function _toHtml()
{
return $this->getChildHtml();
}
}
This doesn't cover the AJAX part, but will get you very close to getting the rest to work.

Drupal 6: Make a menu_hook() return a specific view

I created a hook in order to add an item to the administrator's menu. When the user clicks on the item, I want to return the content of a specific view I created. How should I return the view?
My current code looks like:
function my_view_menu(){
$items['view'] = array(
'title' => 'Report',
'page callback' => 'return_my_view',
'access arguments' => array('access content'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
function return_my_view(){
return t("Hello!");
}
EDIT:
As suggested by Berdir, this the correct way to call a view:
function return_my_view(){
$viewName = 'my_report'; // use the machine readable name of the view
return views_embed_view($viewName);
}
You could just add a menu item in the view itself...and restrict access (to the view) to the admin role of choice :)
In your view choose "page" and click
on the "Add Display" button (if there isn't already a page display).
Under
"Page Settings" add a Path and a
Normal Menu-Entry in the Navigation
Menu
Next Under Basic Settings
change the access to Role based and
choose the role(s) that should have
access
Finally go to the
navigation menu settings and drag
the new menu item to the desired
place in the Administer menu
You want views_embed_view(), see http://web.archive.org/web/20110213234806/http://thedrupalblog.com/embedding-view-drupal-6-using-views-embed-view
views_embed_view() is the correct call. If you are getting a blank page, try checking your apache error log to see if there are any php errors. I also notice that in your revised example you used $viewName = "my-report", but views_embed_view() expects the machine readable name of the view, which only allows for alphanumeric and underscore characters. Perhaps you are using the incorrect name?
Third technique: Once you have created a Page Display for a View, Views will provision that page with a menu entry. Once that exists, it is possible to duplicate that menu entry for your own purposes.
Create a module with a weight of at least 11 (higher weight than Views)
Implement hook_menu_alter() and duplicate the View entry.
function example_menu_alter(&$items) {
$items['admin/new/path'] = $items['original/view/path'];
}
This approach is somewhat convoluted, but is sometimes a useful alternative for Views or other "page" content you want to clone.
In addition to berdir's comment, you can also skip the intermediate callback function and just call views_embed_view directly from your menu router:
function hook_menu(){
$items['path/to/my/view'] = array(
'title' => 'Report',
'page callback' => 'views_embed_view',
'page arguments' => array('my-view-name'),
'access arguments' => array('access content'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}

Difference in rendering when visiting node/1 and programmatically loading it

A node loads a profile of a user (external database + views). All of this works when I visit: node/123/profile/id/3. Now I have implemented hook_menu() in order to load any profile page and have nicer URLs.
When I load it myself for some reason $left in page.tpl.php is suddenly empty and many more variables seem not to be loading. I have tried many different functions to render and create the correct $output but realized that node_show() seems to be the function of choice.
Testing has shown now that for some reason hook_nodeapi() calls are ignored.
My code:
/**
* Implementation of hook_menu
*/
function modulename_menu() {
$items = array();
$items['my/nice/url/profile'] = array(
'description' => 'This page holds a view that shows profiles based on the %',
'page callback' => 'website_profile_load',
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Menu path wildcard callback
*/
function website_profile_load() {
$output = node_show(node_load(1221), false, true);
return $output;
}
So what is the correct way to do this and get Panels (see comment below) to load correctly?
UPDATE:
I am using table wizard and Views 2 to connect to another database with information about people that aren't users of the system. This is an alumni page, the page is administered externally and showed internally (nothing I can do about, have to make this work :)
Just discovered that Panels aren't loaded at all. So even if the node I am trying to load is uses panels for some reason none of that is loaded.
/**
* Menu path wildcard callback
*/
function website_profile_load($uid = null) {
if (!$uid) {
global $user; // if no user passed in argument, show current user profile
$uid = $user->uid;
}
$output = drupal_render(content_profile_show_profiles($uid));
}
There are many reasons why rendering the result of a node_load is different from going to the stock Drupal path /node. It is way too much to go over here honestly but the short answer is that you have to define a template/theme and blocks etc for each page you create. Just because you make a new path and do a node_load in the callback for that path doesn't mean Drupal can automagically know how you want to display that content. It simply loads data from the node and it is available to do whatever you please with it after that. This is why you get a blankish looking page instead of what you'd expect from going through /node.
However I will offer this simple solution since it sounds like you want the exact same page you'd get when you go to 'node/123/profile/id/3' but accessible through a link you define yourself. You just need to setup a redirect in your hook_menu like so:
$items['my/nice/url/profile'] = array(
'description' => 'This page holds a view that shows profiles based on the %',
'page callback' => 'drupal_goto',
'page arguments' => 'node/123/profile/id/3',
'access callback' => TRUE,
'type' => MENU_CALLBACK);
This is essentially saying that when you navigate to 'my/nicer/url/profile' it runs: drupal_goto('node/123/profile/id/3');
I found the answer to be that apparently somewhere in the pipeline of creating a node Drupal uses $path (that is originally set by $_GET['q']) and sometimes also $_GET['q'] to determine how to render the page. NOTE that I am using Panels and Ctools Page Manager modules in order to get my things working correctly.
It turns out Panels, if you search the code, looks at $_GET['q'] for quite an amount of things.
Here is what I ended up with:
/**
* Implementation of hook_menu
*/
function modulename_menu() {
$items = array();
// For department and having nice URL's for their profile pages.
$items['my/nice/url/profile/%'] = array(
'description' => 'This page holds a view that shows profiles based on the %',
'page callback' => 'website_profile_load',
'page arguments' => arg(4),
'access callback' => TRUE,
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Menu path callback
*/
function website_profile_load($id = NULL) {
// Rename the query internally since other functions base the design
// on the way the query is structured and not simply by the node which
// is currently loading.
if(!empty($id)) {
$path = $_GET['q'] = 'node/1221/profile/id/' . $id;
}
// Use ctools function to correctly display node view since
// this site heavily uses ctools rendering for panels and
// web parts / web pages.
drupal_load('module', 'page_manager');
ctools_include('node_view', 'page_manager', 'plugins/tasks');
if(function_exists('page_manager_node_view')) {
$output = page_manager_node_view(node_load(1221));
} else {
// Will display incorrectly but still load the UI
$output = node_page_view(node_load(1221));
}
return $output;
}
And it works :)

Categories