Mod Manager - Config File Creation Example

From TNG_Wiki
Jump to navigation Jump to search


The purpose of this page is to illustrate how a (pair of) TNG files might be edited, and how a TNG Mod might be created to implement those edits.

The Programming Process

This article describes a process in which the programmer:

  1. Edits the TNG files as necessary to implement the desired changes,
  2. Tests the application to confirm that the changes work as intended.
  3. Repeats steps 1 and 2 until TNG works as desired.
  4. Uses a text editor to creates a new Mod .cfg file by starting from an old one.
  5. Uses a file-comparison tool to compare the new, edited files with either
    • A backup of the files, made just before editing them, or
    • The corresponding "pristine" files from the TNG release, and
  6. Takes each difference found by the file comparison, and copies-and-pastes snippets of code from the TNG files into a .cfg file.

Notes that steps 1, 2, and 3 don't have anything to do with Mod Manager; they are just standard steps in the programming process. However, as described later in this article, the programmer does need to be sensitive to certain programming and code-documentation conventions while commenting the code changes. In particular, it is important to

  1. Make sure to avoid code that has been inserted by other mods.
  2. Avoid making unnecessary changes to pristine TNG code. Such changes increase the risk of
    • Accidentally causing conflicts with mods that you have not installed, and
    • Creating conflicts with future TNG updates.
  3. In particular, avoid the temptation to "improve" pristine TNG code. Most of the TNG code has been functioning well for a long time. While it is true that HTML coding standards (more so than PHP) have changed in the intervening years, if it ain't broke, don't fix it!
    (Mea culpa: For instance, I have been known to decide that it would be "better" to turn <td> elements in table headings into <th> elements, merge <span> elements into the parent element, try to "simplify" code by reducing the number of transitions between PHP mode and HTML mode, and even use new-fangled CSS techniques to reduce the number of classes and styles that are repeated in multiple <td> elements. But I've caused too many unintended conflicts by doing so - and spent time "improving" code that worked just fine.)

This process is applicable to CSS files, JavaScript (.js) files, and PHP files, and to the PHP, CSS, and JavaScript code that can be found inside PHP files - plus raw text inside those files. A key to understanding Mod Manager .cfg files is that Mod Manager is completely oblivious to the language(s) being used in files that Mod Manager modifies. Mod Manager simply looks for text (which may or may not be "code") that is specified in the .cfg file, and then either replaces that text or inserts new text.

Programming Tools

It is essential to have a good programmer's editor such as Notepad++, and a good file comparison utility such as BeyondCompare. Other similar tools are used by some TNG programmers.

Editing the TNG Files

This article does not try to address the programming process, so it does not tell you how to make changes to PHP, JavaScript, or CSS code. However, it is important to note that the search text for each location in a file must be unique to that file, and that the insertion or replacement text must also be unique (both relative to the file as it existed before any modifications, and as it exists after any modifications).

That is, once the programmer has made the necessary changes to a file, the programmer must take uniqueness of search and replacement strings into account in order to:

  1. Effectively place comments about the changes in the file, and
  2. Decide how much text (how much code) must be in the search text and replacement or insertion text in order to make it unique.

Note that comments can be extremely useful in assuring that replacement and insertion text is unique.

The Example

The mod we will build is a very simple one. It takes the TNG Whats New program and removes any reference to the user who made the edits listed by Whats New. This mod is most applicable to sites where only one person has edit rights, and thus the username of the editor is pointless.

To implement the change, we will need to modify two PHP programs:

  1. whatsnew.php, which displays the Individuals (from the People database table) and Families
  2. function.php, where the doMedia function displays each media type.
whatsnew.php Before the mod whatsnew.php - What we want it to look like
Mmexample-before.png Mmexample-after2.png

Editing a PHP file

Here, in one screenshot, are both locations within whatsnew.php that must be changed. Only two lines of code need to be edited, and they are each highlighted with a blue background. Both locations contain a conditional expression that says, in effect "If there is a current username (i.e. if the user is logged in), display the database field that represents the username of the person who made the edit". That conditional expression will be removed from both locations, thus removing the username of the person who made the edit.

Now, see those same two locations with the necessary edits. The two edited lines of code are highlighted by red boxes. In both cases, the conditional expression has been replaced by a comment that is within the line of code.

Not all TNG programmers insert comments when they make changes to TNG files. But it is very useful to incorporate comments into your changes, for several reasons, such as:

  1. Comments that contain the mod name flag the fact that text has been changed by the mod.
  2. In this particular case, both edits simply remove code. You can't remove text in Mod Manager without replacing it with something else, such as a comment.
  3. In cases such as this, where the two code changes are identical, comments can assure that the replacement text is unique.
  4. In general, comments are helpful to programmers who happen upon the code and don't otherwise know what is going on.

Some TNG programmers like to add new lines before and after a change to clearly mark where a change has been made. However, in simple one-line changes, the comments can often fit nicely on the same line as the change.

In the present example, there are two files:

  • In whatsnew.php, brief comments about the code changes will be placed within the same line as the code changes, as shown above.
  • In functions.php, the one code change will be associated with a more explict comment on the line above the code change.
  • And in both files, a comment will be placed at the top of the file to describe the effect of the mod.

Top-of-file comments

It is also very useful to add a comment at the top of any file that you edit. This comment serves to document the fact that a mod has modified the file, and to explain what the purpose of the mod is. Here is whatsnew.php with a new explanatory comment at the beginning of the file, right after the first <?php directive.

Testing the code changes

This article will not try to cover the testing and approval process, which should be independent of whether Mod Manager is involved. For the purposes of this article, we will

  • Assume that the edits shown above meet the "project" requirements, and
  • The necessary edits to any other files also are tested and approved.

In this example, function.php must also be edited. Those edits will be considered as they apply to the Mod Manager .cfg file.

Creating the Mod Manager .cfg File

The simplest way to start a new Mod Manager .cfg file is to copy a simple config file and change it. Here is a screenshot of the beginning of another mod .cfg file. Note the syntax highlighting - with orange percent signs, green keywords, and the mod description highlighted in yellow. This syntax highlighting is a result of installing the special Mod Manger language plugin for Notepad++, which is described in the Wiki article Notepad++ Mod Manager Language.

And here is the beginning of the file after it has been modified to become the WhatsNew Hide Editor mod. Please note that is very important that you remember to do a Save As to the new filename before you save any changes. It is usually a good idea to do that Save As before you actually make any changes.

Note that the name of the new file is whatsnew_hide_editor_v11.0.0.1.cfg. The mod's version number is defined both in the filename, and within the file. This version number ( that the mod works for TNGv11.0.0 and above, and that this is version 1 of the Whatsnew Hide Editor mod.

In the screenshot above, you can also see

  • The beginning of a Change History comment in the .cfg file. There is no special syntax to mark Mod Manager comments because any text that is not within a Mod Manager directive is a comment.
  • The "%target directive, which specifies that the whatsnew.php file is to be modified by the subsequent directives.

One File's Target Locations

We know that there are three change locations in whatsnew.php. To describe them to Mod Manager, we need to specify unique text to search for, and unique insertion or replacement text. In this example, the first target location will insert the top-of-file comment, and then the second and third target locations will replace PHP code.

An effective way to figure out the search text and replacement or insertion text for each location, and to put that text in the .cfg file, is to

  1. Display a side-by-side comparison of the edited file and the previous version.
    • The screen shots in this example use the file comparison tool BeyondCompare.
    • WinMerge is less powerful, but free file comparison tool for Microsoft Windows.
    • Notepad++ has a reasonably useful side-by-side comparison function (which must be installed as a plugin), but if you are using NotePad++ to edit the .cfg file, then you can't really use it to compare the two versions of the edited file.
  2. Simultaneously have the .cfg file open in an editor. This example will continue to use Notepad++ to edit the .cfg file.
  3. With the side-by-side comparison and the editor all open at once, copy-and-paste snippets of text from the new and old PHP files to the .cfg file.

The follow screen shots illustrate this process. For the sake of display space, illustrations show

  • a side-by-side comparison in BeyondCompare with narrower panels
  • a smaller Notepad++ editor window, and
  • more overlap than you would probably have on your PC screen.

Location 1

The first illustration of this process shows the beginning of each copy of whatsnew.php, with the top-of-file comment, and, as it turns out, a change from a different mod that just happens to be close to the top of the file. We will ignore the target location from the Living Color mod. Note that the edited file is on the left, and the previous version is on the right.

In this screenshot, you can clearly see the three lines that make up the top-of-file comment (lines 2-5 on the left), and you must inspect the corresponding and adjacent lines in the previous version to determine whether to do a replacement or insertion, and to select text that will make the search text unique.

In the Notepad++ window, where the .cfg file whatsnew_hide_editor_v10.0.0.1.cfg is being edited, note that the target location that was in the file we started from has already been modified as follows:

  • Line 10 - The %target directive now specifies whatsnew.php,
  • Line 15 - The Mod Manager comment now also specifies whatsnew.php. As it turns out, the description of this first location has not changed. It is still "Top-of-file comment".
  • Line 17 - The search text from the first location in the old mod has been removed, and there is nothing specified between the %location% directive and the %end:% direction that bracket the search text.
  • Line 19 - Similarly, the insertion text from the first location in the old mod has been removed, and there is nothing specified between the action directive (%insert:before%, which we could change) and the %end:% directive that bracket the insertion or replacement text.
  • Note also that the comment for location 2 in line 21 still has the old filename, since that comment has not yet been modified.

As we look at Figure 5 above, it should be clear that that the changed lines (2-4) on the left are new (since there are no matching lines on the right). And it should be easy to at least guess that the line that follows the insertion (line 2 on the right) may be sufficient to serve as unique search text.

It is usually a good idea to highlight the candidate search text (all of line 2 on the right side), and then use the BeyondCompare search command (control-f) to see if that text occurs elsewhere. In this case, it doesn't, so we can just copy and paste line that line between lines 16 and 17 in the .cfg file. Then we can copy and paste the insertion text between the %insert directive and the %end:% directive in the .cfg file. Note that we can leave the %insert:before% action directive alone, since the new mod, like the old one, will insert the new text before the search text.

The resulting target location is shown in the next illustration. The .cfg file has search text in what is now line 17, and it has insertion text in what is now lines 19-21.

Location 2

Now, here, knowing that we made the exact same edit in locations 2 and 3, we have to be very careful to select unique search text. If the original lines of code for locations 2 and 3 are actually identical, our search text will have to incorporate enough lines of code to make it unique. But, conveniently, the text in the two locations is not identical. As can be seen in this side-by-side comparisons of the two pristine locations (a repeat of figure 1a),
there is a slight different between the two lines. The code snippet that we have eliminated is identical, but location 2 (on the right) includes the HTML attribute and value valign=\"top\" and location 1 on the left doesn't.

Thus, to get unique search text, we can work within the line of code. (When the search text is just part of a line, it is known to Mod Manager as a "code fragment".) We simply have to make sure that our search text includes something before the place where valign=\"top\" occurs in location 3. Rather than just grab a small part of an HTML attribute, we'll start with "<td class=" near the beginning of the line. Note that, in BeyondCompare, with our narrow panels, each line of text is cut off because BeyondCompare does not wrap long lines. But at the bottom of the BeyondCompare window, we can see the two selected lines above and below each other, so we can see most of each line.

Therefore, we can select unique search text from the right-hand panel by selecting the portion of the line highlighted in blue at the bottom of the BeyondCompare window. And we can select the corresponding replacement text from the left panel. Note that both text snippets begin with a space, and end with a non-space character, because it is prudent to avoid trailing spaces in code fragments.

The search text and replacement text are shown pasted into the .cfg file in Figure 8. Also, note that the action directive is %trimreplace:%. The "trim" prefix is needed when you work with a code fragment.

In Figure 8, note the two Mod Manager comments:

  • One listing the line number (within the pristine file) where the change occurs. It is not particularly useful to list the line number in the changed file (where the change actually is), because the changed file could also have changes from any number of mods, so it is impossible for the mod programmer to know what the target line number will be in the changed file.
  • A comment simply intended to inform future programmers about the similarity between the two target locations.

Location 3

We'll describe location 3 more succinctly than we did locations 1 or 2, since location 3 is virtually the same as location 2. In fact, rather that start location 3 by using location 3 from the old file, I copied-and-pasted the completed location 2, and used that text as my starting point for location 3.

We're also using a code fragment for location 3, and, will make sure to

  • include the text valign=\"top\" to distinguish this location from location 2, and
  • Start with a space and end with a non-space character as before


Figure 10 shows a completed location 3 for whatsnew.php.

The Second File's Target Locations

We also must remove the same code snippet from the doMedia function in functions.php that we removed twice from whatsnew.php. But, search, replacement, and insertion text only has to be unique within a file, so we don't have to worry about whether the functions.php search text is different from the 2 locations in whatsnew.php.

To start the second file's Mod Manager instructions, we need a %target directive, just as we did to start the first file.

Location 1

Location 1 in functions.php is a top-of-file comment, just like Location 1 in whatsnew.php. So Figure 11 is analogous to Figure 5. It shows a comparison of the beginning of the edited functions.php file with the beginning of the pristine functions.php, along with the portion of .cfg file ready for us to paste in the search text and insertion text for location 1 of functions.php I "seeded" location 1 by copying-and-pasting location 1 from whatsnew.php, and then removing the search text and replacement text. (This time I didn't add dummy text to show where the search text and replacement text will go, as I did with Figure 5.)

As with location 1 of whatsnew.php, it is easy to recognize the new text to be inserted at this location in the left panel, and easy to recognize that the one-line function declaration at line 2 in the pristine file will serve as unique text.

So a completed location 1 for functions.php looks like this:

Location 2

Now, location 2 in functions.php is almost identical to location 2 in whatsnew.php. In fact, since we don't have to worry about whether it is distinct from similar location in functions.php, we can use a shorter code fragment.

But, for illustration purposes, we'll take a completely different tack this time. Rather than use a code fragment, as we did with whatsnew.php, we will target the entire line of PHP code, and replace it with a comment on a line by itself plus a full line of modified PHP code, like this:
Note that this style of change is particularly applicable when the change involves several lines in the target file, in which case, it is also useful to place a comment line at the end of the insertion/replacement.

Location 3 in the .cfg file thus looks like this:

We have now specified all of the changes needed for both target files, and can proceed to test the new mod.

Testing the Mod

Testing involves the following activities:

  1. Making sure that the mod status is "Installed"
  2. Uninstalling & Reinstalling the mod, to make sure that the mod returns the target files to their previous state.
  3. Retesting the TNG application, and making sure that the modifications perform as they should.

Installed Status

It is important to note that, using the programming process described at the beginning of this article, the TNG programs to be modified by the mod have already been changed. So, when you run the Mod Manager in the test environment, the mod's status should be Installed. If the status is anything else, we have not built it correctly, and we need to edit either the target files or the .cfg file, or perhaps both.

  • If the status is Not Installed, then something is very wrong, since that means that none of the mods locations have been installed correctly. The mod .cfg file or the edited target files are probably in the wrong folders.
  • If the status is Cannot Install or Partially Installed, then at least one of the target locations in the .cfg file is out of sync with its target file. You need to open the status cell in Mod Manager and look at the list of locations.
    • A location status of "Bad Target" means that neither the search text nor the replacement/insertion text was found in the target file.
    • A location status of "Not Installed" means that the search text was found, but not the replacement/insertion text.
    In either case, you can visually compare the target locations in the .cfg file and the target file, or, in BeyondCompare or Notepad++, you can compare the .cfg file to the target file. There will be very few matches between those two files, of course, but your search text and/or replacement/insertion text should match. So look for blank spots in the file map at the left of the BeyondCompare window, or search for text that should be in the search, replacement, or insertion text to see where the mismatch occurs. Small typos such as trailing spaces can cause these errors.

Once you achieve a mod status of Installed, you're through with this phase.

Uninstall & Reinstall

You need to make sure that your mod both installs and uninstalls correctly, and that, when uninstalled, it returns the file to its previous state. As you go through multiple edit-and-test cycles, it is easy to accidentally incorporate text - or, more particularly, whitespace - into your target locations in ways that don't return the file to its previous state.

The development process described above called on you to save the previous version of each file you change. Now, you should

  1. Backup your edited version so that you can make sure not to lose important code when you uninstall and reinstall.
  2. Uninstall the mod.
  3. Then, for each file:
    1. Compare the brand-new version with your backed-up previous version, and correct any differences.
    2. Reinstall the mod.
    3. Compare the even-newer version you now have with your backed-up edited version, and correct any differences.
    4. Repeat as necessary.

Test the App

As you must have done multiple times in the development process, make sure that TNG works correctly once you have re-installed your mod. It is a good idea to get help from other TNG user to test your mod in another production environment.

Check for Conflicts

As you install and uninstall your mod in your environment, make sure that no other mods change status. If other mods change status, then you have conflicts with those mods that you need to resolve. Make sure that anyone else who tests the mod for you does the same.

Also, (especially, but not only if you plan to publish your mod for others to use) you should search the TNG wiki for other mods that change the same files, and at least inspect those mods for possible conflicts. Ideally, you should install each of those mods, and look for both Mod Manager conflicts and functional conflicts. That is, some mods can be installed together without Mod Manager conflict, but don't work together.

Publishing your Mod

This is a very light treatment of this topic... If you want to make your mod available to others, then you need to

  • Pay extra attention to your internal documentation of your changes,
  • Pay extra attention to testing your mod against other published mods,
  • Write a TNG Wiki article about your mod, in which you
    • Describe the features of your mod,
    • Note which mods conflict with and/or coordinate with your mod,
    • Provide visualizations of the effects your mod has on TNG, and
    • Provide a way for users of your mod to contact you.

The mod in this article is actually a real mod that has been published at Mod User Support Form mod.

The Complete .cfg File

The mod described in this artice is a real mod that has been published on the TNG Wiki. The mod name has been changed to Whatsnew Hide Edit User, so you can go to the wiki article Whatsnew Hide Edit User to download the TNG version 10 mod described here, which is zipped-up as The updated (and renamed) copy of the mod in the wiki article is valid for TNGv11, TNGv12, and TNGv13, so if you want to install this mod, you'll probably need to install the updated copy.

You can view the mod right in this article by clicking on the [Expand] link on the right.
%name:Whatsnew Hide Editor%
%description:Suppress the display of the username of the person who made each edit.  This mod is primarily useful for sites where there is only one administrator and that username is redundant. 
<br/>Mod developer is <a href="" target="_blank">Robin Richmond</a>
<br/>Wiki article: <a href="" target="_blank">Whatsnew_Hide_Editor</a>

Change history:
v1 - 10 Oct 2015 - Initial version


*************** whatsnew.php Location 1 - Top-of-file comments
$textpart = "whatsnew";
# Modified by the Whatsnew Hide Editor mod to suppress display of the person who made each edit.
# It must make two identical changes in this file for the People and Families tables. Both remove
# a conditional expression that usually returns the username of the person who made the edit.
# Locations 2 and 3 are code fragment changes and are not fully documented by comments in those
# locations.  Location 2 handles Individuals (the People table), and Location 3 handles Families.


*************** whatsnew.php Location 2 - Remove the username from the list of changes to Individuals.
*** line 175 in the pristine tng10.1.2 whatsnew.php ***
*** Note that this target location is nearly identical to location 3 ***
"<td class=\"databack nw\">" . displayDate( $row['changedatef'] ) . ($currentuser ? " ({$row['changedby']})" : "")
"<td class=\"databack nw\">" . displayDate( $row['changedatef'] ) /* ### Whatsnew Hide Editor location 2 */

*************** whatsnew.php Location 3 - Remove the username from the list of changes to the Families table.
*** line 243 ***
valign=\"top\">" . displayDate( $row['changedatef'] ) . ($currentuser ? " ({$row['changedby']})" : "")
valign=\"top\">" . displayDate( $row['changedatef'] ) /* ### Whatsnew Hide Editor location 3 */


*************** functions.php Location 1 - Top-of-file comments
function get_item_id( $result, $offset, $itemname ) {
# The doMedia function in this file has been modified by the Whatsnew Hide Editor mod v1 to suppress 
# display of the username of the person who made each edit.


*************** functions.php Location 2 - Remove the username from the lists of media changes for the Whats New report
*** line 239 ***
            $mediatext .= "<td valign=\"top\" class=\"databack\">" . displayDate( $row['changedatef'] ) . ($currentuser ? " ({$row['changedby']})" : "") . "</td></tr>\n";
            ### Whatsnew Hide Editor Location 2 - One line change - remove the username of the person who made the change.
            $mediatext .= "<td valign=\"top\" class=\"databack\">" . displayDate( $row['changedatef'] ) . "</td></tr>\n";

Related Links

Mod Manager

Mod Manager Controls

For Mod Developers


Developer Tools

Example Mods