I have inherited a concrete 5 project and am debugging why certain 'areas' on the page do not show up the 'inline editing' feature.
The version is 5.5.1.
Essentially there is a page where it lists some items and each item has some div's to contain some information about each one, e.g name, description:
<div class = "description"></div>
The issue is that only one of the description elements is editable - I have worked out that this could be because the 'area' is name statically thus:
<div class = "description">
$a = new Area('Property Details');
$cont = Page::getByID($page->getCollectionID());
$regexMatchThis = $a->display($cont);
</div>
So therefore there is only one area called 'Property Details' allowed to be editable. Am I ciorrect, and how can I name the area so that it reads the correct data but can be uniquely named so that it can be editable?
Help appreciated.
Pekka is correct, but I'm hesitant to litter the answer discussion with another (long) explanation.
Areas are dynamic based on the name. Thus, "Property Details 1" is different than "Property Details 01".
You could do something like:
for ($i = 1; $i <= 10; $i++) {
$a = new Area('Property Details ' + $i);
$a->display();
}
And you'd get 10 sequentially named "Property Details x" areas, from 1 - 10.
Let's say you add content block to them. As long as they remain with the exact same names, then the blocks will work as expected. You could even change the first line to:
for ($i = 10; $i >= 1; $i--) {
In that case, you'd get the areas named sequentially downward (10, 9, 8...) and C5 would keep the content blocks in their original areas -- so they'd all be in reverse.
But let's say you do:
for ($i = 11; $i <= 20; $i++) {
Now you get 10 areas (11, 12, 13...), and all are blank. The content blocks have basically disappeared. You can create new content blocks if you want. But then go ahead and put the original loop back in (1, 2, 3...). Your original content blocks are back -- just like before.
This really long explanation just goes to show that C5 creates a block based on a name, and that name becomes the key. It can be anything. You can base it on the page name, or dynamically generate it, or whatever. You just can't change it once it's been created (if you don't want to "lose" the blocks).
But... I'll agree with Pekka again here... you probably don't want to do this. Not knowing your goal, you're creating (or prolonging) a very brittle solution that's difficult to maintain. Pekka suggests creating subpages for each property, then you can use a page list block to "pull" the applicable attributes. Or, if you don't want to create separate pages, use Jordan's Designer Content block -- http://www.concrete5.org/marketplace/addons/designer-content/ . Have a single area ("Property Details"), and add a block for each property. Much easier to delete, reorder, etc.
Edit to address Sphere's first two questions:
Adding blocks to areas is really straightforward. As long as the areas don't have duplicate names, you click on it just like you've tried previously, and add a block. I'm not sure what block type your particular site needs -- that's specific to your site. It might just be a Content block, or maybe a Pagelist block with a particular template, where the previous developer set it up to "list" one page per block instance, per area (which would be REALLY weird, but you never know...). Or, maybe it's a block type created from the Designer Content block which I mentioned earlier. Poking around on the existing blocks should give you an idea. Also, I find that sometimes they write out some identifying ID in the HTML. So, the source is something like .
As for your code sample: Yes, $cont is page. The code that Pekka and I provided ($a->display()) basically does:
Initialize an area called 'Property Details' (or 1 or 2 or whatever). This is the key, as discussed.
Display it, defaulting to displaying it "for" the current page. This is different than "on" the current page. It will always display on the current page... what you pass as an argument to ->display() is more like "the page that the area should be pulled from". So if you could theoretically pass $thePageObjectForPropertyOnMainStreet, and it would display that page's 'Property Details' area. Using $cont is unnecessary. As it creating it (it already exists).
But... now that I think of it, that might be what he tried to do. $cont might have been a reference to individual property pages. Those pages might have an area called "Property Details", and this his loop serves to "pull the area" from those pages. But, $cont would have looked different.
You can hardcode this by doing something like $cont = Page::getByID(x);, where x is the cID for a property page, which has an area called "Property Details". You can get the cID in the URL after you edit and save it.
Yup, that code seems to be defining only one area (and doing some unrelated things in between).
If the second area you desire doesn't exist yet, just make up a second one like so:
<div class = "description">
<?php
$a = new Area('Some more info');
$a->display(); `
?>
</div>
Related
I have the issue that one of the pages in a TYPO3 (11.5.20) environment contains dozens of subpages, which would overly extend the HMENU displayed on the frontend. The suggestion by a colleague was to hide all the subpages in said menu and instead display them on a separate menu embedded on the page itself. This basically means we have to make the subpages hidden for only one specific menu, not for all of them, ruling out the possibility to hide the subpages for navigation by the backend.
To have this functionality not just applying to a single, statically defined page, my idea to approach this would be to register a separate page layout for pages with this requirement and somehow configure HMENU in Typoscript to ignore subpages of that given layout. What I found is the itemArrayProcFunc for processing menu arrays; what I would do is to simply return an empty array with it if said page layout applies. I am encountering two problems though:
The function I have defined seems not to get called. I am including the script like in the Typoscript snippet below, but even when deliberately throwing an exception inside, there is no feedback on it whatsover by TYPO3, with the menu displaying all pages as usual. Is that method of inclusion possibly outdated? The official TYPO3 doc dictates USER and USER_INT for registering custom functions, but I'm not exactly sure how to make this work together with itemArrayProcFunc.
Even if the function worked, I'm not sure how to retrieve the layout of the respective parent page, or if it is even possible to retrieve it at all.
I'm assuming there are some major points regarding custom functions within Typoscript I might have missed (to be fair though - TYPO3's documentation is not exactly transpicuous). Could anyone possibly give me a hint on it? Is there maybe even a more elegant way to hide menus from specific pages?
lib.ts (snippet):
includeLibs.user_menuItemArrayProcFunc = EXT:lraffb_intern/Classes/MenuItemArrayProcFunc.php
lib {
...
20 = HMENU
20 {
stdWrap {
outerWrap = <nav class="navigation">|</nav>
}
entryLevel = 0
1 = TMENU
1 {
wrap = <ul>|</ul>
NO = 1
NO {
allWrap = <li>|
wrapItemAndSub = |</li>
itemArrayProcFunc = user_menuItemArrayProcFunc->process
}
ACT < .NO
ACT {
allWrap = <li class="act">|
}
}
2 < .1
3 < .2
4 < .3
5 < .4
}
...
}
MenuItemArrayProcFunc.php:
<?php
class MenuItemArrayProcFunc {
public function process($menuArr, $conf) {
if (PAGE_LAYOUT == 'pagets__left_no_subpages') // retrieve the page layout here somehow
return [];
return $menuArr;
}
}
This basically means we have to make the subpages hidden for only one specific menu, not for all of them, ruling out the possibility to hide the subpages for navigation by the backend.
Well - actually this is the solution you are looking for but just the other way around. Set those pages to hide in menus and then use the includeNotInMenu parameter to still use them in all menus except the one you mentioned.
https://docs.typo3.org/m/typo3/reference-typoscript/main/en-us/ContentObjects/Hmenu/Index.html#includenotinmenu
Depending on a flag (that could be the page layout) you should differ the rendering of menus. That would be easy if you render your menus with FLUID as you can insert conditions in an easier way than in TypoScript.
e.g.: Depending on your condition you render the second level or skip it.
On page rendering you have all fields from pages record, including your flag. When you call the menu partial just remember to insert the flag in the arguments.
I am trying to create a module which has both frontend and backend functionality. Like I need to ask for the city in the home page when the store loads. And all the available cities are entered/managed in backend admin panel.
Before I used to write for only backend things, frontend seems little confusing.
There is a design folder which is completely for theme development.
All the example are little different(https://www.mageplaza.com/magento-2-module-development/,http://inchoo.net/magento-2/how-to-create-a-basic-module-in-magento-2/]2), they have routes.xml, where route_id, and all are defined, but here I don't need any extra route. Need some additional tweaks in frontend pages.
I created module V_name/M_name/adminhtml/block controllers etc view ...
Guide me how to create a module, which has both front end and backend connection, cities should be entered in admin, they should show on the frontend homepage.
For now, I only managed to edit home page content CMS page by adding some HTML which shows a popup with a dropdown for cities when the page loads.
Since you already have the back-end figured out I will focus on front-end. Also, since all you need to do is populate a list that you already have created this should be easy. I did something like this before and I found it easier to just use JSON to query a list of, in your case the cities, and populate the drop down. I don't believe this is the most 'MVP/proper' way to go, but it is less work then the other ways. (At least for me it is. I always prefer the JavaScript option since it allows for easy future page customization.)
To use the JSON method you need to create a Block with a method like the one below. You will see that you will also have to create a Resource Model (I'm not going to go over creating the Resource Model or the details of Blocks since there are much better resources than me already online that will go into every single detail you need.). Once this is complete you can access the data straight from the .phtml page in an easy to use JSON array.
First you need to make sure you are now structuring your Modules properly. The new Block below should be in a structure like this...
app/code/<VENDOR>/<MODULE>/Block/Wrapper.php (or whatever you name it)
The admin Blocks should be in the structure below, which it sounds like you are already know how to do.
app/code/<VENDOR>/<MODULE>/Block/Adminhtml
Create your Block and add a method to create a JOSN array like below...
public function getCityList()
{
$city_array = array();
/** #var \<VENDOR>\<MODULE>\Model\ResourceModel\City\Collection $collection */
$collection = $this->_cityCollectionFactory->create();
$collection->addFieldToFilter('active','1')->addFieldToSelect(['city_id', 'city']);
$collection->getSelect()->order(array('city ASC', 'city_id ASC'));
$count = 0;
foreach ($collection as $model)
{
$city_array["$count"] = $model->getData();
$count++;
}
return \Zend_Json::encode($city_array);
}
FYI... The foreach loop in the code above is weird and uses $count because I needed to do some tricky things to get something to work.
Then you can create the Block in your .phtml file to access the data via javascript.
<?php
$block_obj = $block->getLayout()->createBlock('<VENDOR>\<MODULE>\Block\Wrapper');
?>
<script type="text/javascript">
window.citylistJson = <?php echo $block_obj->getCityList() ?>;
</script>
I want to ask, is it possible working with a template, and duplicate a specific page in that template without using WordFragment or addExternalFile (I want the template to be 1 file only)?
As an example, I have 3 page, I want to duplicate (or repeating) page 2 for 4 times, so the result is that I have a 7 paged document with a second page repeating for 4 times? Is it possible to do it without WordFragment or addExternalFile? Because I want to make it easier to edit in the template.
My Phpdocx is a trial version.
What I have tried so far is using wordfragment, by using $wordfragment$ variable in document template (in second page), and do this in php:
$wf = new WordFragment($docx, 'document');
for($i = 0: $<4; $i++) {
/*here I put a code to make a text and table in wordfragment (sorry it's too long to write it here, it's about 500 lines)*/
$wf->addBreak(array('type'=>'page')); //it's to go to next page
} //so this loop will make 4 same pages with the content I want in that 500 lines of code.
$docx->replaceVariableByWordFragment(array('wordfragment'=>$wf), array('type'=>'block'));
Using a WordFragment like above is actually very powerfull, and it is have a very great result, but since it will be used by my user, and we always presume that the user is not good with code, so I cannot let the user to edit the code if he/she just want to edit the template, in example, if the user want to edit the table in template, in this code of mine, that user need to edit it in that 500 lines codes, and that's very not user friendly, what I wanted is to make it more simple, make the text and table in word (so the user could just edit it in there), and in the code I just need to repeat that page. Is it possible?
Oh and the other method, addExternalFile is actually quite good, but by using this, I need to have more than 1 template, in example, I need 3 document, named start.docx, content.docx, end.docx. With addExternalFile, I could just used it like this:
$wf = new WordFragment($docx, 'document');
$wf->addExternalFile(array('src'=>'start.docx'));
$wf->addBreak(array('type'=>'page'));
for($i=0;$i<4;$i++) {
$content = new CreateDocxFromTemplate('content.docx');
/*here I put a code to replace all text and table variable in template*/
$content->replaceVariableByText($variables, $parameter); //$variables and $parameter already included in my code
$content->replaceTableVariable($table); //$table already included in my code
$content->createDocx('newcontent.docx');
$wf->addExternalFile(array('src'=>'newcontent.docx'));
$wf->addBreak(array('type'=>'page'));
} //this loop will make 4 same page
$wf->addExternalFile(array('src'=>'end.docx');
$docx->replaceVariableByWordFragment(array('wordfragment'=>$wf), array('type'=>'block'));
With addExternalFile, I could write text, variables, and draw a table in document and not in wordfragment. It's quite user friendly, but the flaw is that this method need atleast 3 different document to be opened by user if they want to edit it. What I want is just 1 document, all text, variables, and tables are in document, and there's no text or table in php code. Is there any method to do this with phpDocx?
Been using the plugin Custom Content Type Manager to create a custom post that displays location information.
We hold weekly games for each location - So what I'm trying to accomplish is in my custom post I have a set of checkboxes so you check if the venue is played on Monday, Tuesday or Wed...etc Then in my theme I'm going to have a 7 day calendar. And if a location is checked for that day then I want the title/links to the location printed there.
I'm giving you that background because I really dont think I'm going about this the correct way. Essentially I'm doing it in a loop, and I'm pulling all the checkbox options in an Array, and if the option is equal to Monday to that specific day, then it prints the locations title name etc.
I want this setup so a non-technical person (kinda like me lol) can just add a new location and pick "friday" for example and the code does the rest.
Essentially I got it working. 2 problems though
I'm running 7 loops to accomplish this - one for each day. I know this is stupid and there is probably a better solution.
It's printing the correct information - however its also reading/printing each of the other locations except its not putting up the info for them - I know this cause its creating empty DIVs for them.
NOTE: I'm having issues posting the whole code...?? I deleted all the php tags to present this
$weekly = new WP_Query( array( 'post_type' => 'locations', 'posts_per_page' => 5 ) );
while ( $weekly->have_posts() ) : $weekly->the_post();
<div class="weekly-venue-spacer">
$day_array = get_custom_field('weekly_day:to_array');
if (in_array('3', $day_array)) {
print_custom_field('venue_display_name');
echo "<br />";
print_custom_field('city_crossroads');
}
</div>
endwhile;
wp_reset_postdata();
the '3' in the in_array statement just means "Wednesday".
Here look at this image:
http://i40.tinypic.com/svnee0.jpg
an example of the empty DIVs being created - easily seen with padding applied to the div
Thanks for reading. Any solution to approach this differently would be great.
I am not sure I understood correctly what you want , but assuming I did - I think your whole approach is a bit wrong/complicated .
First of all, you do not need 7 loops .
I have noticed have a custom field - so in that custom field , instead of an array, just store the ONE day that you need , and then simply GET by checking the custom_field value ..
Second - why do you use checkbook and not a list ? is there an eventual event that can be in several different days ? because if every event is exclusive for one day - than it would be more easy to use a drop list or even radio buttons.
and for your direct question - I do not know how the value of the custom field is structured - but you are printing ALL of it ..
EDIT I : After reading comment and understanding better the problem -
While still thinking that the approach is a bit wrong , but not knowing exactly how you construct the data - I will address the IMMEDIATE problem :
The code creates empty DIVS simply because you tell it to .
you are using a WHILE condition in the code BEFORE outputting a div.
Since your query gets 5 posts - it will create 5 divs (some of which that do not meet the NEXT condition , will be of course empty).
your function now , put in human-words is working like this :
1. Get 5 post.
2. As long as I have posts (for each post), Open a div.
3. If you have Tuesday in array - print something
4. close div
5. if not finished all posts (in our case, 5) - go back to step 2.
It is obvious that the code will print empty div also for empty events..
So to get it right you simply move the opening div tag to BEFORE the WHILE condition .
that is if you do not need to check for existence of events in the query ..
The right way would be to use also the IF statement, just like the regular wordpress loop.
The general mechanism is this :
<?php if ($weekly->have_posts()) : ?>
//now we open a div
<?php while ( $weekly->have_posts() ) : $weekly->the_post();?>
// now we check for other conditions and print them if available.
<?php endwhile; ?>
// now we close the DIV
<?php endif; ?>
I have a really silly problem that has cost me a load of time already.
I have created a content template with a URL in there. When I look at the HTML code for it, I see a big fat "maxlength=256" in the form tag. I'd like to expand the length of this field, because my customer wishes to enter really long links (over 500 characters). Any idea how I can change it? When I do a generic search through the code I see so many occurences of 256, but the length might just as well be in the database somewhere. I have of course made the database field a longer varchar (1024 sounded poetic to me), so that's something I don't have to worry about.
I think it's silly, but the customer's always right, as we know.
I am using Drupal 6.14.
You want to use a hook_form_alter() in your templete.php or a custom module.
It will look something like this:
MODULE_form_alter(&$form, &$form_state, $form_id) {
if($form_id = 'name_of_form_you_want_to_alter') {
form['name_of_url_field']['#maxlength'] = 500;
}
}
Just replace MODULE with the name of your theme (if in template.php) or replace it with the name of the custom module your using.
To find the id of the form, inspect the element with firebug. Same goes for the id of the url field.
Let me know if you need more detail.
EDIT: As pointed out, it looks like you can't call hooks from the theme level.
The best way to go about this is to create a small custom module for you site. You can call it something like SITENAME_customizations.
All you need is a simple .info file named MODULENAME.info which will look something like this:
name = SITE customizations
description = "Customizations"
You will also need a MODULENAME.module file, which is where you will include your hook_form_alter call.
PS. Make sure that you don't close your php tag (?>) in your .module file.
Yahoooooo! I fixed it, thanks to the helpful Drupal pages:
http://drupal.org/node/300705
I figured out I could edit the form after it has been generated completely. The solution presented by Erik is good, but doesn't appear to work for CCK fields. In my case Erik's solution could have worked if it wasn't for this generation step that needs to happen first.
My new code is as follows:
function longerfield_form_alter(&$form, &$form_state, $form_id) {
$form['#after_build'][] = 'longerfield_after_build';
}
function longerfield_after_build($form, &$form_state) {
// This is for a node reference field:
$form['field_page_boeken'][0]['data']['url']['#maxlength'] = 1024;
return $form;
}
Now, I too see that it's ugly, especially because there might be other form elements here (just increment from 0), but it works for the first element! Yippeee!